Skip to content

Commit

Permalink
Migrate to new team device keys format (#218)
Browse files Browse the repository at this point in the history
Following an internal ADR (Architecture Decision Record), I'm migrating
to a new team device keys format.
  • Loading branch information
Mikescops authored Mar 15, 2024
1 parent aaf2d5a commit 0df5330
Show file tree
Hide file tree
Showing 6 changed files with 57 additions and 28 deletions.
10 changes: 4 additions & 6 deletions documentation/pages/business/index.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -17,21 +17,19 @@ dcli t credentials generate
You will be prompted with a list of variables to export in your environment. Simply copy/paste them in your terminal.

```sh copy
export DASHLANE_TEAM_UUID=08a48d4f-[..redacted..]-fba9193d968c
export DASHLANE_TEAM_ACCESS_KEY=f56[..redacted..]56ce
export DASHLANE_TEAM_SECRET_KEY=839c9[..redacted..]3ada5
export DASHLANE_TEAM_DEVICE_KEYS=dlt_[deviceAccessKey]_[payload]
```

On Windows, you can use the `set` command instead of `export`.

```sh copy
set DASHLANE_TEAM_UUID=08a48d4f-[..redacted..]-fba9193d968c
set DASHLANE_TEAM_ACCESS_KEY=f56[..redacted..]56ce
set DASHLANE_TEAM_SECRET_KEY=839c9[..redacted..]3ada5
set DASHLANE_TEAM_DEVICE_KEYS=dlt_[deviceAccessKey]_[payload]
```

Make sure you save them in a safe place (use a secure note for instance 😉).

<Callout emoji="ℹ️">The token you'll get is starting by `dlt` in order to be easily identified by scanning tools.</Callout>

## List credentials

<Callout emoji="💡">Needs to be authenticated as an admin to use this command.</Callout>
Expand Down
2 changes: 1 addition & 1 deletion src/command-handlers/passwords.ts
Original file line number Diff line number Diff line change
Expand Up @@ -50,7 +50,7 @@ export const runPassword = async (
}

if (!result) {
throw new Error(`No ${field} found for "${selectedCredential.title ?? selectedCredential.url ?? 'N/C'}.`);
throw new Error(`No ${field} found for "${selectedCredential.title ?? selectedCredential.url ?? 'N/C'}".`);
}

if (output === 'console') {
Expand Down
23 changes: 20 additions & 3 deletions src/command-handlers/teamDevices.ts
Original file line number Diff line number Diff line change
@@ -1,8 +1,8 @@
import { connectAndPrepare } from '../modules/database';
import { listTeamDevices } from '../endpoints';
import { listTeamDevices, registerTeamDevice } from '../endpoints';
import { epochTimestampToIso } from '../utils';

export async function listAllTeamDevices(options: { json: boolean }) {
export const listAllTeamDevices = async (options: { json: boolean }) => {
const { db, localConfiguration } = await connectAndPrepare({ autoSync: false });

const listTeamDevicesResponse = await listTeamDevices({ localConfiguration });
Expand Down Expand Up @@ -39,4 +39,21 @@ export async function listAllTeamDevices(options: { json: boolean }) {
});

console.table(result);
}
};

export const createTeamDevice = async () => {
const { db, localConfiguration } = await connectAndPrepare({ autoSync: false });
const credentials = await registerTeamDevice({ localConfiguration, deviceName: 'Dashlane CLI' });
db.close();

const teamDeviceKeysPayload = {
teamUuid: credentials.teamUuid,
deviceSecretKey: credentials.deviceSecretKey,
};

const teamDeviceKeysPayloadB64 = Buffer.from(JSON.stringify(teamDeviceKeysPayload)).toString('base64');

const deviceAccountKey = `dlt_${credentials.deviceAccessKey}_${teamDeviceKeysPayloadB64}`;

return deviceAccountKey;
};
20 changes: 8 additions & 12 deletions src/commands/team/credentials.ts
Original file line number Diff line number Diff line change
@@ -1,8 +1,8 @@
import winston from 'winston';
import { Command } from 'commander';
import { listAllTeamDevices } from '../../command-handlers';
import { createTeamDevice, listAllTeamDevices } from '../../command-handlers';
import { connectAndPrepare } from '../../modules/database';
import { deactivateTeamDevice, registerTeamDevice } from '../../endpoints';
import { deactivateTeamDevice } from '../../endpoints';

export const teamCredentialsCommands = (params: { teamGroup: Command }) => {
const { teamGroup } = params;
Expand All @@ -14,23 +14,19 @@ export const teamCredentialsCommands = (params: { teamGroup: Command }) => {
.option('--json', 'Output in JSON format')
.description('Generate new team credentials')
.action(async (options: { json: boolean }) => {
const { db, localConfiguration } = await connectAndPrepare({ autoSync: false });
const credentials = await registerTeamDevice({ localConfiguration, deviceName: 'Dashlane CLI' });
db.close();
const teamDeviceKeys = await createTeamDevice();

if (options.json) {
console.log(
JSON.stringify({
DASHLANE_TEAM_UUID: credentials.teamUuid,
DASHLANE_TEAM_ACCESS_KEY: credentials.deviceAccessKey,
DASHLANE_TEAM_SECRET_KEY: credentials.deviceSecretKey,
DASHLANE_TEAM_DEVICE_KEYS: teamDeviceKeys,
})
);
} else {
winston.info('The credentials have been generated, run the following commands to export them:');
console.log(`export DASHLANE_TEAM_UUID=${credentials.teamUuid}`);
console.log(`export DASHLANE_TEAM_ACCESS_KEY=${credentials.deviceAccessKey}`);
console.log(`export DASHLANE_TEAM_SECRET_KEY=${credentials.deviceSecretKey}`);
winston.info(
'The credentials have been generated, run the following command to export them in your env:'
);
console.log(`export DASHLANE_TEAM_DEVICE_KEYS=${teamDeviceKeys}`);
}
});

Expand Down
6 changes: 6 additions & 0 deletions src/errors.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,12 @@ export class CouldNotFindTeamCredentialsError extends Error {
}
}

export class TeamCredentialsWrongFormatError extends Error {
constructor() {
super('Team credentials has a wrong format');
}
}

export class InvalidDashlanePathError extends Error {
constructor() {
super('Invalid Dashlane path');
Expand Down
24 changes: 18 additions & 6 deletions src/utils/teamDeviceCredentials.ts
Original file line number Diff line number Diff line change
@@ -1,15 +1,27 @@
import { CouldNotFindTeamCredentialsError } from '../errors';
import { CouldNotFindTeamCredentialsError, TeamCredentialsWrongFormatError } from '../errors';
import { TeamDeviceCredentials } from '../types';

let teamDeviceCredentials: TeamDeviceCredentials | null = null;

export const initTeamDeviceCredentials = (): TeamDeviceCredentials | null => {
const { DASHLANE_TEAM_UUID, DASHLANE_TEAM_ACCESS_KEY, DASHLANE_TEAM_SECRET_KEY } = process.env;
if (DASHLANE_TEAM_UUID && DASHLANE_TEAM_ACCESS_KEY && DASHLANE_TEAM_SECRET_KEY) {
const { DASHLANE_TEAM_DEVICE_KEYS } = process.env;
if (DASHLANE_TEAM_DEVICE_KEYS) {
if (!DASHLANE_TEAM_DEVICE_KEYS.startsWith('dlt_')) {
throw new TeamCredentialsWrongFormatError();
}

const [accessKey, payloadB64] = DASHLANE_TEAM_DEVICE_KEYS.split('_').slice(1);

// TODO: Run AJV validation on the payload
const payload = JSON.parse(Buffer.from(payloadB64, 'base64').toString('utf-8')) as {
teamUuid: string;
deviceSecretKey: string;
};

teamDeviceCredentials = {
uuid: DASHLANE_TEAM_UUID,
accessKey: DASHLANE_TEAM_ACCESS_KEY,
secretKey: DASHLANE_TEAM_SECRET_KEY,
uuid: payload.teamUuid,
accessKey,
secretKey: payload.deviceSecretKey,
};
}
return teamDeviceCredentials;
Expand Down

0 comments on commit 0df5330

Please sign in to comment.