@dotenvx/dotenvx-ops 0.15.6
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.
- package/CHANGELOG.md +161 -0
- package/LICENSE +71 -0
- package/README.md +9 -0
- package/package.json +66 -0
- package/src/cli/actions/login.js +118 -0
- package/src/cli/actions/logout.js +42 -0
- package/src/cli/actions/observe.js +33 -0
- package/src/cli/actions/settings/device.js +24 -0
- package/src/cli/actions/settings/hostname.js +20 -0
- package/src/cli/actions/settings/token.js +24 -0
- package/src/cli/actions/settings/username.js +22 -0
- package/src/cli/actions/status.js +13 -0
- package/src/cli/actions/sync.js +39 -0
- package/src/cli/commands/settings.js +39 -0
- package/src/cli/dotenvx-ops.js +93 -0
- package/src/db/device.js +73 -0
- package/src/db/session.js +119 -0
- package/src/lib/api/postLogout.js +34 -0
- package/src/lib/api/postOauthDeviceCode.js +42 -0
- package/src/lib/api/postOauthToken.js +38 -0
- package/src/lib/api/postObserve.js +59 -0
- package/src/lib/api/postSync.js +65 -0
- package/src/lib/helpers/buildApiError.js +13 -0
- package/src/lib/helpers/buildOauthError.js +13 -0
- package/src/lib/helpers/clipboardy/fallbacks/linux/xsel +0 -0
- package/src/lib/helpers/clipboardy/fallbacks/windows/clipboard_i686.exe +0 -0
- package/src/lib/helpers/clipboardy/fallbacks/windows/clipboard_x86_64.exe +0 -0
- package/src/lib/helpers/clipboardy/linux.js +57 -0
- package/src/lib/helpers/clipboardy/macos.js +14 -0
- package/src/lib/helpers/clipboardy/termux.js +41 -0
- package/src/lib/helpers/clipboardy/windows.js +16 -0
- package/src/lib/helpers/clipboardy.js +51 -0
- package/src/lib/helpers/confirm.js +17 -0
- package/src/lib/helpers/createSpinner.js +101 -0
- package/src/lib/helpers/decryptValue.js +10 -0
- package/src/lib/helpers/encryptValue.js +9 -0
- package/src/lib/helpers/errors.js +30 -0
- package/src/lib/helpers/formatCode.js +11 -0
- package/src/lib/helpers/gitBranch.js +13 -0
- package/src/lib/helpers/gitUrl.js +13 -0
- package/src/lib/helpers/http.js +17 -0
- package/src/lib/helpers/jsonToEnv.js +7 -0
- package/src/lib/helpers/mask.js +12 -0
- package/src/lib/helpers/packageJson.js +3 -0
- package/src/lib/helpers/smartMask.js +11 -0
- package/src/lib/helpers/truncate.js +10 -0
- package/src/lib/main.d.ts +129 -0
- package/src/lib/main.js +47 -0
- package/src/lib/services/logout.js +28 -0
- package/src/lib/services/status.js +11 -0
- package/src/lib/services/sync.js +94 -0
|
@@ -0,0 +1,93 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
|
|
3
|
+
/* c8 ignore start */
|
|
4
|
+
const { Command } = require('commander')
|
|
5
|
+
const program = new Command()
|
|
6
|
+
|
|
7
|
+
const { setLogLevel } = require('@dotenvx/dotenvx')
|
|
8
|
+
|
|
9
|
+
const packageJson = require('./../lib/helpers/packageJson')
|
|
10
|
+
const Session = require('./../db/session')
|
|
11
|
+
const sesh = new Session()
|
|
12
|
+
|
|
13
|
+
// global log levels
|
|
14
|
+
program
|
|
15
|
+
.usage('login')
|
|
16
|
+
.option('-l, --log-level <level>', 'set log level', 'info')
|
|
17
|
+
.option('-q, --quiet', 'sets log level to error')
|
|
18
|
+
.option('-v, --verbose', 'sets log level to verbose')
|
|
19
|
+
.option('-d, --debug', 'sets log level to debug')
|
|
20
|
+
.hook('preAction', (thisCommand, actionCommand) => {
|
|
21
|
+
const options = thisCommand.opts()
|
|
22
|
+
|
|
23
|
+
setLogLevel(options)
|
|
24
|
+
})
|
|
25
|
+
|
|
26
|
+
// cli
|
|
27
|
+
program
|
|
28
|
+
.name('dotenvx-ops')
|
|
29
|
+
.description(packageJson.description)
|
|
30
|
+
.version(packageJson.version)
|
|
31
|
+
.allowUnknownOption()
|
|
32
|
+
|
|
33
|
+
// dotenvx-ops observe base64String
|
|
34
|
+
const observeAction = require('./actions/observe')
|
|
35
|
+
program.command('observe')
|
|
36
|
+
.usage('<BASE64> [options]')
|
|
37
|
+
.description('[INTERNAL] observe')
|
|
38
|
+
.allowUnknownOption()
|
|
39
|
+
.argument('BASE64', 'BASE64')
|
|
40
|
+
.option('--hostname <url>', 'set hostname', sesh.hostname())
|
|
41
|
+
.option('--token <token>', 'set token')
|
|
42
|
+
.action(function (...args) {
|
|
43
|
+
observeAction.apply(this, args)
|
|
44
|
+
})
|
|
45
|
+
|
|
46
|
+
// dotenvx-ops sync
|
|
47
|
+
const syncAction = require('./actions/sync')
|
|
48
|
+
program
|
|
49
|
+
.command('sync')
|
|
50
|
+
.description('sync .env file(s)')
|
|
51
|
+
.option('-h, --hostname <url>', 'set hostname', sesh.hostname())
|
|
52
|
+
.action(syncAction)
|
|
53
|
+
|
|
54
|
+
// dotenvx-ops login
|
|
55
|
+
const loginAction = require('./actions/login')
|
|
56
|
+
program
|
|
57
|
+
.command('login')
|
|
58
|
+
.description('log in')
|
|
59
|
+
.option('--hostname <url>', 'set hostname', sesh.hostname())
|
|
60
|
+
.action(loginAction)
|
|
61
|
+
|
|
62
|
+
// dotenvx-ops logout
|
|
63
|
+
const logoutAction = require('./actions/logout')
|
|
64
|
+
program
|
|
65
|
+
.command('logout')
|
|
66
|
+
.description('log out')
|
|
67
|
+
.option('--hostname <url>', 'set hostname', sesh.hostname())
|
|
68
|
+
.action(logoutAction)
|
|
69
|
+
|
|
70
|
+
// dotenvx-ops status
|
|
71
|
+
const statusAction = require('./actions/status')
|
|
72
|
+
program
|
|
73
|
+
.command('status')
|
|
74
|
+
.description('status')
|
|
75
|
+
.action(statusAction)
|
|
76
|
+
|
|
77
|
+
// dotenvx-ops settings
|
|
78
|
+
program.addCommand(require('./commands/settings'))
|
|
79
|
+
|
|
80
|
+
// monkey-patch help output
|
|
81
|
+
program.helpInformation = function () {
|
|
82
|
+
const originalHelp = Command.prototype.helpInformation.call(this)
|
|
83
|
+
const lines = originalHelp.split('\n')
|
|
84
|
+
|
|
85
|
+
const filteredLines = lines.filter(line =>
|
|
86
|
+
!line.includes('INTERNAL') // hide observe command
|
|
87
|
+
)
|
|
88
|
+
|
|
89
|
+
return filteredLines.join('\n')
|
|
90
|
+
}
|
|
91
|
+
|
|
92
|
+
/* c8 ignore stop */
|
|
93
|
+
program.parse(process.argv)
|
package/src/db/device.js
ADDED
|
@@ -0,0 +1,73 @@
|
|
|
1
|
+
const Conf = require('conf')
|
|
2
|
+
const { PrivateKey } = require('eciesjs')
|
|
3
|
+
|
|
4
|
+
const encryptValue = require('./../lib/helpers/encryptValue')
|
|
5
|
+
const decryptValue = require('./../lib/helpers/decryptValue')
|
|
6
|
+
|
|
7
|
+
class Device {
|
|
8
|
+
constructor () {
|
|
9
|
+
this.store = new Conf({
|
|
10
|
+
cwd: process.env.DOTENVX_CONFIG || undefined,
|
|
11
|
+
projectName: 'dotenvx',
|
|
12
|
+
configName: '.device-key',
|
|
13
|
+
projectSuffix: '',
|
|
14
|
+
fileExtension: '',
|
|
15
|
+
encryptionKey: 'dotenvxpro dotenvxpro dotenvxpro' // backwards compatible
|
|
16
|
+
})
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
touch () {
|
|
20
|
+
const _privateKey = this.privateKey()
|
|
21
|
+
const _publicKey = this.publicKey()
|
|
22
|
+
|
|
23
|
+
return {
|
|
24
|
+
privateKey: _privateKey,
|
|
25
|
+
publicKey: _publicKey
|
|
26
|
+
}
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
configPath () {
|
|
30
|
+
return this.store.path
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
privateKey () {
|
|
34
|
+
const currentPrivateKey = this.store.get('private_key/1')
|
|
35
|
+
if (currentPrivateKey && currentPrivateKey.length > 0) {
|
|
36
|
+
this.store.set('private_key/1', currentPrivateKey)
|
|
37
|
+
|
|
38
|
+
return currentPrivateKey
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
// generate privateKey for the first time
|
|
42
|
+
const kp = new PrivateKey()
|
|
43
|
+
const _privateKey = kp.secret.toString('hex')
|
|
44
|
+
|
|
45
|
+
this.store.set('private_key/1', _privateKey)
|
|
46
|
+
|
|
47
|
+
return _privateKey
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
publicKey () {
|
|
51
|
+
// must have private key to try and get public key
|
|
52
|
+
const privateKeyHex = this.privateKey()
|
|
53
|
+
if (!privateKeyHex || privateKeyHex.length < 1) {
|
|
54
|
+
return ''
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
// create keyPair object from hex string
|
|
58
|
+
const _privateKey = new PrivateKey(Buffer.from(privateKeyHex, 'hex'))
|
|
59
|
+
|
|
60
|
+
// compute publicKey from privateKey
|
|
61
|
+
return _privateKey.publicKey.toHex()
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
encrypt (value) {
|
|
65
|
+
return encryptValue(value, this.publicKey())
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
decrypt (value) {
|
|
69
|
+
return decryptValue(value, this.privateKey())
|
|
70
|
+
}
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
module.exports = Device
|
|
@@ -0,0 +1,119 @@
|
|
|
1
|
+
const Conf = require('conf')
|
|
2
|
+
const dotenv = require('dotenv')
|
|
3
|
+
const si = require('systeminformation')
|
|
4
|
+
|
|
5
|
+
const Device = require('./device')
|
|
6
|
+
const jsonToEnv = require('./../lib/helpers/jsonToEnv')
|
|
7
|
+
|
|
8
|
+
class Session {
|
|
9
|
+
constructor () {
|
|
10
|
+
this.store = new Conf({
|
|
11
|
+
cwd: process.env.DOTENVX_CONFIG || undefined,
|
|
12
|
+
projectName: 'dotenvx',
|
|
13
|
+
configName: '.env',
|
|
14
|
+
projectSuffix: '',
|
|
15
|
+
fileExtension: '',
|
|
16
|
+
serialize: function (json) {
|
|
17
|
+
return jsonToEnv(json)
|
|
18
|
+
},
|
|
19
|
+
// Convert .env format to an object
|
|
20
|
+
deserialize: function (env) {
|
|
21
|
+
return dotenv.parse(env)
|
|
22
|
+
}
|
|
23
|
+
})
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
status () {
|
|
27
|
+
// if logged in
|
|
28
|
+
if (this.username() && this.token()) {
|
|
29
|
+
return 'on'
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
return 'off'
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
//
|
|
36
|
+
// Get
|
|
37
|
+
//
|
|
38
|
+
hostname () {
|
|
39
|
+
return this.store.get('DOTENVX_OPS_HOSTNAME') || this.store.get('DOTENVX_RADAR_HOSTNAME') || 'https://ops.dotenvx.com'
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
username () {
|
|
43
|
+
return this.store.get('DOTENVX_OPS_USERNAME') || this.store.get('DOTENVX_RADAR_USERNAME') || undefined
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
token () {
|
|
47
|
+
return this.store.get('DOTENVX_OPS_TOKEN') || this.store.get('DOTENVX_RADAR_TOKEN') || undefined
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
devicePublicKey () {
|
|
51
|
+
return new Device().publicKey()
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
async systemInformation () {
|
|
55
|
+
const system = await si.system()
|
|
56
|
+
const osInfo = await si.osInfo()
|
|
57
|
+
|
|
58
|
+
return {
|
|
59
|
+
system_uuid: system.uuid,
|
|
60
|
+
os_platform: osInfo.platform,
|
|
61
|
+
os_arch: osInfo.arch
|
|
62
|
+
}
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
//
|
|
66
|
+
// Set/Delete
|
|
67
|
+
//
|
|
68
|
+
login (hostname, id, username, accessToken) {
|
|
69
|
+
if (!hostname) {
|
|
70
|
+
throw new Error('DOTENVX_OPS_HOSTNAME not set. Run [dotenvx-ops login]')
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
if (!id) {
|
|
74
|
+
throw new Error('DOTENVX_OPS_USER not set. Run [dotenvx-ops login]')
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
if (!username) {
|
|
78
|
+
throw new Error('DOTENVX_OPS_USERNAME not set. Run [dotenvx-ops login]')
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
if (!accessToken) {
|
|
82
|
+
throw new Error('DOTENVX_OPS_TOKEN not set. Run [dotenvx-ops login]')
|
|
83
|
+
}
|
|
84
|
+
|
|
85
|
+
this.store.set('DOTENVX_OPS_USER', id)
|
|
86
|
+
this.store.set('DOTENVX_OPS_USERNAME', username)
|
|
87
|
+
this.store.set('DOTENVX_OPS_TOKEN', accessToken)
|
|
88
|
+
this.store.set('DOTENVX_OPS_HOSTNAME', hostname)
|
|
89
|
+
|
|
90
|
+
return accessToken
|
|
91
|
+
}
|
|
92
|
+
|
|
93
|
+
logout (hostname, id, accessToken) {
|
|
94
|
+
if (!hostname) {
|
|
95
|
+
throw new Error('DOTENVX_OPS_HOSTNAME not set. Run [dotenvx-ops login]')
|
|
96
|
+
}
|
|
97
|
+
|
|
98
|
+
if (!id) {
|
|
99
|
+
throw new Error('DOTENVX_OPS_USER not set. Run [dotenvx-ops login]')
|
|
100
|
+
}
|
|
101
|
+
|
|
102
|
+
if (!accessToken) {
|
|
103
|
+
throw new Error('DOTENVX_OPS_TOKEN not set. Run [dotenvx-ops login]')
|
|
104
|
+
}
|
|
105
|
+
|
|
106
|
+
this.store.delete('DOTENVX_OPS_USER')
|
|
107
|
+
this.store.delete('DOTENVX_OPS_USERNAME')
|
|
108
|
+
this.store.delete('DOTENVX_OPS_TOKEN')
|
|
109
|
+
this.store.delete('DOTENVX_OPS_HOSTNAME')
|
|
110
|
+
this.store.delete('DOTENVX_RADAR_USER')
|
|
111
|
+
this.store.delete('DOTENVX_RADAR_USERNAME')
|
|
112
|
+
this.store.delete('DOTENVX_RADAR_TOKEN')
|
|
113
|
+
this.store.delete('DOTENVX_RADAR_HOSTNAME')
|
|
114
|
+
|
|
115
|
+
return true
|
|
116
|
+
}
|
|
117
|
+
}
|
|
118
|
+
|
|
119
|
+
module.exports = Session
|
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
const { http } = require('../../lib/helpers/http')
|
|
2
|
+
|
|
3
|
+
const buildApiError = require('../../lib/helpers/buildApiError')
|
|
4
|
+
|
|
5
|
+
class PostLogout {
|
|
6
|
+
constructor (hostname, token) {
|
|
7
|
+
this.hostname = hostname
|
|
8
|
+
this.token = token
|
|
9
|
+
}
|
|
10
|
+
|
|
11
|
+
async run () {
|
|
12
|
+
const token = this.token
|
|
13
|
+
const url = `${this.hostname}/api/logout`
|
|
14
|
+
|
|
15
|
+
const resp = await http(url, {
|
|
16
|
+
method: 'POST',
|
|
17
|
+
headers: {
|
|
18
|
+
Authorization: `Bearer ${token}`,
|
|
19
|
+
'Content-Type': 'application/json'
|
|
20
|
+
},
|
|
21
|
+
body: JSON.stringify({})
|
|
22
|
+
})
|
|
23
|
+
|
|
24
|
+
const json = await resp.body.json()
|
|
25
|
+
|
|
26
|
+
if (resp.statusCode >= 400) {
|
|
27
|
+
throw buildApiError(resp.statusCode, json)
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
return json
|
|
31
|
+
}
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
module.exports = PostLogout
|
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
const { http } = require('../../lib/helpers/http')
|
|
2
|
+
|
|
3
|
+
// const Device = require('../../db/device')
|
|
4
|
+
const buildOauthError = require('../../lib/helpers/buildOauthError')
|
|
5
|
+
|
|
6
|
+
const OAUTH_CLIENT_ID = 'oac_dotenvxcli'
|
|
7
|
+
|
|
8
|
+
class PostOauthDeviceCode {
|
|
9
|
+
constructor (hostname, devicePublicKey, systemInformation) {
|
|
10
|
+
this.hostname = hostname
|
|
11
|
+
this.devicePublicKey = devicePublicKey
|
|
12
|
+
this.systemInformation = systemInformation
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
async run () {
|
|
16
|
+
const url = `${this.hostname}/oauth/device/code`
|
|
17
|
+
const devicePublicKey = this.devicePublicKey
|
|
18
|
+
const systemInformation = this.systemInformation
|
|
19
|
+
|
|
20
|
+
const resp = await http(url, {
|
|
21
|
+
method: 'POST',
|
|
22
|
+
headers: {
|
|
23
|
+
'Content-Type': 'application/json'
|
|
24
|
+
},
|
|
25
|
+
body: JSON.stringify({
|
|
26
|
+
client_id: OAUTH_CLIENT_ID,
|
|
27
|
+
device_public_key: devicePublicKey,
|
|
28
|
+
system_information: systemInformation
|
|
29
|
+
})
|
|
30
|
+
})
|
|
31
|
+
|
|
32
|
+
const json = await resp.body.json()
|
|
33
|
+
|
|
34
|
+
if (resp.statusCode >= 400) {
|
|
35
|
+
throw buildOauthError(resp.statusCode, json)
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
return json
|
|
39
|
+
}
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
module.exports = PostOauthDeviceCode
|
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
const { http } = require('../../lib/helpers/http')
|
|
2
|
+
|
|
3
|
+
const buildOauthError = require('../../lib/helpers/buildOauthError')
|
|
4
|
+
|
|
5
|
+
const OAUTH_CLIENT_ID = 'oac_dotenvxcli'
|
|
6
|
+
|
|
7
|
+
class PostOauthToken {
|
|
8
|
+
constructor (hostname, deviceCode) {
|
|
9
|
+
this.hostname = hostname
|
|
10
|
+
this.deviceCode = deviceCode
|
|
11
|
+
}
|
|
12
|
+
|
|
13
|
+
async run () {
|
|
14
|
+
const url = `${this.hostname}/oauth/token`
|
|
15
|
+
|
|
16
|
+
const resp = await http(url, {
|
|
17
|
+
method: 'POST',
|
|
18
|
+
headers: {
|
|
19
|
+
'Content-Type': 'application/json'
|
|
20
|
+
},
|
|
21
|
+
body: JSON.stringify({
|
|
22
|
+
client_id: OAUTH_CLIENT_ID,
|
|
23
|
+
device_code: this.deviceCode,
|
|
24
|
+
grant_type: 'urn:ietf:params:oauth:grant-type:device_code'
|
|
25
|
+
})
|
|
26
|
+
})
|
|
27
|
+
|
|
28
|
+
const json = await resp.body.json()
|
|
29
|
+
|
|
30
|
+
if (resp.statusCode >= 400) {
|
|
31
|
+
throw buildOauthError(resp.statusCode, json)
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
return json
|
|
35
|
+
}
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
module.exports = PostOauthToken
|
|
@@ -0,0 +1,59 @@
|
|
|
1
|
+
const { http } = require('../../lib/helpers/http')
|
|
2
|
+
const buildApiError = require('../../lib/helpers/buildApiError')
|
|
3
|
+
const packageJson = require('../../lib/helpers/packageJson')
|
|
4
|
+
|
|
5
|
+
class PostObserve {
|
|
6
|
+
constructor (hostname, token, encoded, pwd = null, gitUrl = null, gitBranch = null, systemUuid = null, osPlatform = null, osArch = null) {
|
|
7
|
+
this.hostname = hostname || 'https://ops.dotenvx.com'
|
|
8
|
+
this.token = token
|
|
9
|
+
this.encoded = encoded
|
|
10
|
+
this.pwd = pwd
|
|
11
|
+
this.gitUrl = gitUrl
|
|
12
|
+
this.gitBranch = gitBranch
|
|
13
|
+
this.systemUuid = systemUuid
|
|
14
|
+
this.osPlatform = osPlatform
|
|
15
|
+
this.osArch = osArch
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
async run () {
|
|
19
|
+
const token = this.token
|
|
20
|
+
const url = `${this.hostname}/api/observe`
|
|
21
|
+
const encoded = this.encoded
|
|
22
|
+
const observedAt = new Date().toISOString()
|
|
23
|
+
const pwd = this.pwd
|
|
24
|
+
const gitUrl = this.gitUrl
|
|
25
|
+
const gitBranch = this.gitBranch
|
|
26
|
+
const systemUuid = this.systemUuid
|
|
27
|
+
const osPlatform = this.osPlatform
|
|
28
|
+
const osArch = this.osArch
|
|
29
|
+
|
|
30
|
+
const resp = await http(url, {
|
|
31
|
+
method: 'POST',
|
|
32
|
+
headers: {
|
|
33
|
+
Authorization: `Bearer ${token}`,
|
|
34
|
+
'Content-Type': 'application/json'
|
|
35
|
+
},
|
|
36
|
+
body: JSON.stringify({
|
|
37
|
+
encoded,
|
|
38
|
+
observed_at: observedAt,
|
|
39
|
+
pwd,
|
|
40
|
+
git_url: gitUrl,
|
|
41
|
+
git_branch: gitBranch,
|
|
42
|
+
system_uuid: systemUuid,
|
|
43
|
+
os_platform: osPlatform,
|
|
44
|
+
os_arch: osArch,
|
|
45
|
+
cli_version: packageJson.version
|
|
46
|
+
})
|
|
47
|
+
})
|
|
48
|
+
|
|
49
|
+
const json = await resp.body.json()
|
|
50
|
+
|
|
51
|
+
if (resp.statusCode >= 400) {
|
|
52
|
+
throw buildApiError(resp.statusCode, json)
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
return json
|
|
56
|
+
}
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
module.exports = PostObserve
|
|
@@ -0,0 +1,65 @@
|
|
|
1
|
+
const { http } = require('../../lib/helpers/http')
|
|
2
|
+
const buildApiError = require('../../lib/helpers/buildApiError')
|
|
3
|
+
const packageJson = require('../../lib/helpers/packageJson')
|
|
4
|
+
|
|
5
|
+
class PostSync {
|
|
6
|
+
constructor (hostname, token, devicePublicKey, encoded, dotenvxProjectId, pwd = null, gitUrl = null, gitBranch = null, systemUuid = null, osPlatform = null, osArch = null) {
|
|
7
|
+
this.hostname = hostname || 'https://ops.dotenvx.com'
|
|
8
|
+
this.token = token
|
|
9
|
+
this.devicePublicKey = devicePublicKey
|
|
10
|
+
this.encoded = encoded
|
|
11
|
+
this.dotenvxProjectId = dotenvxProjectId
|
|
12
|
+
this.pwd = pwd
|
|
13
|
+
this.gitUrl = gitUrl
|
|
14
|
+
this.gitBranch = gitBranch
|
|
15
|
+
this.systemUuid = systemUuid
|
|
16
|
+
this.osPlatform = osPlatform
|
|
17
|
+
this.osArch = osArch
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
async run () {
|
|
21
|
+
const token = this.token
|
|
22
|
+
const devicePublicKey = this.devicePublicKey
|
|
23
|
+
const url = `${this.hostname}/api/sync`
|
|
24
|
+
const encoded = this.encoded
|
|
25
|
+
const dotenvxProjectId = this.dotenvxProjectId
|
|
26
|
+
const syncedAt = new Date().toISOString()
|
|
27
|
+
const pwd = this.pwd
|
|
28
|
+
const gitUrl = this.gitUrl
|
|
29
|
+
const gitBranch = this.gitBranch
|
|
30
|
+
const systemUuid = this.systemUuid
|
|
31
|
+
const osPlatform = this.osPlatform
|
|
32
|
+
const osArch = this.osArch
|
|
33
|
+
|
|
34
|
+
const resp = await http(url, {
|
|
35
|
+
method: 'POST',
|
|
36
|
+
headers: {
|
|
37
|
+
Authorization: `Bearer ${token}`,
|
|
38
|
+
'Content-Type': 'application/json'
|
|
39
|
+
},
|
|
40
|
+
body: JSON.stringify({
|
|
41
|
+
device_public_key: devicePublicKey,
|
|
42
|
+
encoded,
|
|
43
|
+
dotenvx_project_id: dotenvxProjectId,
|
|
44
|
+
synced_at: syncedAt,
|
|
45
|
+
pwd,
|
|
46
|
+
git_url: gitUrl,
|
|
47
|
+
git_branch: gitBranch,
|
|
48
|
+
system_uuid: systemUuid,
|
|
49
|
+
os_platform: osPlatform,
|
|
50
|
+
os_arch: osArch,
|
|
51
|
+
cli_version: packageJson.version
|
|
52
|
+
})
|
|
53
|
+
})
|
|
54
|
+
|
|
55
|
+
const json = await resp.body.json()
|
|
56
|
+
|
|
57
|
+
if (resp.statusCode >= 400) {
|
|
58
|
+
throw buildApiError(resp.statusCode, json)
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
return json
|
|
62
|
+
}
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
module.exports = PostSync
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
function buildApiError (statusCode, json) {
|
|
2
|
+
const code = json.error.code || statusCode.toString()
|
|
3
|
+
const message = `[${code}] ${json.error.message}`
|
|
4
|
+
const help = `[${code}] ${json.error.help || JSON.stringify(json)}`
|
|
5
|
+
|
|
6
|
+
const error = new Error(message)
|
|
7
|
+
error.code = code
|
|
8
|
+
error.help = help
|
|
9
|
+
|
|
10
|
+
return error
|
|
11
|
+
}
|
|
12
|
+
|
|
13
|
+
module.exports = buildApiError
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
function buildOauthError (statusCode, json) {
|
|
2
|
+
const code = json.error // TAKE CAUTION CHANGING THIS. the polling for an oauth token relies on it
|
|
3
|
+
const message = `[${code}] ${json.error_description}`
|
|
4
|
+
const help = `[${code}] ${JSON.stringify(json)}`
|
|
5
|
+
|
|
6
|
+
const error = new Error(message)
|
|
7
|
+
error.code = code
|
|
8
|
+
error.help = help
|
|
9
|
+
|
|
10
|
+
return error
|
|
11
|
+
}
|
|
12
|
+
|
|
13
|
+
module.exports = buildOauthError
|
|
Binary file
|
|
Binary file
|
|
@@ -0,0 +1,57 @@
|
|
|
1
|
+
'use strict'
|
|
2
|
+
const path = require('path')
|
|
3
|
+
const execa = require('execa')
|
|
4
|
+
|
|
5
|
+
const xsel = 'xsel'
|
|
6
|
+
const xselFallback = path.join(__dirname, './fallbacks/linux/xsel')
|
|
7
|
+
|
|
8
|
+
const copyArguments = ['--clipboard', '--input']
|
|
9
|
+
const pasteArguments = ['--clipboard', '--output']
|
|
10
|
+
|
|
11
|
+
const makeError = (xselError, fallbackError) => {
|
|
12
|
+
let error
|
|
13
|
+
if (xselError.code === 'ENOENT') {
|
|
14
|
+
error = new Error('Couldn\'t find the `xsel` binary and fallback didn\'t work. On Debian/Ubuntu you can install xsel with: sudo apt install xsel')
|
|
15
|
+
} else {
|
|
16
|
+
error = new Error('Both xsel and fallback failed')
|
|
17
|
+
error.xselError = xselError
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
error.fallbackError = fallbackError
|
|
21
|
+
return error
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
const xselWithFallback = async (argumentList, options) => {
|
|
25
|
+
try {
|
|
26
|
+
return await execa.stdout(xsel, argumentList, options)
|
|
27
|
+
} catch (xselError) {
|
|
28
|
+
try {
|
|
29
|
+
return await execa.stdout(xselFallback, argumentList, options)
|
|
30
|
+
} catch (fallbackError) {
|
|
31
|
+
throw makeError(xselError, fallbackError)
|
|
32
|
+
}
|
|
33
|
+
}
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
const xselWithFallbackSync = (argumentList, options) => {
|
|
37
|
+
try {
|
|
38
|
+
return execa.sync(xsel, argumentList, options)
|
|
39
|
+
} catch (xselError) {
|
|
40
|
+
try {
|
|
41
|
+
return execa.sync(xselFallback, argumentList, options)
|
|
42
|
+
} catch (fallbackError) {
|
|
43
|
+
throw makeError(xselError, fallbackError)
|
|
44
|
+
}
|
|
45
|
+
}
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
module.exports = {
|
|
49
|
+
copy: async options => {
|
|
50
|
+
await xselWithFallback(copyArguments, options)
|
|
51
|
+
},
|
|
52
|
+
copySync: options => {
|
|
53
|
+
xselWithFallbackSync(copyArguments, options)
|
|
54
|
+
},
|
|
55
|
+
paste: options => xselWithFallback(pasteArguments, options),
|
|
56
|
+
pasteSync: options => xselWithFallbackSync(pasteArguments, options)
|
|
57
|
+
}
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
'use strict'
|
|
2
|
+
const execa = require('execa')
|
|
3
|
+
|
|
4
|
+
const env = {
|
|
5
|
+
...process.env,
|
|
6
|
+
LC_CTYPE: 'UTF-8'
|
|
7
|
+
}
|
|
8
|
+
|
|
9
|
+
module.exports = {
|
|
10
|
+
copy: async options => execa('pbcopy', { ...options, env }),
|
|
11
|
+
paste: async options => execa.stdout('pbpaste', { ...options, env }),
|
|
12
|
+
copySync: options => execa.sync('pbcopy', { ...options, env }),
|
|
13
|
+
pasteSync: options => execa.sync('pbpaste', { ...options, env })
|
|
14
|
+
}
|
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
'use strict'
|
|
2
|
+
const execa = require('execa')
|
|
3
|
+
|
|
4
|
+
const handler = error => {
|
|
5
|
+
if (error.code === 'ENOENT') {
|
|
6
|
+
throw new Error('Couldn\'t find the termux-api scripts. You can install them with: apt install termux-api')
|
|
7
|
+
}
|
|
8
|
+
|
|
9
|
+
throw error
|
|
10
|
+
}
|
|
11
|
+
|
|
12
|
+
module.exports = {
|
|
13
|
+
copy: async options => {
|
|
14
|
+
try {
|
|
15
|
+
await execa('termux-clipboard-set', options)
|
|
16
|
+
} catch (error) {
|
|
17
|
+
handler(error)
|
|
18
|
+
}
|
|
19
|
+
},
|
|
20
|
+
paste: async options => {
|
|
21
|
+
try {
|
|
22
|
+
return await execa.stdout('termux-clipboard-get', options)
|
|
23
|
+
} catch (error) {
|
|
24
|
+
handler(error)
|
|
25
|
+
}
|
|
26
|
+
},
|
|
27
|
+
copySync: options => {
|
|
28
|
+
try {
|
|
29
|
+
execa.sync('termux-clipboard-set', options)
|
|
30
|
+
} catch (error) {
|
|
31
|
+
handler(error)
|
|
32
|
+
}
|
|
33
|
+
},
|
|
34
|
+
pasteSync: options => {
|
|
35
|
+
try {
|
|
36
|
+
return execa.sync('termux-clipboard-get', options)
|
|
37
|
+
} catch (error) {
|
|
38
|
+
handler(error)
|
|
39
|
+
}
|
|
40
|
+
}
|
|
41
|
+
}
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
'use strict'
|
|
2
|
+
const path = require('path')
|
|
3
|
+
const execa = require('execa')
|
|
4
|
+
const arch = require('arch')
|
|
5
|
+
|
|
6
|
+
// Binaries from: https://github.com/sindresorhus/clipboardy/tree/v2.3.0
|
|
7
|
+
const windowBinaryPath = arch() === 'x64'
|
|
8
|
+
? path.join(__dirname, './fallbacks/windows/clipboard_x86_64.exe')
|
|
9
|
+
: path.join(__dirname, './fallbacks/windows/clipboard_i686.exe')
|
|
10
|
+
|
|
11
|
+
module.exports = {
|
|
12
|
+
copy: async options => execa(windowBinaryPath, ['--copy'], options),
|
|
13
|
+
paste: async options => execa.stdout(windowBinaryPath, ['--paste'], options),
|
|
14
|
+
copySync: options => execa.sync(windowBinaryPath, ['--copy'], options),
|
|
15
|
+
pasteSync: options => execa.sync(windowBinaryPath, ['--paste'], options)
|
|
16
|
+
}
|