Skip to content

Commit 0df5330

Browse files
author
Corentin Mors
authored
Migrate to new team device keys format (#218)
Following an internal ADR (Architecture Decision Record), I'm migrating to a new team device keys format.
1 parent aaf2d5a commit 0df5330

File tree

6 files changed

+57
-28
lines changed

6 files changed

+57
-28
lines changed

documentation/pages/business/index.mdx

+4-6
Original file line numberDiff line numberDiff line change
@@ -17,21 +17,19 @@ dcli t credentials generate
1717
You will be prompted with a list of variables to export in your environment. Simply copy/paste them in your terminal.
1818

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

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

2725
```sh copy
28-
set DASHLANE_TEAM_UUID=08a48d4f-[..redacted..]-fba9193d968c
29-
set DASHLANE_TEAM_ACCESS_KEY=f56[..redacted..]56ce
30-
set DASHLANE_TEAM_SECRET_KEY=839c9[..redacted..]3ada5
26+
set DASHLANE_TEAM_DEVICE_KEYS=dlt_[deviceAccessKey]_[payload]
3127
```
3228

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

31+
<Callout emoji="ℹ️">The token you'll get is starting by `dlt` in order to be easily identified by scanning tools.</Callout>
32+
3533
## List credentials
3634

3735
<Callout emoji="💡">Needs to be authenticated as an admin to use this command.</Callout>

src/command-handlers/passwords.ts

+1-1
Original file line numberDiff line numberDiff line change
@@ -50,7 +50,7 @@ export const runPassword = async (
5050
}
5151

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

5656
if (output === 'console') {

src/command-handlers/teamDevices.ts

+20-3
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,8 @@
11
import { connectAndPrepare } from '../modules/database';
2-
import { listTeamDevices } from '../endpoints';
2+
import { listTeamDevices, registerTeamDevice } from '../endpoints';
33
import { epochTimestampToIso } from '../utils';
44

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

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

4141
console.table(result);
42-
}
42+
};
43+
44+
export const createTeamDevice = async () => {
45+
const { db, localConfiguration } = await connectAndPrepare({ autoSync: false });
46+
const credentials = await registerTeamDevice({ localConfiguration, deviceName: 'Dashlane CLI' });
47+
db.close();
48+
49+
const teamDeviceKeysPayload = {
50+
teamUuid: credentials.teamUuid,
51+
deviceSecretKey: credentials.deviceSecretKey,
52+
};
53+
54+
const teamDeviceKeysPayloadB64 = Buffer.from(JSON.stringify(teamDeviceKeysPayload)).toString('base64');
55+
56+
const deviceAccountKey = `dlt_${credentials.deviceAccessKey}_${teamDeviceKeysPayloadB64}`;
57+
58+
return deviceAccountKey;
59+
};

src/commands/team/credentials.ts

+8-12
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,8 @@
11
import winston from 'winston';
22
import { Command } from 'commander';
3-
import { listAllTeamDevices } from '../../command-handlers';
3+
import { createTeamDevice, listAllTeamDevices } from '../../command-handlers';
44
import { connectAndPrepare } from '../../modules/database';
5-
import { deactivateTeamDevice, registerTeamDevice } from '../../endpoints';
5+
import { deactivateTeamDevice } from '../../endpoints';
66

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

2119
if (options.json) {
2220
console.log(
2321
JSON.stringify({
24-
DASHLANE_TEAM_UUID: credentials.teamUuid,
25-
DASHLANE_TEAM_ACCESS_KEY: credentials.deviceAccessKey,
26-
DASHLANE_TEAM_SECRET_KEY: credentials.deviceSecretKey,
22+
DASHLANE_TEAM_DEVICE_KEYS: teamDeviceKeys,
2723
})
2824
);
2925
} else {
30-
winston.info('The credentials have been generated, run the following commands to export them:');
31-
console.log(`export DASHLANE_TEAM_UUID=${credentials.teamUuid}`);
32-
console.log(`export DASHLANE_TEAM_ACCESS_KEY=${credentials.deviceAccessKey}`);
33-
console.log(`export DASHLANE_TEAM_SECRET_KEY=${credentials.deviceSecretKey}`);
26+
winston.info(
27+
'The credentials have been generated, run the following command to export them in your env:'
28+
);
29+
console.log(`export DASHLANE_TEAM_DEVICE_KEYS=${teamDeviceKeys}`);
3430
}
3531
});
3632

src/errors.ts

+6
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,12 @@ export class CouldNotFindTeamCredentialsError extends Error {
44
}
55
}
66

7+
export class TeamCredentialsWrongFormatError extends Error {
8+
constructor() {
9+
super('Team credentials has a wrong format');
10+
}
11+
}
12+
713
export class InvalidDashlanePathError extends Error {
814
constructor() {
915
super('Invalid Dashlane path');

src/utils/teamDeviceCredentials.ts

+18-6
Original file line numberDiff line numberDiff line change
@@ -1,15 +1,27 @@
1-
import { CouldNotFindTeamCredentialsError } from '../errors';
1+
import { CouldNotFindTeamCredentialsError, TeamCredentialsWrongFormatError } from '../errors';
22
import { TeamDeviceCredentials } from '../types';
33

44
let teamDeviceCredentials: TeamDeviceCredentials | null = null;
55

66
export const initTeamDeviceCredentials = (): TeamDeviceCredentials | null => {
7-
const { DASHLANE_TEAM_UUID, DASHLANE_TEAM_ACCESS_KEY, DASHLANE_TEAM_SECRET_KEY } = process.env;
8-
if (DASHLANE_TEAM_UUID && DASHLANE_TEAM_ACCESS_KEY && DASHLANE_TEAM_SECRET_KEY) {
7+
const { DASHLANE_TEAM_DEVICE_KEYS } = process.env;
8+
if (DASHLANE_TEAM_DEVICE_KEYS) {
9+
if (!DASHLANE_TEAM_DEVICE_KEYS.startsWith('dlt_')) {
10+
throw new TeamCredentialsWrongFormatError();
11+
}
12+
13+
const [accessKey, payloadB64] = DASHLANE_TEAM_DEVICE_KEYS.split('_').slice(1);
14+
15+
// TODO: Run AJV validation on the payload
16+
const payload = JSON.parse(Buffer.from(payloadB64, 'base64').toString('utf-8')) as {
17+
teamUuid: string;
18+
deviceSecretKey: string;
19+
};
20+
921
teamDeviceCredentials = {
10-
uuid: DASHLANE_TEAM_UUID,
11-
accessKey: DASHLANE_TEAM_ACCESS_KEY,
12-
secretKey: DASHLANE_TEAM_SECRET_KEY,
22+
uuid: payload.teamUuid,
23+
accessKey,
24+
secretKey: payload.deviceSecretKey,
1325
};
1426
}
1527
return teamDeviceCredentials;

0 commit comments

Comments
 (0)