-
Notifications
You must be signed in to change notification settings - Fork 32
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Merge pull request #51 from dotenv-org/dx
Dx
- Loading branch information
Showing
11 changed files
with
545 additions
and
541 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,15 @@ | ||
import {Command} from '@oclif/core' | ||
|
||
import {LoginService} from '../services/login-service' | ||
|
||
export default class Login extends Command { | ||
static description = 'Login to Dotenv Vault' | ||
|
||
static examples = [ | ||
'<%= config.bin %> <%= command.id %>', | ||
] | ||
|
||
public async run(): Promise<void> { | ||
new LoginService({cmd: this}).run() | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,91 @@ | ||
import chalk from 'chalk' | ||
import {vars} from '../vars' | ||
import {LogService} from '../services/log-service' | ||
|
||
interface AbortServiceAttrs { | ||
cmd; | ||
} | ||
|
||
class AbortService { | ||
public cmd; | ||
public log; | ||
|
||
constructor(attrs: AbortServiceAttrs = {} as AbortServiceAttrs) { | ||
this.cmd = attrs.cmd | ||
this.log = new LogService({cmd: attrs.cmd}) | ||
} | ||
|
||
missingEnvVault(): void { | ||
this.log.plain(`${chalk.red('x')} Aborted.`) | ||
this.cmd.error(`Missing ${vars.vaultFilename} (${vars.vaultKey}).`, { | ||
code: 'MISSING_DOTENV_VAULT', | ||
ref: '', | ||
suggestions: [`Missing ${vars.vaultFilename} (${vars.vaultKey}). To create it, run: npx dotenv-vault@latest new`], | ||
}) | ||
} | ||
|
||
emptyEnvVault(): void { | ||
this.log.plain(`${chalk.red('x')} Aborted.`) | ||
this.cmd.error(`Empty ${vars.vaultFilename} (${vars.vaultKey}).`, { | ||
code: 'EMPTY_DOTENV_VAULT', | ||
ref: '', | ||
suggestions: [`Empty ${vars.vaultFilename} (${vars.vaultKey}). To fix it, run: npx dotenv-vault@latest new`], | ||
}) | ||
} | ||
|
||
invalidEnvVault(): void { | ||
this.log.plain(`${chalk.red('x')} Aborted.`) | ||
this.cmd.error(`Invalid ${vars.vaultFilename} (${vars.vaultKey}).`, { | ||
code: 'INVALID_DOTENV_VAULT', | ||
ref: '', | ||
suggestions: [`Invalid ${vars.vaultFilename} (${vars.vaultKey}). To fix it, run: npx dotenv-vault@latest new`], | ||
}) | ||
} | ||
|
||
existingEnvVault(): void { | ||
this.log.plain(`${chalk.red('x')} Aborted.`) | ||
this.cmd.error(`Existing ${vars.vaultFilename} (${vars.vaultKey}).`, { | ||
code: 'EXISTING_DOTENV_VAULT', | ||
ref: '', | ||
suggestions: [`Existing ${vars.vaultFilename} (${vars.vaultKey}). To fix it, delete ${vars.vaultFilename} and then run: npx dotenv-vault@latest new`], | ||
}) | ||
} | ||
|
||
missingEnvMe(): void { | ||
this.log.plain(`${chalk.red('x')} Aborted.`) | ||
this.cmd.error('Missing .env.me (DOTENV_ME).', { | ||
code: 'MISSING_DOTENV_ME', | ||
ref: '', | ||
suggestions: ['Missing .env.me (DOTENV_ME). To create it, run: npx dotenv-vault@latest login'], | ||
}) | ||
} | ||
|
||
emptyEnvMe(): void { | ||
this.log.plain(`${chalk.red('x')} Aborted.`) | ||
this.cmd.error('Empty .env.me (DOTENV_ME).', { | ||
code: 'EMPTY_DOTENV_ME', | ||
ref: '', | ||
suggestions: ['Empty .env.me (DOTENV_ME). To create it, run: npx dotenv-vault@latest login'], | ||
}) | ||
} | ||
|
||
missingEnv(filename: string | any = '.env'): void { | ||
this.log.plain(`${chalk.red('x')} Aborted.`) | ||
this.cmd.error(`Missing ${filename}.`, { | ||
code: 'MISSING_ENV_FILE', | ||
ref: '', | ||
suggestions: [`Missing ${filename}. Create it (touch ${filename}) and then try again. Or run, npx dotenv-vault@latest pull`], | ||
}) | ||
} | ||
|
||
emptyEnv(filename: string | any = '.env'): void { | ||
this.log.plain(`${chalk.red('x')} Aborted.`) | ||
this.cmd.error(`Empty ${filename}.`, { | ||
code: 'EMPTY_ENV_FILE', | ||
ref: '', | ||
suggestions: [`Empty ${filename}. Populate it with values and then try again. Or run, npx dotenv-vault@latest pull`], | ||
}) | ||
} | ||
} | ||
|
||
export {AbortService} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,47 @@ | ||
import chalk from 'chalk' | ||
|
||
interface LogServiceAttrs { | ||
cmd; | ||
} | ||
|
||
class LogService { | ||
public cmd; | ||
|
||
constructor(attrs: LogServiceAttrs = {} as LogServiceAttrs) { | ||
this.cmd = attrs.cmd | ||
} | ||
|
||
get pretextLocal(): string { | ||
return 'local: ' | ||
} | ||
|
||
get pretextRemote(): string { | ||
return 'remote: ' | ||
} | ||
|
||
plain(msg: string): void { | ||
if (msg === undefined) { | ||
msg = '' | ||
} | ||
|
||
this.cmd.log(msg) | ||
} | ||
|
||
local(msg: string): void { | ||
if (msg === undefined) { | ||
msg = '' | ||
} | ||
|
||
this.cmd.log(`${chalk.dim(this.pretextLocal)}${msg}`) | ||
} | ||
|
||
remote(msg: string): void { | ||
if (msg === undefined) { | ||
msg = '' | ||
} | ||
|
||
this.cmd.log(`${chalk.dim(this.pretextRemote)}${msg}`) | ||
} | ||
} | ||
|
||
export {LogService} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,104 @@ | ||
import * as crypto from 'node:crypto' | ||
import chalk from 'chalk' | ||
import axios, {AxiosRequestConfig} from 'axios' | ||
import {existsSync, writeFileSync} from 'node:fs' | ||
import {vars} from '../vars' | ||
import {CliUx} from '@oclif/core' | ||
import {AppendToDockerignoreService} from '../services/append-to-dockerignore-service' | ||
import {AppendToGitignoreService} from '../services/append-to-gitignore-service' | ||
import {AppendToNpmignoreService} from '../services/append-to-npmignore-service' | ||
import {LogService} from '../services/log-service' | ||
import {AbortService} from '../services/abort-service' | ||
|
||
interface LoginServiceAttrs { | ||
cmd; | ||
} | ||
|
||
class LoginService { | ||
public cmd; | ||
public log; | ||
public requestUid; | ||
public controller; | ||
public abort; | ||
|
||
constructor(attrs: LoginServiceAttrs = {} as LoginServiceAttrs) { | ||
this.cmd = attrs.cmd | ||
this.log = new LogService({cmd: attrs.cmd}) | ||
this.abort = new AbortService({cmd: attrs.cmd}) | ||
|
||
const rand = crypto.randomBytes(32).toString('hex') | ||
this.requestUid = `req_${rand}` | ||
} | ||
|
||
async run(): Promise<void> { | ||
new AppendToDockerignoreService().run() | ||
new AppendToGitignoreService().run() | ||
new AppendToNpmignoreService().run() | ||
|
||
if (vars.missingEnvVault) { | ||
this.abort.missingEnvVault() | ||
} | ||
|
||
if (vars.emptyEnvVault) { | ||
this.abort.emptyEnvVault() | ||
} | ||
|
||
CliUx.ux.open(this.loginUrl) | ||
CliUx.ux.action.start(`${chalk.dim(this.log.pretextLocal)}Waiting for login`) | ||
this.check() | ||
} | ||
|
||
async check(): Promise<void> { | ||
if (this.controller) { | ||
this.controller.abort() | ||
} | ||
|
||
this.controller = new AbortController() | ||
|
||
const options: AxiosRequestConfig = { | ||
method: 'POST', | ||
headers: {'content-type': 'application/json'}, | ||
data: { | ||
vaultUid: vars.vaultValue, | ||
requestUid: this.requestUid, | ||
}, | ||
url: this.checkUrl, | ||
signal: this.controller.signal, | ||
} | ||
|
||
let resp | ||
try { | ||
resp = await axios(options) | ||
} catch (error: any) { | ||
resp = error.response | ||
} finally { | ||
if (resp.status < 300) { | ||
// Step 3 | ||
CliUx.ux.action.stop() | ||
const meUid = resp.data.data.meUid | ||
writeFileSync('.env.me', `DOTENV_ME=${meUid}`) | ||
this.log.local(`Logged in as .env.me (DOTENV_ME=${meUid.slice(0, 9)}...)`) | ||
this.log.plain('') | ||
this.log.plain(`Next run ${chalk.bold('npx dotenv-vault@latest pull')} or ${chalk.bold('npx dotenv-vault@latest push')}`) | ||
} else { | ||
// 404 - keep trying | ||
await CliUx.ux.wait(2000) // check every 2 seconds | ||
this.check() // check again | ||
} | ||
} | ||
} | ||
|
||
get loginUrl(): string { | ||
return `${vars.apiUrl}/login?vaultUid=${vars.vaultValue}&requestUid=${this.requestUid}` | ||
} | ||
|
||
get checkUrl(): string { | ||
return `${vars.apiUrl}/check?vaultUid=${vars.vaultValue}&requestUid=${this.requestUid}` | ||
} | ||
|
||
get existingEnvVault(): boolean { | ||
return existsSync(vars.vaultFilename) | ||
} | ||
} | ||
|
||
export {LoginService} |
Oops, something went wrong.