Skip to content

Commit

Permalink
Migrate to service device keys format (#220)
Browse files Browse the repository at this point in the history
Following an internal ADR (Architecture Decision Record), I'm updating
the non-interactive device registration and usage to a new format.
  • Loading branch information
Corentin Mors authored Mar 15, 2024
1 parent 7cb091b commit d71249b
Show file tree
Hide file tree
Showing 4 changed files with 47 additions and 20 deletions.
13 changes: 8 additions & 5 deletions documentation/pages/personal/devices.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -64,14 +64,17 @@ This will create a new device named `my_server` and will print the device creden
Save them in a safe place (like in a secure note), as you won't be able to retrieve them later.
Run the suggested commands on your target device (your server or CI) to set the device credentials as environment variables.

```sh
export DASHLANE_SERVICE_DEVICE_KEYS=dls_[deviceAccessKey]_[payload]
```

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

```sh
export DASHLANE_DEVICE_ACCESS_KEY=bdd5[..redacted..]6eb
export DASHLANE_DEVICE_SECRET_KEY=99f7d9bd547c0[..redacted..]c93fa2118cdf7e3d0
export [email protected]
export DASHLANE_MASTER_PASSWORD=<insert your master password here>
set DASHLANE_SERVICE_DEVICE_KEYS=dls_[deviceAccessKey]_[payload]
```

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

<Callout type="warning" emoji="⚠️">
OTP at each login and SSO are not supported for non-interactive devices. We recommend creating a dedicated Dashlane
Expand Down
22 changes: 14 additions & 8 deletions src/command-handlers/devices.ts
Original file line number Diff line number Diff line change
Expand Up @@ -97,7 +97,7 @@ export async function removeAllDevices(devices: string[] | null, options: { all:

export const registerNonInteractiveDevice = async (deviceName: string, options: { json: boolean }) => {
const {
localConfiguration: { login },
localConfiguration: { login, masterPassword },
db,
} = await connectAndPrepare({ autoSync: false });

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

const serviceDeviceKeysPayload = {
login,
deviceSecretKey,
masterPassword,
};

const serviceDeviceKeysPayloadB64 = Buffer.from(JSON.stringify(serviceDeviceKeysPayload)).toString('base64');

const serviceDeviceKeys = `dls_${deviceAccessKey}_${serviceDeviceKeysPayloadB64}`;

if (options.json) {
console.log(
JSON.stringify({
DASHLANE_DEVICE_ACCESS_KEY: deviceAccessKey,
DASHLANE_DEVICE_SECRET_KEY: deviceSecretKey,
DASHLANE_SERVICE_DEVICE_KEYS: serviceDeviceKeys,
})
);
} else {
winston.info('The device credentials have been generated, save and run the following commands to export them:');
console.log(`export DASHLANE_DEVICE_ACCESS_KEY=${deviceAccessKey}`);
console.log(`export DASHLANE_DEVICE_SECRET_KEY=${deviceSecretKey}`);
console.log(`export DASHLANE_LOGIN=${login}`);
console.log(`export DASHLANE_MASTER_PASSWORD=<insert your master password here>`);
winston.info('The device credentials have been generated, save and run the following command to export them:');
console.log(`export DASHLANE_SERVICE_DEVICE_KEYS=${serviceDeviceKeys}`);
}

db.close();
Expand Down
6 changes: 6 additions & 0 deletions src/errors.ts
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,12 @@ export class TeamCredentialsWrongFormatError extends Error {
}
}

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

export class InvalidDashlanePathError extends Error {
constructor() {
super('Invalid Dashlane path');
Expand Down
26 changes: 19 additions & 7 deletions src/utils/deviceCredentials.ts
Original file line number Diff line number Diff line change
@@ -1,16 +1,28 @@
import { DeviceCredentialsWrongFormatError } from '../errors';
import { DeviceCredentials } from '../types';

let deviceCredentials: DeviceCredentials | null = null;

export const initDeviceCredentials = (): DeviceCredentials | null => {
const { DASHLANE_DEVICE_ACCESS_KEY, DASHLANE_DEVICE_SECRET_KEY, DASHLANE_LOGIN, DASHLANE_MASTER_PASSWORD } =
process.env;
if (DASHLANE_DEVICE_ACCESS_KEY && DASHLANE_DEVICE_SECRET_KEY && DASHLANE_LOGIN && DASHLANE_MASTER_PASSWORD) {
const { DASHLANE_SERVICE_DEVICE_KEYS } = process.env;
if (DASHLANE_SERVICE_DEVICE_KEYS) {
if (!DASHLANE_SERVICE_DEVICE_KEYS.startsWith('dls_')) {
throw new DeviceCredentialsWrongFormatError();
}

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

const payload = JSON.parse(Buffer.from(payloadB64, 'base64').toString('utf-8')) as {
login: string;
deviceSecretKey: string;
masterPassword: string;
};

deviceCredentials = {
login: DASHLANE_LOGIN,
accessKey: DASHLANE_DEVICE_ACCESS_KEY,
secretKey: DASHLANE_DEVICE_SECRET_KEY,
masterPassword: DASHLANE_MASTER_PASSWORD,
login: payload.login,
accessKey,
secretKey: payload.deviceSecretKey,
masterPassword: payload.masterPassword,
};
}
return deviceCredentials;
Expand Down

0 comments on commit d71249b

Please sign in to comment.