diff --git a/src/commands/generate.command.ts b/src/commands/generate.command.ts new file mode 100644 index 0000000000..97a7fc1baf --- /dev/null +++ b/src/commands/generate.command.ts @@ -0,0 +1,31 @@ +import * as program from 'commander'; + +import { PasswordGenerationService } from 'jslib/abstractions/passwordGeneration.service'; + +import { Response } from '../models/response'; +import { StringResponse } from '../models/response/stringResponse'; + +export class GenerateCommand { + constructor(private passwordGenerationService: PasswordGenerationService) { } + + async run(cmd: program.Command): Promise { + const options = { + uppercase: cmd.uppercase || false, + lowercase: cmd.lowercase || false, + number: cmd.number || false, + special: cmd.special || false, + length: cmd.length || 14, + }; + if (!options.uppercase && !options.lowercase && !options.special && !options.number) { + options.lowercase = true; + options.uppercase = true; + options.number = true; + } + if (options.length < 5) { + options.length = 5; + } + const password = await this.passwordGenerationService.generatePassword(options); + const res = new StringResponse(password); + return Response.success(res); + } +} diff --git a/src/commands/get.command.ts b/src/commands/get.command.ts index c10906ba77..bccc7273d3 100644 --- a/src/commands/get.command.ts +++ b/src/commands/get.command.ts @@ -5,8 +5,6 @@ import { CipherType } from 'jslib/enums/cipherType'; import { CipherService } from 'jslib/abstractions/cipher.service'; import { CollectionService } from 'jslib/abstractions/collection.service'; import { FolderService } from 'jslib/abstractions/folder.service'; -import { PasswordGenerationService } from 'jslib/abstractions/passwordGeneration.service'; -import { SyncService } from 'jslib/abstractions/sync.service'; import { TotpService } from 'jslib/abstractions/totp.service'; import { CipherView } from 'jslib/models/view/cipherView'; @@ -34,14 +32,9 @@ import { CliUtils } from '../utils'; export class GetCommand { constructor(private cipherService: CipherService, private folderService: FolderService, - private collectionService: CollectionService, private totpService: TotpService, - private syncService: SyncService, private passwordGenerationService: PasswordGenerationService) { } + private collectionService: CollectionService, private totpService: TotpService) { } async run(object: string, id: string, cmd: program.Command): Promise { - if (id == null && object !== 'lastsync' && object !== 'password') { - return Response.badRequest('`id` argument is required.'); - } - if (id != null) { id = id.toLowerCase(); } @@ -57,10 +50,6 @@ export class GetCommand { return await this.getCollection(id); case 'template': return await this.getTemplate(id); - case 'lastsync': - return await this.getLastSync(); - case 'password': - return await this.getPassword(cmd); default: return Response.badRequest('Unknown object.'); } @@ -206,31 +195,4 @@ export class GetCommand { const res = new TemplateResponse(template); return Response.success(res); } - - private async getLastSync() { - const lastSyncDate = await this.syncService.getLastSync(); - const res = new StringResponse(lastSyncDate == null ? null : lastSyncDate.toISOString()); - return Response.success(res); - } - - private async getPassword(cmd: program.Command) { - const options = { - uppercase: cmd.uppercase || false, - lowercase: cmd.lowercase || false, - number: cmd.number || false, - special: cmd.special || false, - length: cmd.length || 14, - }; - if (!options.uppercase && !options.lowercase && !options.special && !options.number) { - options.lowercase = true; - options.uppercase = true; - options.number = true; - } - if (options.length < 5) { - options.length = 5; - } - const password = await this.passwordGenerationService.generatePassword(options); - const res = new StringResponse(password); - return Response.success(res); - } } diff --git a/src/commands/sync.command.ts b/src/commands/sync.command.ts index 2cc9eb1421..a3ba3f23f6 100644 --- a/src/commands/sync.command.ts +++ b/src/commands/sync.command.ts @@ -3,16 +3,29 @@ import * as program from 'commander'; import { SyncService } from 'jslib/abstractions/sync.service'; import { Response } from '../models/response'; +import { MessageResponse } from '../models/response/messageResponse'; +import { StringResponse } from '../models/response/stringResponse'; export class SyncCommand { constructor(private syncService: SyncService) { } async run(cmd: program.Command): Promise { + if (cmd.last || false) { + return await this.getLastSync(); + } + try { const result = await this.syncService.fullSync(cmd.force || false); - return Response.success(); + const res = new MessageResponse('Syncing complete.', null); + return Response.success(res); } catch (e) { return Response.error(e); } } + + private async getLastSync() { + const lastSyncDate = await this.syncService.getLastSync(); + const res = new StringResponse(lastSyncDate == null ? null : lastSyncDate.toISOString()); + return Response.success(res); + } } diff --git a/src/program.ts b/src/program.ts index 15dfef365b..b8d53c3b2e 100644 --- a/src/program.ts +++ b/src/program.ts @@ -7,6 +7,7 @@ import { CreateCommand } from './commands/create.command'; import { DeleteCommand } from './commands/delete.command'; import { EditCommand } from './commands/edit.command'; import { EncodeCommand } from './commands/encode.command'; +import { GenerateCommand } from './commands/generate.command'; import { GetCommand } from './commands/get.command'; import { ListCommand } from './commands/list.command'; import { LockCommand } from './commands/lock.command'; @@ -53,8 +54,8 @@ export class Program { program .command('login [email] [password]') .description('Log into a Bitwarden user account.') - .option('-m, --method ', 'Two-step login method.') - .option('-c, --code ', 'Two-step login code.') + .option('--method ', 'Two-step login method.') + .option('--code ', 'Two-step login code.') .action(async (email: string, password: string, cmd: program.Command) => { await this.exitIfAuthed(); const command = new LoginCommand(this.main.authService, this.main.apiService, @@ -98,6 +99,7 @@ export class Program { .command('sync') .description('Sync user\'s vault from server.') .option('-f, --force', 'Force a full sync.') + .option('--last', 'Get the last sync date.') .action(async (cmd) => { await this.exitIfLocked(); const command = new SyncCommand(this.main.syncService); @@ -121,18 +123,12 @@ export class Program { }); program - .command('get [id]') + .command('get ') .description('Get an object.') - .option('--uppercase', 'Include uppercase characters.') - .option('--lowercase', 'Include lowercase characters.') - .option('--number', 'Include numeric characters.') - .option('--special', 'Include special characters.') - .option('--length ', 'Password length.') .action(async (object, id, cmd) => { await this.exitIfLocked(); const command = new GetCommand(this.main.cipherService, this.main.folderService, - this.main.collectionService, this.main.totpService, this.main.syncService, - this.main.passwordGenerationService); + this.main.collectionService, this.main.totpService); const response = await command.run(object, id, cmd); this.processResponse(response); }); @@ -167,6 +163,20 @@ export class Program { this.processResponse(response); }); + program + .command('generate') + .description('Generate a password.') + .option('-u, --uppercase', 'Include uppercase characters.') + .option('-l, --lowercase', 'Include lowercase characters.') + .option('-n, --number', 'Include numeric characters.') + .option('-s, --special', 'Include special characters.') + .option('--length ', 'Length of the password.') + .action(async (cmd) => { + const command = new GenerateCommand(this.main.passwordGenerationService); + const response = await command.run(cmd); + this.processResponse(response); + }); + program .command('encode') .description('Base64 encode stdin.')