Skip to content

Commit d71249b

Browse files
author
Corentin Mors
authored
Migrate to service device keys format (#220)
Following an internal ADR (Architecture Decision Record), I'm updating the non-interactive device registration and usage to a new format.
1 parent 7cb091b commit d71249b

File tree

4 files changed

+47
-20
lines changed

4 files changed

+47
-20
lines changed

documentation/pages/personal/devices.mdx

+8-5
Original file line numberDiff line numberDiff line change
@@ -64,14 +64,17 @@ This will create a new device named `my_server` and will print the device creden
6464
Save them in a safe place (like in a secure note), as you won't be able to retrieve them later.
6565
Run the suggested commands on your target device (your server or CI) to set the device credentials as environment variables.
6666

67+
```sh
68+
export DASHLANE_SERVICE_DEVICE_KEYS=dls_[deviceAccessKey]_[payload]
69+
```
70+
71+
On Windows, you can use the `set` command instead of `export`.
72+
6773
```sh
68-
export DASHLANE_DEVICE_ACCESS_KEY=bdd5[..redacted..]6eb
69-
export DASHLANE_DEVICE_SECRET_KEY=99f7d9bd547c0[..redacted..]c93fa2118cdf7e3d0
70-
export DASHLANE_LOGIN=email@domain.com
71-
export DASHLANE_MASTER_PASSWORD=<insert your master password here>
74+
set DASHLANE_SERVICE_DEVICE_KEYS=dls_[deviceAccessKey]_[payload]
7275
```
7376

74-
Please, replace `<insert your master password here>` with your actual master password.
77+
<Callout emoji="ℹ️">The token you'll get is starting by `dls` in order to be easily identified by scanning tools.</Callout>
7578

7679
<Callout type="warning" emoji="⚠️">
7780
OTP at each login and SSO are not supported for non-interactive devices. We recommend creating a dedicated Dashlane

src/command-handlers/devices.ts

+14-8
Original file line numberDiff line numberDiff line change
@@ -97,7 +97,7 @@ export async function removeAllDevices(devices: string[] | null, options: { all:
9797

9898
export const registerNonInteractiveDevice = async (deviceName: string, options: { json: boolean }) => {
9999
const {
100-
localConfiguration: { login },
100+
localConfiguration: { login, masterPassword },
101101
db,
102102
} = await connectAndPrepare({ autoSync: false });
103103

@@ -116,19 +116,25 @@ export const registerNonInteractiveDevice = async (deviceName: string, options:
116116
deviceName: `Non-Interactive - ${deviceName}`,
117117
});
118118

119+
const serviceDeviceKeysPayload = {
120+
login,
121+
deviceSecretKey,
122+
masterPassword,
123+
};
124+
125+
const serviceDeviceKeysPayloadB64 = Buffer.from(JSON.stringify(serviceDeviceKeysPayload)).toString('base64');
126+
127+
const serviceDeviceKeys = `dls_${deviceAccessKey}_${serviceDeviceKeysPayloadB64}`;
128+
119129
if (options.json) {
120130
console.log(
121131
JSON.stringify({
122-
DASHLANE_DEVICE_ACCESS_KEY: deviceAccessKey,
123-
DASHLANE_DEVICE_SECRET_KEY: deviceSecretKey,
132+
DASHLANE_SERVICE_DEVICE_KEYS: serviceDeviceKeys,
124133
})
125134
);
126135
} else {
127-
winston.info('The device credentials have been generated, save and run the following commands to export them:');
128-
console.log(`export DASHLANE_DEVICE_ACCESS_KEY=${deviceAccessKey}`);
129-
console.log(`export DASHLANE_DEVICE_SECRET_KEY=${deviceSecretKey}`);
130-
console.log(`export DASHLANE_LOGIN=${login}`);
131-
console.log(`export DASHLANE_MASTER_PASSWORD=<insert your master password here>`);
136+
winston.info('The device credentials have been generated, save and run the following command to export them:');
137+
console.log(`export DASHLANE_SERVICE_DEVICE_KEYS=${serviceDeviceKeys}`);
132138
}
133139

134140
db.close();

src/errors.ts

+6
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,12 @@ export class TeamCredentialsWrongFormatError extends Error {
1010
}
1111
}
1212

13+
export class DeviceCredentialsWrongFormatError extends Error {
14+
constructor() {
15+
super('Device credentials has a wrong format');
16+
}
17+
}
18+
1319
export class InvalidDashlanePathError extends Error {
1420
constructor() {
1521
super('Invalid Dashlane path');

src/utils/deviceCredentials.ts

+19-7
Original file line numberDiff line numberDiff line change
@@ -1,16 +1,28 @@
1+
import { DeviceCredentialsWrongFormatError } from '../errors';
12
import { DeviceCredentials } from '../types';
23

34
let deviceCredentials: DeviceCredentials | null = null;
45

56
export const initDeviceCredentials = (): DeviceCredentials | null => {
6-
const { DASHLANE_DEVICE_ACCESS_KEY, DASHLANE_DEVICE_SECRET_KEY, DASHLANE_LOGIN, DASHLANE_MASTER_PASSWORD } =
7-
process.env;
8-
if (DASHLANE_DEVICE_ACCESS_KEY && DASHLANE_DEVICE_SECRET_KEY && DASHLANE_LOGIN && DASHLANE_MASTER_PASSWORD) {
7+
const { DASHLANE_SERVICE_DEVICE_KEYS } = process.env;
8+
if (DASHLANE_SERVICE_DEVICE_KEYS) {
9+
if (!DASHLANE_SERVICE_DEVICE_KEYS.startsWith('dls_')) {
10+
throw new DeviceCredentialsWrongFormatError();
11+
}
12+
13+
const [accessKey, payloadB64] = DASHLANE_SERVICE_DEVICE_KEYS.split('_').slice(1);
14+
15+
const payload = JSON.parse(Buffer.from(payloadB64, 'base64').toString('utf-8')) as {
16+
login: string;
17+
deviceSecretKey: string;
18+
masterPassword: string;
19+
};
20+
921
deviceCredentials = {
10-
login: DASHLANE_LOGIN,
11-
accessKey: DASHLANE_DEVICE_ACCESS_KEY,
12-
secretKey: DASHLANE_DEVICE_SECRET_KEY,
13-
masterPassword: DASHLANE_MASTER_PASSWORD,
22+
login: payload.login,
23+
accessKey,
24+
secretKey: payload.deviceSecretKey,
25+
masterPassword: payload.masterPassword,
1426
};
1527
}
1628
return deviceCredentials;

0 commit comments

Comments
 (0)