@take2identity/verosint 0.2.4

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 (4) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +322 -0
  3. package/package.json +35 -0
  4. package/postinstall.js +280 -0
package/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ The MIT License (MIT)
2
+
3
+ Copyright (c) 2023 Take 2 Identity, Inc <support@verosint.com> (https://verosint.com)
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
package/README.md ADDED
@@ -0,0 +1,322 @@
1
+ # verosint
2
+
3
+ ![verosint](https://gitlab.com/443id/public/verosint/-/raw/main/assets/Verosint-logo-h-color.svg)
4
+ [![Go Report Card][reportcard]](https://goreportcard.com/report/gitlab.com/443id/public/verosint)
5
+
6
+ `verosint` is an open source tool that enables command line access to Verosint identity security endpoints.
7
+
8
+ ## Installation
9
+
10
+ Use the `verosint` tool to:
11
+
12
+ * Evaluate risk scores or create a rule set for a single set of identifiers
13
+ (email, IP, and/or phone number).
14
+ * Determine risk by running a batch evaluation for identifiers using a
15
+ [CSV](https://en.wikipedia.org/wiki/Comma-separated_values),
16
+ [LDIF](https://www.rfc-editor.org/rfc/rfc2849.html) files.
17
+ * Send events to the SignalPrint endpoint to create a map of identities and access history.
18
+ * Generate an [LDAP Schema](https://www.rfc-editor.org/rfc/rfc4512#page-22)
19
+ file to store risk scoring and/or rules evaluation atttributes in user
20
+ entries.
21
+
22
+ Download the binary from:
23
+ [releases page](https://gitlab.com/443id/public/verosint/-/releases).
24
+ Binaries for macOS, Windows, and Linux are available.
25
+
26
+ ### Alternative Installation methods
27
+
28
+ #### Node Package Manager (NPM)
29
+
30
+ ```shell
31
+ npm i -g @take2identity/verosint
32
+ ```
33
+
34
+ Check permissions before installing the CLI tool. If installation
35
+ fails, run the command with "sudo" (MacOS/Linux), or run the command
36
+ inside a terminal using administrator privileges (Windows).
37
+
38
+ #### Using `go install`
39
+
40
+ ```shell
41
+ go install gitlab.com/443id/public/verosint@latest
42
+ ```
43
+
44
+ #### Executing with a Docker container
45
+
46
+ Use the following command to run the CLI inside a Docker container
47
+ without having to install the tool on your system. This method
48
+ also enables running the CLI inside in a containerized
49
+ CI/CD pipeline.
50
+
51
+ ```shell
52
+ docker run --rm registry.gitlab.com/443id/public/verosint
53
+ ```
54
+
55
+ Configuration for the CLI is stored in the `.verosint.yaml` file in the
56
+ home directory. To make the configuration accessible to the Docker
57
+ container, create a volume map for the configuration file. For example:
58
+
59
+ ```shell
60
+ docker run --rm -v "$HOME/.verosint.yaml:/root/.verosint.yaml" registry.gitlab.com/443id/public/verosint
61
+ ```
62
+
63
+ ## Usage
64
+
65
+ After installing the CLI, you can execute it using `verosint`.
66
+
67
+ Interacting with the Verosint APIs require an API key. You can pass the API
68
+ key using the `--apiKey` argument. It is recommended to store the API
69
+ key inside a configuration file or an environment variable to prevent
70
+ exposure.
71
+
72
+ You can get command help using the `--help` argument:
73
+
74
+ ```shell
75
+ verosint --help
76
+ ```
77
+
78
+ Note that each subcommand has its own specific help. For example, to
79
+ print the help for the `evaluate rules-batch` subcommand, run:
80
+
81
+ ```shell
82
+ verosint evaluate rules-batch --help
83
+ ```
84
+
85
+ ### Configuration File
86
+
87
+ The tool can read settings from a configuration file in a
88
+ [YAML](https://yaml.org/) format.
89
+ For example, you can store the API key as well as rules inside the file.
90
+
91
+ By default, the tool looks for the configuration file `.verosint.yaml` in
92
+ your home directory. You can override this setting with the
93
+ `--configFile` flag.
94
+
95
+ An example configuration file:
96
+
97
+ ```yaml
98
+ apiKey: <API key goes here>
99
+ rules:
100
+ - name: IP - Tor/Bot/VPN
101
+ outcomes:
102
+ - DENY
103
+ query: 'signals.ip.bot || signals.ip.tor || signals.ip.vpn'
104
+ reason: This IP address is a known bot, active Tor node, or a VPN
105
+ ```
106
+
107
+ #### API key as an Environment Variable
108
+
109
+ You can also set the `VEROSINT_APIKEY` environment variable to hold the value
110
+ of the API key:
111
+
112
+ ```shell
113
+ export VEROSINT_APIKEY="API key goes here"
114
+ verosint evaluate risk ip:172.66.43.186
115
+ ```
116
+
117
+ ### Evaluating Risk or Rules
118
+
119
+ #### Single Set of Identifiers
120
+
121
+ The CLI accepts the following identifiers.
122
+
123
+ | Name | Description |
124
+ | ---- | ----------- |
125
+ | ip | IP address (either IPv4 or IPv6) |
126
+ | email | Email address |
127
+ | phone | Phone number in the [international phone number format](https://en.wikipedia.org/wiki/E.164) |
128
+
129
+ When providing a set of identifiers, the API expects one or more
130
+ identifiers (IP address, email, or phone number) and only one value per
131
+ identifier.
132
+
133
+ IPv6 addresses may compress zeros for a shorter form and use
134
+ representations as described in [RFC 5952](https://www.rfc-editor.org/rfc/rfc5952).
135
+
136
+ Responses are provided in the JSON format on the standard output.
137
+
138
+ ##### Examples
139
+
140
+ ###### 1. Evaluate an IPv4 address for risk
141
+
142
+ ```shell
143
+ verosint evaluate risk ip:172.66.43.186
144
+ ```
145
+
146
+ ###### 2. Evaluate an IPv6 address, a phone number and an email address for risk
147
+
148
+ ```shell
149
+ verosint evaluate risk ip:2607:fb91:1296:c7dc:a0c4:25a9:ac7a:4384 email:user@example.com phone:15123944240
150
+ ```
151
+
152
+ ###### 3. Evaluate an IPv4 for address against a rule set already defined in the configuration
153
+
154
+ To obtain the UUID of the rule set, visit the
155
+ [Rules](https://app.verosint.com/rules) configuration and copy the UUID of
156
+ the rule set you would like to evaluate.
157
+
158
+ ![Copy Rule Set UUID](assets/copyrulesetuuid.png)
159
+
160
+ ```shell
161
+ verosint evalute rule ip:104.255.6.45 --ruleSetUuid 4f5ab21b-984c-455e-b889-b6b0272a4567
162
+ ```
163
+
164
+ ###### 4. Evaluate an Email address against a rule set provided using a local file
165
+
166
+ You can export a rule set defined in the [Rules](https://app.verosint.com/rules)
167
+ configuration into a local file as shown below.
168
+
169
+ ![Export Rule Set](assets/exportruleset.png)
170
+
171
+ This example evaluates the `babs@jensen.com` email address against the rule defined
172
+ in the `mfarule.json` file.
173
+
174
+ ```shell
175
+ verosint evaluate rule email:babs@jensen.com --rulesSetFile mfarule.json
176
+ ```
177
+
178
+ ##### 5. Check if an IP address is within 100 kilometers of Austin, TX using a local rule set
179
+
180
+ You can place rules inside a local configuration file. The following is
181
+ an example file that uses the `isWithin` function, which enables you to
182
+ create rules for [geo-fencing](https://en.wikipedia.org/wiki/Geo-fence)
183
+ purposes:
184
+
185
+ ```yaml
186
+ apiKey: <API key goes here>
187
+ rules:
188
+ - name: IP not in Austin
189
+ outcomes:
190
+ - DENY
191
+ query: '!signals.ip.geo.isWithin(30.3079827, -97.895826, 100)'
192
+ reason: This IP is not within 100 kilometers of Austin, Texas
193
+ ```
194
+
195
+ The following example runs the same rule saved in the default
196
+ configuration file against the `104.16.44.99` IP address:
197
+
198
+ ```shell
199
+ verosint evaluate rules ip:104.16.44.99
200
+ ```
201
+
202
+ #### Batch Evaluation
203
+
204
+ Use input files to evaluate multiple sets of identifiers for risk or
205
+ against rules. Batch commands can use input and output files in CSV or
206
+ LDIF format, and can produce a report file formatted as JSON.
207
+
208
+ Processing time may take much longer with larger files, than for a
209
+ single set of identifiers.
210
+
211
+ ##### Batch Evaluation Examples
212
+
213
+ ###### 1. Executing Batch Risk Evaluation using CSV input/output format
214
+
215
+ The input file does not have to be fully populated for all identifiers.
216
+ For example, the following CSV-formatted input file is valid without a
217
+ phone number present on the last record:
218
+
219
+ ```csv
220
+ ip,email,phone
221
+ 104.16.44.99,babs@jensen.com,15123944240
222
+ 2607:fb91:1296:c7dc:a0c4:25a9:ac7a:4384,alison@example.com,
223
+ ```
224
+
225
+ To evaluate the same file and save it as `myRecords.csv`, run the
226
+ following command:
227
+
228
+ ```shell
229
+ verosint evaluate risk-batch --inputFile myRecords.csv \
230
+ --outputFile riskOutput.csv --reportFile riskReport.json
231
+ ```
232
+
233
+ ###### 2. Executing Batch Rules Evaluation with column index and LDIF output
234
+
235
+ If using an input file that has multiple identifiers, you can provide a
236
+ column index (where 0 refers to the first column) to indicate where the
237
+ value of a particular identifier is present. This content is saved in
238
+ `mapped.csv`.
239
+
240
+ ```csv
241
+ ipaddress,mail,telephone
242
+ 104.16.44.99,babs@jensen.com,15123944240
243
+ ```
244
+
245
+ Using the rules present in the default configuration file, the
246
+ following command generates LDIF-formatted output and JSON report
247
+ files:
248
+
249
+ ```shell
250
+ verosint evaluate rules-batch ip:0 email:1 phone:2 \
251
+ --inputFile mapped.csv \
252
+ --outputFile output.ldif --outputType ldif \
253
+ --reportFile report.json
254
+ ```
255
+
256
+ #### Submitting SignalPrint Events
257
+
258
+ You can submit events to the SignalPrint endpoint using the
259
+ `signalprint send-events` subcommand. This subcommand works like the
260
+ batch commands for risk and rules. An event timestamp, IP address, and
261
+ user agent is required for each event. You can optionally add an
262
+ accountId, email, and/or phone with each event.
263
+
264
+ The timestamp is expected to be in the
265
+ [RFC3339](https://www.rfc-editor.org/rfc/rfc3339) format. For example:
266
+ `2019-01-22T03:56:17+03:30`.
267
+
268
+ ##### Examples for Signal Print
269
+
270
+ Using the following event information saved in `events.csv`,
271
+
272
+ ```csv
273
+ timestamp,ip,accountId,email,phone,userAgent
274
+ 2019-01-22T03:56:17-05:00,104.16.44.99,babs_jensen,babs@jensen.com,15123944240,"Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/109.0.0.0 Safari/537.36"
275
+ ```
276
+
277
+ you can send the event to SignalPrint with:
278
+
279
+ ```csv
280
+ verosint signalprint send-events --inputFile events.csv
281
+ ```
282
+
283
+ ### Generating LDAP Schema
284
+
285
+ This command prints an LDAP schema that allows you to enrich existing
286
+ user entries in your directory with risk or rule evaluation data from
287
+ the API. The enterprise number (59592) in the object identifiers (OIDs)
288
+ is registered with the
289
+ [Internet Assigned Numbers Authority](https://www.iana.org/assignments/enterprise-numbers/).
290
+ This guarantees that the schema will not collide with your existing
291
+ schema elements.
292
+
293
+ Note that generating the LDAP schema does *not* require an API key. To
294
+ generate a schema, run the following command:
295
+
296
+ ```shell
297
+ verosint generate schema
298
+ ```
299
+
300
+ ## Development
301
+
302
+ ## Prerequisites
303
+
304
+ ### Go
305
+
306
+ Install the 1.20 version of [Go](https://golang.dev).
307
+
308
+ ### Task
309
+
310
+ The [task](https://taskfile.dev/installation/) utility is required to
311
+ execute the various build related tasks.
312
+
313
+ ### Testing
314
+
315
+ Unit tests can be executed using the `task test:unit` command. Our goal
316
+ is to maintain a minimum of 70% coverage.
317
+
318
+ ## Issues
319
+
320
+ Report issues at [Verosint Support](mailto:support@verosint.com)
321
+
322
+ [reportcard]: https://goreportcard.com/badge/gitlab.com/443id/public/verosint
package/package.json ADDED
@@ -0,0 +1,35 @@
1
+ {
2
+ "name": "@take2identity/verosint",
3
+ "version": "0.2.4",
4
+ "description": "Official CLI to interact with Verosint API",
5
+ "main": "index.js",
6
+ "scripts": {
7
+ "postinstall": "node postinstall.js install",
8
+ "preuninstall": "node postinstall.js uninstall"
9
+ },
10
+ "repository": {
11
+ "type": "git",
12
+ "url": "https://gitlab.com/443id/public/verosint.git"
13
+ },
14
+ "author": "Verosint",
15
+ "license": "MIT",
16
+ "bugs": {
17
+ "url": "https://gitlab.com/443id/public/verosint/-/issues"
18
+ },
19
+ "goBinary": {
20
+ "name": "verosint",
21
+ "path": "./bin",
22
+ "url": "https://gitlab.com/443id/public/verosint/-/releases/v{{version}}/downloads/verosint_"
23
+ },
24
+ "files": [
25
+ "dist",
26
+ "postinstall.js"
27
+ ],
28
+ "homepage": "https://gitlab.com/443id/public/verosint#readme",
29
+ "dependencies": {
30
+ "mkdirp": "^2.1.5",
31
+ "request": "^2.88.2",
32
+ "tar": "^6.1.13",
33
+ "unzipper": "0.10.11"
34
+ }
35
+ }
package/postinstall.js ADDED
@@ -0,0 +1,280 @@
1
+ #!/usr/bin/env node
2
+ /*
3
+ Copyright (c) 2023 Take 2 Identity, Inc
4
+ */
5
+ "use strict"
6
+
7
+ const { join } = require('path');
8
+ const { exec } = require('child_process');
9
+ const { existsSync, chmodSync, copyFileSync, unlinkSync, createWriteStream, readFileSync } = require('fs');
10
+ const mkdirp = require('mkdirp');
11
+ const request = require('request');
12
+ const tar = require('tar');
13
+ const zlib = require('zlib');
14
+ const unzipper = require('unzipper');
15
+
16
+ // Mapping from Node's `process.arch` to Our binary arch standard
17
+ const ARCH_MAPPING = {
18
+ "x64": "x86_64",
19
+ "x32": "i386",
20
+ "arm64": "arm64",
21
+ "amd64": "x86_64"
22
+ };
23
+
24
+ // Mapping between Node's `process.platform` to Our binary platform standard
25
+ const PLATFORM_MAPPING = {
26
+ "darwin": "MacOS",
27
+ "linux": "Linux",
28
+ "win32": "Windows",
29
+ };
30
+
31
+ function getInstallationPath(callback) {
32
+
33
+ // `npm bin` will output the path where binary files should be installed
34
+ exec('npm bin', (err, stdout, stderr) => {
35
+ let dir = null;
36
+ if (err || stderr || !stdout || stdout.length === 0) {
37
+
38
+ // We couldn't infer path from `npm bin`. Let's try to get it from
39
+ // Environment variables set by NPM when it runs.
40
+ // npm_config_prefix points to NPM's installation directory where `bin` folder is available
41
+ // Ex: /Users/foo/.nvm/versions/node/v4.3.0
42
+ const env = process.env;
43
+
44
+ if (env && env.npm_config_prefix) {
45
+ dir = join(env.npm_config_prefix, 'bin');
46
+ } else {
47
+ return callback(new Error('Error finding binary installation directory'));
48
+ }
49
+ } else {
50
+ dir = stdout.trim();
51
+ }
52
+
53
+ dir = dir.replace(/node_modules.*[\/\\]\.bin/, join('node_modules', '.bin'));
54
+ mkdirp.sync(dir);
55
+ callback(null, dir);
56
+ });
57
+ }
58
+
59
+ function verifyAndPlaceBinary(binName, binPath, callback) {
60
+ if (!existsSync(join(binPath, binName))) {
61
+ return callback(`Downloaded binary does not contain the binary specified in configuration - ${binName}`);
62
+ }
63
+
64
+ getInstallationPath((err, installationPath) => {
65
+ if (err) {
66
+ return callback(err);
67
+ }
68
+
69
+ // Move the binary file and make sure it is executable
70
+ copyFileSync(join(binPath, binName), join(installationPath, binName));
71
+ unlinkSync(join(binPath, binName));
72
+ chmodSync(join(installationPath, binName), '755');
73
+
74
+ console.log('Placed binary on', join(installationPath, binName));
75
+
76
+ callback(null);
77
+ });
78
+ }
79
+
80
+ function validateConfiguration(packageJson) {
81
+
82
+ if (!packageJson.version) {
83
+ return "'version' property must be specified";
84
+ }
85
+
86
+ if (!packageJson.goBinary || typeof(packageJson.goBinary) !== "object") {
87
+ return "'goBinary' property must be defined and be an object";
88
+ }
89
+
90
+ if (!packageJson.goBinary.name) {
91
+ return "'name' property is necessary";
92
+ }
93
+
94
+ if (!packageJson.goBinary.path) {
95
+ return "'path' property is necessary";
96
+ }
97
+
98
+ if (!packageJson.goBinary.url) {
99
+ return "'url' property is required";
100
+ }
101
+ }
102
+
103
+ function parsePackageJson() {
104
+ if (!(process.arch in ARCH_MAPPING)) {
105
+ console.error("Installation is not supported for this architecture: " + process.arch);
106
+ return;
107
+ }
108
+
109
+ if (!(process.platform in PLATFORM_MAPPING)) {
110
+ console.error("Installation is not supported for this platform: " + process.platform);
111
+ return
112
+ }
113
+
114
+ const packageJsonPath = join(".", "package.json");
115
+ if (!existsSync(packageJsonPath)) {
116
+ console.error("Unable to find package.json. " +
117
+ "Please run this script at root of the package you want to be installed");
118
+ return
119
+ }
120
+
121
+ let packageJson = JSON.parse(readFileSync(packageJsonPath));
122
+ let error = validateConfiguration(packageJson);
123
+ if (error && error.length > 0) {
124
+ console.error("Invalid package.json: " + error);
125
+ return
126
+ }
127
+
128
+ // We have validated the config. It exists in all its glory
129
+ let binName = packageJson.goBinary.name;
130
+ let binPath = packageJson.goBinary.path;
131
+ let url = packageJson.goBinary.url;
132
+ let version = packageJson.version;
133
+
134
+ // Binary name on Windows has .exe suffix
135
+ if (process.platform === "win32") {
136
+ binName += ".exe";
137
+ url = url.replace(/{{win_ext}}/g, '.exe');
138
+ } else {
139
+ url = url.replace(/{{win_ext}}/g, '');
140
+ }
141
+
142
+ url = url.replace(/{{version}}/g, version);
143
+
144
+ switch(PLATFORM_MAPPING[process.platform]) {
145
+ case "MacOS":
146
+ url = url + "MacOS_all.tar.gz";
147
+ break;
148
+ case "Linux":
149
+ url = url + "Linux_" + ARCH_MAPPING[process.arch] + ".tar.gz";
150
+ break;
151
+ case "Windows":
152
+ url = url + "Windows_" + ARCH_MAPPING[process.arch] + ".zip";
153
+ break;
154
+ default:
155
+ console.error(`You have an unsupported platform (${process.platform}) or architecture (${process.arch})`);
156
+ return;
157
+ }
158
+
159
+ return {
160
+ binName: binName,
161
+ binPath: binPath,
162
+ url: url,
163
+ version: version
164
+ }
165
+ }
166
+
167
+ function unzip({ opts, req, onSuccess, onError }) {
168
+ const unzip = unzipper.Extract({ path: opts.binPath });
169
+ unzip.on('error', onError);
170
+ unzip.on('close', onSuccess);
171
+ req.pipe(unzip);
172
+ }
173
+
174
+ function untar({ opts, req, onSuccess, onError }) {
175
+ const ungz = zlib.createGunzip();
176
+ const untar = tar.Extract({ path: opts.binPath });
177
+ ungz.on('error', onError);
178
+ untar.on('error', onError);
179
+ untar.on('end', onSuccess);
180
+ req.pipe(ungz).pipe(untar);
181
+ }
182
+
183
+ /**
184
+ * Move strategy for binary resources without compression.
185
+ */
186
+ function move({ opts, req, onSuccess, onError }) {
187
+ const stream = createWriteStream(join(opts.binPath, opts.binName));
188
+ stream.on('error', onError);
189
+ stream.on('close', onSuccess);
190
+ req.pipe(stream);
191
+ }
192
+
193
+ function getStrategy({ url }) {
194
+ if (url.endsWith('.tar.gz')) {
195
+ return untar;
196
+ } else if (url.endsWith('.zip')) {
197
+ return unzip;
198
+ } else {
199
+ return move;
200
+ }
201
+ }
202
+
203
+ /**
204
+ * Reads the configuration from application's package.json,
205
+ * validates properties, downloads the binary, untars, and stores at
206
+ * ./bin in the package's root. NPM already has support to install binary files
207
+ * specific locations when invoked with "npm install -g"
208
+ *
209
+ * See: https://docs.npmjs.com/files/package.json#bin
210
+ */
211
+
212
+ function install(callback) {
213
+
214
+ const opts = parsePackageJson();
215
+ if (!opts) return callback('Invalid inputs');
216
+
217
+ mkdirp.sync(opts.binPath);
218
+
219
+ console.log('Downloading from URL: ' + opts.url);
220
+
221
+ const req = request({ uri: opts.url });
222
+ req.on('error', () => callback('Error downloading from URL: ' + opts.url));
223
+ req.on('response', (res) => {
224
+ if (res.statusCode !== 200) return callback('Error downloading binary. HTTP Status Code: ' + res.statusCode);
225
+
226
+ const strategy = getStrategy(opts);
227
+
228
+ strategy({
229
+ opts,
230
+ req,
231
+ onSuccess: () => verifyAndPlaceBinary(opts.binName, opts.binPath, callback),
232
+ onError: callback
233
+ });
234
+ });
235
+ }
236
+
237
+
238
+ function uninstall(callback) {
239
+ const { binName } = parsePackageJson();
240
+ getInstallationPath((err, installationPath) => {
241
+ if (err) {
242
+ return callback(err);
243
+ }
244
+ try {
245
+ unlinkSync(join(installationPath, binName));
246
+ } catch(ex) {
247
+ // Ignore errors when deleting the file.
248
+ }
249
+ return callback(null);
250
+ });
251
+ }
252
+
253
+
254
+
255
+ // Parse command line arguments and call the right method
256
+ let actions = {
257
+ "install": install,
258
+ "uninstall": uninstall
259
+ };
260
+
261
+ let argv = process.argv;
262
+ if (argv && argv.length > 2) {
263
+ let cmd = process.argv[2];
264
+ if (!actions[cmd]) {
265
+ console.log("Invalid command to postinstall script. `install` and `uninstall` are the only supported commands");
266
+ process.exit(1);
267
+ }
268
+
269
+ actions[cmd](function(err) {
270
+ if (err) {
271
+ console.error(err);
272
+ process.exit(1);
273
+ } else {
274
+ process.exit(0);
275
+ }
276
+ });
277
+ } else {
278
+ console.log('No command supplied. `install` and `uninstall` are the only supported commands');
279
+ exit(1);
280
+ }