Skip to content

Commit

Permalink
Use device credentials from env (#150)
Browse files Browse the repository at this point in the history
This is a simple way to bypass manually inputing email and master
password as well as registering a device.

Fix #130
  • Loading branch information
Mikescops authored Aug 4, 2023
1 parent e403458 commit f27f2cc
Show file tree
Hide file tree
Showing 10 changed files with 58 additions and 7 deletions.
1 change: 1 addition & 0 deletions documentation/pages/personal/devices.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -67,6 +67,7 @@ Run the suggested commands on your target device (your server or CI) to set the
```sh
export DASHLANE_DEVICE_ACCESS_KEY=bdd5[..redacted..]6eb
export DASHLANE_DEVICE_SECRET_KEY=99f7d9bd547c0[..redacted..]c93fa2118cdf7e3d0
export DASHLANE_LOGIN=email@domain.com
export DASHLANE_MASTER_PASSWORD=<insert your master password here>
```

Expand Down
2 changes: 1 addition & 1 deletion documentation/theme.config.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -38,7 +38,7 @@ export default {
property="og:description"
content={frontMatter.description || 'Learn how to access your Dashlane vault and API endpoints from the command line.'}
/>
<link rel="icon" href="/favicon.png" type="image/png" />
<link rel="icon" href="/dashlane-cli/favicon.png" type="image/png" />
</>
);
}
Expand Down
1 change: 1 addition & 0 deletions src/command-handlers/devices.ts
Original file line number Diff line number Diff line change
Expand Up @@ -127,6 +127,7 @@ export const registerNonInteractiveDevice = async (deviceName: string, options:
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>`);
}

Expand Down
2 changes: 1 addition & 1 deletion src/command-handlers/logout.ts
Original file line number Diff line number Diff line change
Expand Up @@ -34,7 +34,7 @@ export const runLogout = async () => {
deviceIds: [deviceConfiguration.accessKey],
login: deviceConfiguration.login,
secrets,
});
}).catch((error) => console.error('Unable to deactivate the device', error));
}
reset({ db, secrets });
console.log('The local Dashlane local storage has been reset and you have been logged out');
Expand Down
3 changes: 2 additions & 1 deletion src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ import winston from 'winston';

import { cliVersionToString, CLI_VERSION } from './cliVersion';
import { rootCommands } from './commands';
import { initTeamDeviceCredentials } from './utils';
import { initDeviceCredentials, initTeamDeviceCredentials } from './utils';

const debugLevel = process.argv.indexOf('--debug') !== -1 ? 'debug' : 'info';

Expand All @@ -15,6 +15,7 @@ winston.configure({
});

initTeamDeviceCredentials();
initDeviceCredentials();

const program = new Command();

Expand Down
16 changes: 12 additions & 4 deletions src/modules/crypto/keychainManager.ts
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ import { perform2FAVerification, registerDevice } from '../auth';
import { DeviceConfiguration, Secrets } from '../../types';
import { askEmailAddress, askMasterPassword } from '../../utils/dialogs';
import { get2FAStatusUnauthenticated } from '../../endpoints/get2FAStatusUnauthenticated';
import { getDeviceCredentials } from '../../utils';

const SERVICE = 'dashlane-cli';

Expand Down Expand Up @@ -86,10 +87,17 @@ const getSecretsWithoutDB = async (
const localKey = generateLocalKey();

// Register the user's device
const { deviceAccessKey, deviceSecretKey, serverKey } = await registerDevice({
login,
deviceName: `${os.hostname()} - ${os.platform()}-${os.arch()}`,
});
const deviceCredentials = getDeviceCredentials();
const { deviceAccessKey, deviceSecretKey, serverKey } = deviceCredentials
? {
deviceAccessKey: deviceCredentials.accessKey,
deviceSecretKey: deviceCredentials.secretKey,
serverKey: undefined,
}
: await registerDevice({
login,
deviceName: `${os.hostname()} - ${os.platform()}-${os.arch()}`,
});

// Get the authentication type (mainly to identify if the user is with OTP2)
const { type } = await get2FAStatusUnauthenticated({ login });
Expand Down
7 changes: 7 additions & 0 deletions src/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,13 @@ export interface TeamDeviceCredentials {
secretKey: string;
}

export interface DeviceCredentials {
login: string;
accessKey: string;
secretKey: string;
masterPassword: string;
}

export interface DeviceConfiguration extends DeviceKeys {
login: string;
version: string;
Expand Down
21 changes: 21 additions & 0 deletions src/utils/deviceCredentials.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
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) {
deviceCredentials = {
login: DASHLANE_LOGIN,
accessKey: DASHLANE_DEVICE_ACCESS_KEY,
secretKey: DASHLANE_DEVICE_SECRET_KEY,
masterPassword: DASHLANE_MASTER_PASSWORD,
};
}
return deviceCredentials;
};

export const getDeviceCredentials = (): DeviceCredentials | null => {
return deviceCredentials;
};
11 changes: 11 additions & 0 deletions src/utils/dialogs.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
import inquirer from 'inquirer';
import inquirerSearchList from 'inquirer-search-list';
import { removeUnderscoresAndCapitalize } from './strings';
import { getDeviceCredentials } from './deviceCredentials';
import {
PrintableVaultCredential,
PrintableVaultNote,
Expand All @@ -14,6 +15,11 @@ export const prompt = inquirer.createPromptModule({ output: process.stderr });
prompt.registerPrompt('search-list', inquirerSearchList as PromptConstructor);

export const askMasterPassword = async (): Promise<string> => {
const deviceCredentials = getDeviceCredentials();
if (deviceCredentials !== null) {
return deviceCredentials.masterPassword;
}

const response = await prompt<{ masterPassword: string }>([
{
type: 'password',
Expand Down Expand Up @@ -53,6 +59,11 @@ export const askIgnoreBreakingChanges = async () => {
};

export const askEmailAddress = async (): Promise<string> => {
const deviceCredentials = getDeviceCredentials();
if (deviceCredentials !== null) {
return deviceCredentials.login;
}

const response = await prompt<{ login: string }>([
{
type: 'input',
Expand Down
1 change: 1 addition & 0 deletions src/utils/index.ts
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
export * from './deviceCredentials';
export * from './dialogs';
export * from './gotImplementation';
export * from './strings';
Expand Down

0 comments on commit f27f2cc

Please sign in to comment.