@dotenvx/dotenvx-vlt 0.49.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (125) hide show
  1. package/CHANGELOG.md +652 -0
  2. package/LICENSE +71 -0
  3. package/README.md +11 -0
  4. package/package.json +77 -0
  5. package/src/cli/actions/armor/down.js +37 -0
  6. package/src/cli/actions/armor/move.js +42 -0
  7. package/src/cli/actions/armor/pull.js +37 -0
  8. package/src/cli/actions/armor/push.js +37 -0
  9. package/src/cli/actions/armor/rotate.js +25 -0
  10. package/src/cli/actions/armor/up.js +37 -0
  11. package/src/cli/actions/backup.js +93 -0
  12. package/src/cli/actions/gateway/start.js +17 -0
  13. package/src/cli/actions/get.js +34 -0
  14. package/src/cli/actions/keypair.js +59 -0
  15. package/src/cli/actions/login.js +110 -0
  16. package/src/cli/actions/logout.js +36 -0
  17. package/src/cli/actions/observe.js +36 -0
  18. package/src/cli/actions/open.js +37 -0
  19. package/src/cli/actions/rotate/github/connect.js +84 -0
  20. package/src/cli/actions/rotate/npm/connect.js +84 -0
  21. package/src/cli/actions/rotate/openai/connect.js +84 -0
  22. package/src/cli/actions/rotate.js +44 -0
  23. package/src/cli/actions/set.js +34 -0
  24. package/src/cli/actions/settings/device.js +24 -0
  25. package/src/cli/actions/settings/hostname.js +20 -0
  26. package/src/cli/actions/settings/off.js +17 -0
  27. package/src/cli/actions/settings/on.js +17 -0
  28. package/src/cli/actions/settings/path.js +21 -0
  29. package/src/cli/actions/settings/token.js +24 -0
  30. package/src/cli/actions/settings/username.js +22 -0
  31. package/src/cli/actions/status.js +13 -0
  32. package/src/cli/actions/sync.js +104 -0
  33. package/src/cli/commands/armor.js +73 -0
  34. package/src/cli/commands/gateway.js +16 -0
  35. package/src/cli/commands/rotate/github.js +26 -0
  36. package/src/cli/commands/rotate/npm.js +26 -0
  37. package/src/cli/commands/rotate/openai.js +26 -0
  38. package/src/cli/commands/rotate.js +32 -0
  39. package/src/cli/commands/settings.js +60 -0
  40. package/src/cli/dotenvx-ops.js +163 -0
  41. package/src/cli/postinstall.js +16 -0
  42. package/src/db/device.js +73 -0
  43. package/src/db/session.js +193 -0
  44. package/src/lib/api/getAccount.js +32 -0
  45. package/src/lib/api/getSynchronization.js +34 -0
  46. package/src/lib/api/getVersion.js +24 -0
  47. package/src/lib/api/postArmorDown.js +48 -0
  48. package/src/lib/api/postArmorMove.js +48 -0
  49. package/src/lib/api/postArmorPull.js +48 -0
  50. package/src/lib/api/postArmorPush.js +48 -0
  51. package/src/lib/api/postArmorUp.js +51 -0
  52. package/src/lib/api/postBackup.js +68 -0
  53. package/src/lib/api/postGet.js +37 -0
  54. package/src/lib/api/postKeypair.js +60 -0
  55. package/src/lib/api/postLogout.js +34 -0
  56. package/src/lib/api/postOauthDeviceCode.js +45 -0
  57. package/src/lib/api/postOauthToken.js +38 -0
  58. package/src/lib/api/postObserve.js +62 -0
  59. package/src/lib/api/postRotate.js +39 -0
  60. package/src/lib/api/postRotateConnect.js +54 -0
  61. package/src/lib/api/postSet.js +43 -0
  62. package/src/lib/api/postSync.js +68 -0
  63. package/src/lib/helpers/armoredKeyDisplay.js +10 -0
  64. package/src/lib/helpers/buildApiError.js +16 -0
  65. package/src/lib/helpers/buildOauthError.js +13 -0
  66. package/src/lib/helpers/canonicalEnvFilename.js +13 -0
  67. package/src/lib/helpers/clipboardy/fallbacks/linux/xsel +0 -0
  68. package/src/lib/helpers/clipboardy/fallbacks/windows/clipboard_i686.exe +0 -0
  69. package/src/lib/helpers/clipboardy/fallbacks/windows/clipboard_x86_64.exe +0 -0
  70. package/src/lib/helpers/clipboardy/linux.js +57 -0
  71. package/src/lib/helpers/clipboardy/macos.js +14 -0
  72. package/src/lib/helpers/clipboardy/termux.js +41 -0
  73. package/src/lib/helpers/clipboardy/windows.js +16 -0
  74. package/src/lib/helpers/clipboardy.js +51 -0
  75. package/src/lib/helpers/confirm.js +17 -0
  76. package/src/lib/helpers/createSpinner.js +101 -0
  77. package/src/lib/helpers/createSpinner2.js +24 -0
  78. package/src/lib/helpers/decryptValue.js +10 -0
  79. package/src/lib/helpers/dotenvxProjectId.js +36 -0
  80. package/src/lib/helpers/encryptValue.js +9 -0
  81. package/src/lib/helpers/errors.js +30 -0
  82. package/src/lib/helpers/formatCode.js +11 -0
  83. package/src/lib/helpers/gitBranch.js +13 -0
  84. package/src/lib/helpers/gitUrl.js +13 -0
  85. package/src/lib/helpers/http.js +17 -0
  86. package/src/lib/helpers/jsonToEnv.js +7 -0
  87. package/src/lib/helpers/keyNamesForEnvFile.js +43 -0
  88. package/src/lib/helpers/keypairMetadata.js +88 -0
  89. package/src/lib/helpers/likelyUpdateCommand.js +33 -0
  90. package/src/lib/helpers/localKeypair.js +12 -0
  91. package/src/lib/helpers/mask.js +12 -0
  92. package/src/lib/helpers/normalizePath.js +5 -0
  93. package/src/lib/helpers/normalizeToken.js +5 -0
  94. package/src/lib/helpers/openUrl.js +7 -0
  95. package/src/lib/helpers/packageJson.js +3 -0
  96. package/src/lib/helpers/playwrightConnect.js +29 -0
  97. package/src/lib/helpers/pluralize.js +10 -0
  98. package/src/lib/helpers/prompts.js +68 -0
  99. package/src/lib/helpers/removeEnvKey.js +50 -0
  100. package/src/lib/helpers/safeRealpath.js +13 -0
  101. package/src/lib/helpers/sha256File.js +9 -0
  102. package/src/lib/helpers/smartMask.js +11 -0
  103. package/src/lib/helpers/truncate.js +10 -0
  104. package/src/lib/helpers/upsertEnvKey.js +61 -0
  105. package/src/lib/main.d.ts +152 -0
  106. package/src/lib/main.js +114 -0
  107. package/src/lib/services/armorDown.js +77 -0
  108. package/src/lib/services/armorMove.js +54 -0
  109. package/src/lib/services/armorPull.js +77 -0
  110. package/src/lib/services/armorPush.js +82 -0
  111. package/src/lib/services/armorUp.js +79 -0
  112. package/src/lib/services/backup.js +105 -0
  113. package/src/lib/services/gatewayStart.js +132 -0
  114. package/src/lib/services/keypair.js +59 -0
  115. package/src/lib/services/loggedIn.js +24 -0
  116. package/src/lib/services/login.js +28 -0
  117. package/src/lib/services/loginPoll.js +43 -0
  118. package/src/lib/services/logout.js +28 -0
  119. package/src/lib/services/rotate.js +28 -0
  120. package/src/lib/services/rotateGithubConnect.js +56 -0
  121. package/src/lib/services/rotateNpmConnect.js +56 -0
  122. package/src/lib/services/rotateOpenaiConnect.js +60 -0
  123. package/src/lib/services/status.js +11 -0
  124. package/src/lib/services/sync.js +70 -0
  125. package/src/lib/services/syncConflict.js +36 -0
@@ -0,0 +1,9 @@
1
+ const fs = require('fs')
2
+ const crypto = require('crypto')
3
+
4
+ function sha256File (filepath) {
5
+ const buf = fs.readFileSync(filepath)
6
+ return crypto.createHash('sha256').update(buf).digest('hex')
7
+ }
8
+
9
+ module.exports = sha256File
@@ -0,0 +1,11 @@
1
+ const mask = require('./mask')
2
+
3
+ function smartMask (str, unmask = false, showChar = 7) {
4
+ if (unmask) {
5
+ return str
6
+ } else {
7
+ return mask(str, showChar)
8
+ }
9
+ }
10
+
11
+ module.exports = smartMask
@@ -0,0 +1,10 @@
1
+ function truncate (str, showChar = 7) {
2
+ if (str && str.length > 0) {
3
+ const visiblePart = str.slice(0, showChar)
4
+ return visiblePart + '…'
5
+ } else {
6
+ return ''
7
+ }
8
+ }
9
+
10
+ module.exports = truncate
@@ -0,0 +1,61 @@
1
+ const fs = require('fs')
2
+ const path = require('path')
3
+
4
+ function escapeForRegex (value) {
5
+ return value.replace(/[.*+?^${}()|[\]\\]/g, '\\$&')
6
+ }
7
+
8
+ function upsertEnvKey (key, value, keysFilepath = '.env.keys') {
9
+ const resolvedKeysFilepath = path.resolve(keysFilepath)
10
+ const keyValueLine = `${key}=${value}`
11
+ const created = !fs.existsSync(resolvedKeysFilepath)
12
+
13
+ let src = ''
14
+ if (!created) {
15
+ src = fs.readFileSync(resolvedKeysFilepath, 'utf8')
16
+ }
17
+
18
+ const eol = src.includes('\r\n') ? '\r\n' : '\n'
19
+ const keyPattern = new RegExp(`^\\s*(?:export\\s+)?${escapeForRegex(key)}\\s*=`)
20
+ const lines = src.length > 0 ? src.split(/\r?\n/) : []
21
+
22
+ while (lines.length > 0 && lines[lines.length - 1] === '') {
23
+ lines.pop()
24
+ }
25
+
26
+ let replaced = false
27
+ const nextLines = []
28
+
29
+ for (const line of lines) {
30
+ if (keyPattern.test(line)) {
31
+ if (!replaced) {
32
+ nextLines.push(keyValueLine)
33
+ replaced = true
34
+ }
35
+ continue
36
+ }
37
+
38
+ nextLines.push(line)
39
+ }
40
+
41
+ if (!replaced) {
42
+ nextLines.push(keyValueLine)
43
+ }
44
+
45
+ const nextSrc = `${nextLines.join(eol)}${eol}`
46
+ const changed = created || nextSrc !== src
47
+
48
+ if (changed) {
49
+ fs.writeFileSync(resolvedKeysFilepath, nextSrc, 'utf8')
50
+ }
51
+
52
+ return {
53
+ changed,
54
+ key,
55
+ value,
56
+ created,
57
+ filepath: keysFilepath
58
+ }
59
+ }
60
+
61
+ module.exports = upsertEnvKey
@@ -0,0 +1,152 @@
1
+ import type { URL } from 'url';
2
+
3
+ /**
4
+ * Observes a dotenvx run
5
+ *
6
+ * @see https://dotenvx.com/docs
7
+ * @param payload - observability payload string
8
+ * @returns the original payload string
9
+ */
10
+ export function observe(payload: string): string;
11
+
12
+ export interface DotenvOpsOptions {
13
+ hostname?: string;
14
+ token?: string;
15
+ }
16
+
17
+ export interface DotenvOpsKeypairOptions extends DotenvOpsOptions {
18
+ team?: string;
19
+ }
20
+
21
+ export interface DotenvOpsKeypairOutput {
22
+ publicKey: string;
23
+ privateKey: string;
24
+ }
25
+
26
+ /**
27
+ * Creates a remote keypair for the current authenticated device.
28
+ *
29
+ * @param publicKey - optional existing public key to fetch
30
+ * @param options - optional hostname/token/team overrides
31
+ * @returns generated public and private keys
32
+ */
33
+ export function keypair(publicKey?: string, options?: DotenvOpsKeypairOptions): Promise<DotenvOpsKeypairOutput>;
34
+
35
+ export interface DotenvConfigOptions {
36
+ /**
37
+ * Specify a custom path if your file containing environment variables is located elsewhere.
38
+ * Can also be an array of strings, specifying multiple paths.
39
+ *
40
+ * @default require('path').resolve(process.cwd(), '.env')
41
+ * @example require('@dotenvx/dotenvx').config({ path: '/custom/path/to/.env' })
42
+ * @example require('@dotenvx/dotenvx').config({ path: ['/path/to/first.env', '/path/to/second.env'] })
43
+ */
44
+ path?: string | string[] | URL;
45
+
46
+ /**
47
+ * Specify the encoding of your file containing environment variables.
48
+ *
49
+ * @default 'utf8'
50
+ * @example require('@dotenvx/dotenvx').config({ encoding: 'latin1' })
51
+ */
52
+ encoding?: string;
53
+
54
+ /**
55
+ * Override any environment variables that have already been set on your machine with values from your .env file.
56
+ * @default false
57
+ * @example require('@dotenvx/dotenvx').config({ overload: true })
58
+ * @alias overload
59
+ */
60
+ overload?: boolean;
61
+
62
+ /**
63
+ * @default false
64
+ * @alias override
65
+ */
66
+ override?: boolean;
67
+
68
+ /**
69
+ * Throw immediately if an error is encountered - like a missing .env file.
70
+ * @default false
71
+ * @example require('@dotenvx/dotenvx').config({ strict: true })
72
+ */
73
+ strict?: boolean;
74
+
75
+ /**
76
+ * Suppress specific errors like MISSING_ENV_FILE. The error keys can be found
77
+ * in src/lib/helpers/errors.js
78
+ * @default []
79
+ * @example require('@dotenvx/dotenvx').config({ ignore: ['MISSING_ENV_FILE'] })
80
+ */
81
+ ignore?: string[];
82
+
83
+ /**
84
+ * Specify an object to write your secrets to. Defaults to process.env environment variables.
85
+ *
86
+ * @default process.env
87
+ * @example const processEnv = {}; require('@dotenvx/dotenvx').config({ processEnv: processEnv })
88
+ */
89
+ processEnv?: DotenvPopulateInput;
90
+
91
+ /**
92
+ * Customize the path to your .env.keys file. This is useful with monorepos.
93
+ * @default []
94
+ * @example require('@dotenvx/dotenvx').config({ envKeysFile: '../../.env.keys'} })
95
+ */
96
+ envKeysFile?: string;
97
+
98
+ /**
99
+ * Pass the DOTENV_KEY directly to config options. Defaults to looking for process.env.DOTENV_KEY environment variable. Note this only applies to decrypting .env.vault files. If passed as null or undefined, or not passed at all, dotenv falls back to its traditional job of parsing a .env file.
100
+ *
101
+ * @default undefined
102
+ * @example require('@dotenvx/dotenvx').config({ DOTENV_KEY: 'dotenv://:key_1234…@dotenvx.com/vault/.env.vault?environment=production' })
103
+ */
104
+ DOTENV_KEY?: string;
105
+
106
+ /**
107
+ * Load a .env convention (available conventions: 'nextjs, flow')
108
+ */
109
+ convention?: string;
110
+
111
+ /**
112
+ * Turn on logging to help debug why certain keys or values are not being set as you expect.
113
+ *
114
+ * @default false
115
+ * @example require('@dotenvx/dotenvx').config({ debug: process.env.DEBUG })
116
+ */
117
+ debug?: boolean;
118
+
119
+ verbose?: boolean;
120
+
121
+ quiet?: boolean;
122
+
123
+ logLevel?:
124
+ | 'error'
125
+ | 'warn'
126
+ | 'success'
127
+ | 'successv'
128
+ | 'info'
129
+ | 'help'
130
+ | 'verbose'
131
+ | 'debug';
132
+ }
133
+
134
+ export interface DotenvConfigOutput {
135
+ error?: Error;
136
+ parsed?: DotenvParseOutput;
137
+ }
138
+
139
+ export interface DotenvPopulateInput {
140
+ [name: string]: string;
141
+ }
142
+
143
+ /**
144
+ * Loads `.env` file contents into process.env by default. If `DOTENV_KEY` is present, it smartly attempts to load encrypted `.env.vault` file contents into process.env.
145
+ *
146
+ * @see https://dotenvx.com/docs
147
+ *
148
+ * @param options - additional options. example: `{ path: './custom/path', encoding: 'latin1', debug: true, overload: false }`
149
+ * @returns an object with a `parsed` key if successful or `error` key if an error occurred. example: { parsed: { KEY: 'value' } }
150
+ *
151
+ */
152
+ export function config(options?: DotenvConfigOptions): DotenvConfigOutput;
@@ -0,0 +1,114 @@
1
+ const si = require('systeminformation')
2
+ const dotenvx = require('@dotenvx/dotenvx')
3
+
4
+ const Session = require('./../db/session')
5
+ const PostObserve = require('./api/postObserve')
6
+ const PostGet = require('./api/postGet')
7
+ const PostSet = require('./api/postSet')
8
+ const Keypair = require('./services/keypair')
9
+
10
+ const gitUrl = require('./helpers/gitUrl')
11
+ const gitBranch = require('./helpers/gitBranch')
12
+ const dotenvxProjectId = require('./helpers/dotenvxProjectId')
13
+
14
+ const observe = async function (encoded, options = {}) {
15
+ const sesh = new Session() // TODO: handle scenario where constructor fails
16
+
17
+ let hostname = options.hostname
18
+ if (!hostname) {
19
+ hostname = sesh.hostname()
20
+ }
21
+
22
+ let token = options.token
23
+ if (!token) {
24
+ token = sesh.token()
25
+ }
26
+
27
+ const _pwd = process.cwd()
28
+ const _dotenvxProjectId = options.dotenvxProjectId || dotenvxProjectId(_pwd, false)
29
+
30
+ const _gitUrl = gitUrl()
31
+ const _gitBranch = gitBranch()
32
+
33
+ const system = await si.system()
34
+ const _systemUuid = system.uuid
35
+
36
+ const osInfo = await si.osInfo()
37
+ const _osPlatform = osInfo.platform
38
+ const _osArch = osInfo.arch
39
+
40
+ const json = await new PostObserve(hostname, token, encoded, _pwd, _gitUrl, _gitBranch, _systemUuid, _osPlatform, _osArch, _dotenvxProjectId).run()
41
+
42
+ return json
43
+ }
44
+
45
+ const get = async function (uri, options = {}) {
46
+ const sesh = new Session() // TODO: handle scenario where constructor fails
47
+
48
+ let hostname = options.hostname
49
+ if (!hostname) {
50
+ hostname = sesh.hostname()
51
+ }
52
+
53
+ let token = options.token
54
+ if (!token) {
55
+ token = sesh.token()
56
+ }
57
+
58
+ const value = await new PostGet(hostname, token, uri).run()
59
+ return value
60
+ }
61
+
62
+ const set = async function (uri, value, options = {}) {
63
+ const sesh = new Session() // TODO: handle scenario where constructor fails
64
+
65
+ let hostname = options.hostname
66
+ if (!hostname) {
67
+ hostname = sesh.hostname()
68
+ }
69
+
70
+ let token = options.token
71
+ if (!token) {
72
+ token = sesh.token()
73
+ }
74
+
75
+ const devicePublicKey = sesh.devicePublicKey()
76
+
77
+ return await new PostSet(hostname, token, devicePublicKey, uri, value).run()
78
+ }
79
+
80
+ const keypair = async function (publicKey, options = {}) {
81
+ const sesh = new Session() // TODO: handle scenario where constructor fails
82
+
83
+ let hostname = options.hostname
84
+ if (!hostname) {
85
+ hostname = sesh.hostname()
86
+ }
87
+
88
+ let token = options.token
89
+ if (!token) {
90
+ token = sesh.token()
91
+ }
92
+
93
+ const devicePublicKey = sesh.devicePublicKey()
94
+
95
+ const json = await new Keypair(hostname, token, devicePublicKey, publicKey, options.team, options.envFile).run()
96
+
97
+ return {
98
+ publicKey: json.public_key,
99
+ privateKey: json.private_key
100
+ }
101
+ }
102
+
103
+ const config = function (options = {}) {
104
+ return dotenvx.config(options)
105
+ }
106
+
107
+ module.exports = {
108
+ observe,
109
+ get,
110
+ set,
111
+ keypair,
112
+ // dotenv proxies
113
+ config
114
+ }
@@ -0,0 +1,77 @@
1
+ const dotenvx = require('@dotenvx/dotenvx')
2
+ const prompts = require('../helpers/prompts')
3
+ const PostArmorDown = require('../api/postArmorDown')
4
+ const keyNamesForEnvFile = require('../helpers/keyNamesForEnvFile')
5
+ const upsertEnvKey = require('../helpers/upsertEnvKey')
6
+
7
+ function teamChoicesFromMeta (meta) {
8
+ return meta.organizations.map(org => ({
9
+ name: org.provider_slug,
10
+ value: org.provider_slug
11
+ }))
12
+ }
13
+
14
+ class ArmorDown {
15
+ constructor (hostname, token, devicePublicKey, envFile = '.env', team = undefined) {
16
+ this.hostname = hostname
17
+ this.token = token
18
+ this.devicePublicKey = devicePublicKey
19
+ this.envFile = envFile
20
+ this.team = team
21
+ }
22
+
23
+ async run () {
24
+ const hostname = this.hostname
25
+ const token = this.token
26
+ const devicePublicKey = this.devicePublicKey
27
+ const envFile = this.envFile
28
+ const team = this.team
29
+
30
+ const {
31
+ publicKeyName,
32
+ privateKeyName
33
+ } = keyNamesForEnvFile(envFile)
34
+
35
+ const publicKey = dotenvx.get(publicKeyName, { path: envFile, strict: true, ignore: ['MISSING_PRIVATE_KEY'], noOps: true })
36
+ let json
37
+
38
+ if (team) {
39
+ json = await new PostArmorDown(hostname, token, devicePublicKey, publicKey, team).run()
40
+ } else {
41
+ try {
42
+ json = await new PostArmorDown(hostname, token, devicePublicKey, publicKey, undefined).run()
43
+ } catch (error) {
44
+ if (error.code !== 'DOTENVX_TEAM_REQUIRED') {
45
+ throw error
46
+ }
47
+
48
+ const choices = teamChoicesFromMeta(error.meta)
49
+
50
+ let team = choices[0].value
51
+ if (choices.length > 1) {
52
+ team = await prompts.select({
53
+ message: 'Select team',
54
+ choices
55
+ }, {
56
+ input: process.stdin,
57
+ output: process.stderr
58
+ })
59
+ }
60
+
61
+ json = await new PostArmorDown(hostname, token, devicePublicKey, publicKey, team).run()
62
+ }
63
+ }
64
+
65
+ upsertEnvKey(privateKeyName, json.private_key)
66
+
67
+ return {
68
+ ...json,
69
+ changed: json.changed,
70
+ privateKeyName,
71
+ privateKeyValue: json.private_key,
72
+ publicKeyValue: publicKey
73
+ }
74
+ }
75
+ }
76
+
77
+ module.exports = ArmorDown
@@ -0,0 +1,54 @@
1
+ const dotenvx = require('@dotenvx/dotenvx')
2
+ const prompts = require('../helpers/prompts')
3
+ const PostArmorMove = require('../api/postArmorMove')
4
+ const GetAccount = require('../api/getAccount')
5
+ const keyNamesForEnvFile = require('../helpers/keyNamesForEnvFile')
6
+
7
+ class ArmorMove {
8
+ constructor (hostname, token, devicePublicKey, envFile = '.env') {
9
+ this.hostname = hostname
10
+ this.token = token
11
+ this.devicePublicKey = devicePublicKey
12
+ this.envFile = envFile
13
+
14
+ this.team = null // implement
15
+ }
16
+
17
+ async run () {
18
+ const hostname = this.hostname
19
+ const token = this.token
20
+ const devicePublicKey = this.devicePublicKey
21
+ const envFile = this.envFile
22
+ let team = this.team
23
+
24
+ const {
25
+ publicKeyName,
26
+ privateKeyName
27
+ } = keyNamesForEnvFile(envFile)
28
+ const publicKey = dotenvx.get(publicKeyName, { path: envFile, strict: true, ignore: ['MISSING_PRIVATE_KEY'], noOps: true })
29
+
30
+ const accountJson = await new GetAccount(hostname, token).run()
31
+ const choices = accountJson.organizations.map(o => ({
32
+ name: o.provider_slug,
33
+ value: o.provider_slug
34
+ }))
35
+ team = await prompts.select({
36
+ message: 'Select team',
37
+ choices
38
+ }, {
39
+ input: process.stdin,
40
+ output: process.stderr
41
+ })
42
+
43
+ const json = await new PostArmorMove(hostname, token, devicePublicKey, publicKey, team).run()
44
+
45
+ return {
46
+ ...json,
47
+ privateKeyName,
48
+ privateKeyValue: json.private_key,
49
+ publicKeyValue: publicKey
50
+ }
51
+ }
52
+ }
53
+
54
+ module.exports = ArmorMove
@@ -0,0 +1,77 @@
1
+ const dotenvx = require('@dotenvx/dotenvx')
2
+ const prompts = require('../helpers/prompts')
3
+ const PostArmorPull = require('../api/postArmorPull')
4
+ const upsertEnvKey = require('../helpers/upsertEnvKey')
5
+ const keyNamesForEnvFile = require('../helpers/keyNamesForEnvFile')
6
+
7
+ function teamChoicesFromMeta (meta) {
8
+ return meta.organizations.map(org => ({
9
+ name: org.provider_slug,
10
+ value: org.provider_slug
11
+ }))
12
+ }
13
+
14
+ class ArmorPull {
15
+ constructor (hostname, token, devicePublicKey, envFile = '.env', team = undefined) {
16
+ this.hostname = hostname
17
+ this.token = token
18
+ this.devicePublicKey = devicePublicKey
19
+ this.envFile = envFile
20
+ this.team = team
21
+ }
22
+
23
+ async run () {
24
+ const hostname = this.hostname
25
+ const token = this.token
26
+ const devicePublicKey = this.devicePublicKey
27
+ const envFile = this.envFile
28
+ const team = this.team
29
+
30
+ const {
31
+ publicKeyName,
32
+ privateKeyName
33
+ } = keyNamesForEnvFile(envFile)
34
+
35
+ const publicKey = dotenvx.get(publicKeyName, { path: envFile, strict: true, ignore: ['MISSING_PRIVATE_KEY'], noOps: true })
36
+ let json
37
+
38
+ if (team) {
39
+ json = await new PostArmorPull(hostname, token, devicePublicKey, publicKey, team).run()
40
+ } else {
41
+ try {
42
+ json = await new PostArmorPull(hostname, token, devicePublicKey, publicKey, undefined).run()
43
+ } catch (error) {
44
+ if (error.code !== 'DOTENVX_TEAM_REQUIRED') {
45
+ throw error
46
+ }
47
+
48
+ const choices = teamChoicesFromMeta(error.meta)
49
+
50
+ let team = choices[0].value
51
+ if (choices.length > 1) {
52
+ team = await prompts.select({
53
+ message: 'Select team',
54
+ choices
55
+ }, {
56
+ input: process.stdin,
57
+ output: process.stderr
58
+ })
59
+ }
60
+
61
+ json = await new PostArmorPull(hostname, token, devicePublicKey, publicKey, team).run()
62
+ }
63
+ }
64
+
65
+ const result = upsertEnvKey(privateKeyName, json.private_key)
66
+
67
+ return {
68
+ ...json,
69
+ changed: result.changed,
70
+ privateKeyName,
71
+ privateKeyValue: json.private_key,
72
+ publicKeyValue: publicKey
73
+ }
74
+ }
75
+ }
76
+
77
+ module.exports = ArmorPull
@@ -0,0 +1,82 @@
1
+ const dotenvx = require('@dotenvx/dotenvx')
2
+ const { PrivateKey } = require('eciesjs')
3
+ const prompts = require('../helpers/prompts')
4
+ const PostArmorPush = require('../api/postArmorPush')
5
+ const keyNamesForEnvFile = require('../helpers/keyNamesForEnvFile')
6
+
7
+ function teamChoicesFromMeta (meta) {
8
+ return meta.organizations.map(org => ({
9
+ name: org.provider_slug,
10
+ value: org.provider_slug
11
+ }))
12
+ }
13
+
14
+ function publicKeyFromPrivateKey (privateKey) {
15
+ try {
16
+ return new PrivateKey(Buffer.from(privateKey, 'hex')).publicKey.toHex()
17
+ } catch {
18
+ return ''
19
+ }
20
+ }
21
+
22
+ class ArmorPush {
23
+ constructor (hostname, token, devicePublicKey, envFile = '.env', team = undefined) {
24
+ this.hostname = hostname
25
+ this.token = token
26
+ this.devicePublicKey = devicePublicKey
27
+ this.envFile = envFile
28
+ this.team = team
29
+ }
30
+
31
+ async run () {
32
+ const hostname = this.hostname
33
+ const token = this.token
34
+ const devicePublicKey = this.devicePublicKey
35
+ const envFile = this.envFile
36
+ const team = this.team
37
+
38
+ const { privateKeyName } = keyNamesForEnvFile(envFile)
39
+
40
+ const privateKey = dotenvx.get(privateKeyName, { path: '.env.keys', strict: true, noOps: true })
41
+ const publicKey = publicKeyFromPrivateKey(privateKey)
42
+
43
+ let json
44
+
45
+ if (team) {
46
+ json = await new PostArmorPush(hostname, token, devicePublicKey, privateKey, team).run()
47
+ } else {
48
+ try {
49
+ json = await new PostArmorPush(hostname, token, devicePublicKey, privateKey, undefined).run()
50
+ } catch (error) {
51
+ if (error.code !== 'DOTENVX_TEAM_REQUIRED') {
52
+ throw error
53
+ }
54
+
55
+ const choices = teamChoicesFromMeta(error.meta)
56
+
57
+ let team = choices[0].value
58
+ if (choices.length > 1) {
59
+ team = await prompts.select({
60
+ message: 'Select team',
61
+ choices
62
+ }, {
63
+ input: process.stdin,
64
+ output: process.stderr
65
+ })
66
+ }
67
+
68
+ json = await new PostArmorPush(hostname, token, devicePublicKey, privateKey, team).run()
69
+ }
70
+ }
71
+
72
+ return {
73
+ ...json,
74
+ changed: json.changed,
75
+ privateKeyName,
76
+ privateKeyValue: json.private_key,
77
+ publicKeyValue: publicKey
78
+ }
79
+ }
80
+ }
81
+
82
+ module.exports = ArmorPush