@heroku/skynet 1.13.0 → 2.0.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.
- package/dist/commands/allowlist/add.d.ts +11 -0
- package/dist/commands/allowlist/add.js +34 -0
- package/dist/commands/allowlist/remove.d.ts +10 -0
- package/dist/commands/allowlist/remove.js +27 -0
- package/dist/commands/allowlists.d.ts +7 -0
- package/dist/commands/allowlists.js +24 -0
- package/dist/commands/categories/add.d.ts +10 -0
- package/dist/commands/categories/add.js +33 -0
- package/dist/commands/categories/get.d.ts +7 -0
- package/dist/commands/categories/get.js +19 -0
- package/dist/commands/categories/remove.d.ts +9 -0
- package/dist/commands/categories/remove.js +26 -0
- package/dist/commands/deprovision.d.ts +14 -0
- package/dist/commands/deprovision.js +80 -0
- package/dist/commands/suspend/app-owner.d.ts +15 -0
- package/dist/commands/suspend/app-owner.js +87 -0
- package/dist/commands/suspend/apps.d.ts +13 -0
- package/dist/commands/suspend/apps.js +54 -0
- package/dist/commands/suspend/user.d.ts +17 -0
- package/dist/commands/suspend/user.js +110 -0
- package/dist/commands/suspensions.d.ts +9 -0
- package/dist/commands/suspensions.js +25 -0
- package/dist/commands/unsuspend/apps.d.ts +11 -0
- package/dist/commands/unsuspend/apps.js +48 -0
- package/dist/commands/unsuspend/user.d.ts +11 -0
- package/dist/commands/unsuspend/user.js +49 -0
- package/dist/commands/userpass/add.d.ts +10 -0
- package/dist/commands/userpass/add.js +33 -0
- package/dist/commands/userpass/remove.d.ts +10 -0
- package/dist/commands/userpass/remove.js +33 -0
- package/dist/lib/heroku.d.ts +13 -0
- package/dist/lib/heroku.js +32 -0
- package/dist/lib/skynet.d.ts +32 -0
- package/dist/lib/skynet.js +215 -0
- package/dist/lib/sudo.d.ts +1 -0
- package/dist/lib/sudo.js +7 -0
- package/dist/lib/utils.d.ts +5 -0
- package/dist/lib/utils.js +57 -0
- package/oclif.manifest.json +730 -0
- package/package.json +61 -23
- package/commands/allowlist/add.js +0 -38
- package/commands/allowlist/remove.js +0 -29
- package/commands/allowlists.js +0 -30
- package/commands/categories/add.js +0 -40
- package/commands/categories/get.js +0 -27
- package/commands/categories/remove.js +0 -33
- package/commands/deprovision.js +0 -42
- package/commands/suspend/app-owner.js +0 -58
- package/commands/suspend/apps.js +0 -34
- package/commands/suspend/user.js +0 -80
- package/commands/suspensions.js +0 -24
- package/commands/unsuspend/apps.js +0 -33
- package/commands/unsuspend/user.js +0 -33
- package/commands/userpass/add.js +0 -21
- package/commands/userpass/remove.js +0 -21
- package/index.js +0 -23
- package/lib/command.js +0 -12
- package/lib/heroku.js +0 -30
- package/lib/notifyOption.js +0 -24
- package/lib/skynet.js +0 -218
- package/lib/sudo.js +0 -5
- package/lib/utils.js +0 -35
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
import SkynetAPI from '../lib/skynet.js';
|
|
2
|
+
import { Command } from '@heroku-cli/command';
|
|
3
|
+
import { Flags, ux } from '@oclif/core';
|
|
4
|
+
export default class Suspensions extends Command {
|
|
5
|
+
static description = '(requires sudo) suspension history of the given user account';
|
|
6
|
+
static examples = [
|
|
7
|
+
'$ heroku skynet:suspensions -a [user account]'
|
|
8
|
+
];
|
|
9
|
+
static flags = {
|
|
10
|
+
account: Flags.string({
|
|
11
|
+
name: 'account',
|
|
12
|
+
char: 'a',
|
|
13
|
+
description: 'user account email',
|
|
14
|
+
hasValue: true,
|
|
15
|
+
required: true
|
|
16
|
+
})
|
|
17
|
+
};
|
|
18
|
+
async run() {
|
|
19
|
+
const { flags } = await this.parse(Suspensions);
|
|
20
|
+
const skynet = new SkynetAPI(this.heroku.auth);
|
|
21
|
+
let response = await skynet.suspensions(flags.account);
|
|
22
|
+
response = JSON.parse(response);
|
|
23
|
+
ux.log(response);
|
|
24
|
+
}
|
|
25
|
+
}
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
import { Command } from '@heroku-cli/command';
|
|
2
|
+
export default class UnsuspendApp extends Command {
|
|
3
|
+
static description: string;
|
|
4
|
+
static examples: string[];
|
|
5
|
+
static flags: {
|
|
6
|
+
app: import("@oclif/core/lib/interfaces/parser.js").OptionFlag<string, import("@oclif/core/lib/interfaces/parser.js").CustomOptions>;
|
|
7
|
+
category: import("@oclif/core/lib/interfaces/parser.js").OptionFlag<string, import("@oclif/core/lib/interfaces/parser.js").CustomOptions>;
|
|
8
|
+
notes: import("@oclif/core/lib/interfaces/parser.js").OptionFlag<string, import("@oclif/core/lib/interfaces/parser.js").CustomOptions>;
|
|
9
|
+
};
|
|
10
|
+
run(): Promise<void>;
|
|
11
|
+
}
|
|
@@ -0,0 +1,48 @@
|
|
|
1
|
+
import SkynetAPI from '../../lib/skynet.js';
|
|
2
|
+
import { Command } from '@heroku-cli/command';
|
|
3
|
+
import { color } from '@heroku-cli/color';
|
|
4
|
+
import { Flags, ux } from '@oclif/core';
|
|
5
|
+
import { processUnsuspendResult } from '../../lib/utils.js';
|
|
6
|
+
export default class UnsuspendApp extends Command {
|
|
7
|
+
static description = '(requires sudo) unsuspends an app';
|
|
8
|
+
static examples = [
|
|
9
|
+
'$ heroku skynet:unsuspend:app -a test-app -n "helpful unsuspend message" -c "unsuspend-apology"'
|
|
10
|
+
];
|
|
11
|
+
static flags = {
|
|
12
|
+
app: Flags.string({
|
|
13
|
+
name: 'app',
|
|
14
|
+
char: 'a',
|
|
15
|
+
description: 'app to unsuspend',
|
|
16
|
+
hasValue: true,
|
|
17
|
+
required: true
|
|
18
|
+
}),
|
|
19
|
+
category: Flags.string({
|
|
20
|
+
name: 'category',
|
|
21
|
+
char: 'c',
|
|
22
|
+
description: 'unsuspension category',
|
|
23
|
+
hasValue: true,
|
|
24
|
+
required: true
|
|
25
|
+
}),
|
|
26
|
+
notes: Flags.string({
|
|
27
|
+
name: 'notes',
|
|
28
|
+
char: 'n',
|
|
29
|
+
description: 'unsuspend notes',
|
|
30
|
+
hasValue: true,
|
|
31
|
+
required: true
|
|
32
|
+
})
|
|
33
|
+
};
|
|
34
|
+
async run() {
|
|
35
|
+
const { flags } = await this.parse(UnsuspendApp);
|
|
36
|
+
const skynet = new SkynetAPI(this.heroku.auth);
|
|
37
|
+
const app = flags.app;
|
|
38
|
+
const category = flags.category;
|
|
39
|
+
const notes = flags.notes;
|
|
40
|
+
if (!app) {
|
|
41
|
+
ux.error('Required flag: --app APP');
|
|
42
|
+
}
|
|
43
|
+
ux.action.start(`Unsuspending app ${color.cyan(app)}`);
|
|
44
|
+
let response = await skynet.unsuspendApp(app, category, notes);
|
|
45
|
+
response = JSON.parse(response);
|
|
46
|
+
processUnsuspendResult(app, response);
|
|
47
|
+
}
|
|
48
|
+
}
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
import { Command } from '@heroku-cli/command';
|
|
2
|
+
export default class UnsuspendUser extends Command {
|
|
3
|
+
static description: string;
|
|
4
|
+
static examples: string[];
|
|
5
|
+
static flags: {
|
|
6
|
+
user: import("@oclif/core/lib/interfaces/parser.js").OptionFlag<string, import("@oclif/core/lib/interfaces/parser.js").CustomOptions>;
|
|
7
|
+
category: import("@oclif/core/lib/interfaces/parser.js").OptionFlag<string, import("@oclif/core/lib/interfaces/parser.js").CustomOptions>;
|
|
8
|
+
notes: import("@oclif/core/lib/interfaces/parser.js").OptionFlag<string, import("@oclif/core/lib/interfaces/parser.js").CustomOptions>;
|
|
9
|
+
};
|
|
10
|
+
run(): Promise<void>;
|
|
11
|
+
}
|
|
@@ -0,0 +1,49 @@
|
|
|
1
|
+
import SkynetAPI from '../../lib/skynet.js';
|
|
2
|
+
import { requireSudo } from '../../lib/sudo.js';
|
|
3
|
+
import { Command } from '@heroku-cli/command';
|
|
4
|
+
import { color } from '@heroku-cli/color';
|
|
5
|
+
import { Flags, ux } from '@oclif/core';
|
|
6
|
+
import { processUnsuspendResult } from '../../lib/utils.js';
|
|
7
|
+
export default class UnsuspendUser extends Command {
|
|
8
|
+
static description = '(requires sudo) unsuspends a user';
|
|
9
|
+
static examples = [
|
|
10
|
+
'$ heroku skynet:unsuspend:user -u foo@bar.com -n "helpful unsuspend message" -c "unsuspend-account-recovery"'
|
|
11
|
+
];
|
|
12
|
+
static flags = {
|
|
13
|
+
user: Flags.string({
|
|
14
|
+
name: 'user',
|
|
15
|
+
char: 'u',
|
|
16
|
+
description: 'user to unsuspend',
|
|
17
|
+
hasValue: true
|
|
18
|
+
}),
|
|
19
|
+
category: Flags.string({
|
|
20
|
+
name: 'category',
|
|
21
|
+
char: 'c',
|
|
22
|
+
description: 'unsuspension category',
|
|
23
|
+
hasValue: true,
|
|
24
|
+
required: true
|
|
25
|
+
}),
|
|
26
|
+
notes: Flags.string({
|
|
27
|
+
name: 'notes',
|
|
28
|
+
char: 'n',
|
|
29
|
+
description: 'unsuspend notes',
|
|
30
|
+
hasValue: true,
|
|
31
|
+
required: true
|
|
32
|
+
})
|
|
33
|
+
};
|
|
34
|
+
async run() {
|
|
35
|
+
requireSudo();
|
|
36
|
+
const { flags } = await this.parse(UnsuspendUser);
|
|
37
|
+
const skynet = new SkynetAPI(this.heroku.auth);
|
|
38
|
+
const user = flags.user || process.env.HEROKU_USER;
|
|
39
|
+
const category = flags.category;
|
|
40
|
+
const notes = flags.notes;
|
|
41
|
+
if (!user) {
|
|
42
|
+
ux.error('Required flag: --user USER');
|
|
43
|
+
}
|
|
44
|
+
ux.action.start(`Unsuspending ${color.cyan(user)}`);
|
|
45
|
+
let response = await skynet.unsuspendUser(user, category, notes);
|
|
46
|
+
response = JSON.parse(response);
|
|
47
|
+
processUnsuspendResult(user, response);
|
|
48
|
+
}
|
|
49
|
+
}
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
import { Command } from '@heroku-cli/command';
|
|
2
|
+
export default class AddUserpass extends Command {
|
|
3
|
+
static description: string;
|
|
4
|
+
static examples: string[];
|
|
5
|
+
static flags: {
|
|
6
|
+
user: import("@oclif/core/lib/interfaces/parser.js").OptionFlag<string, import("@oclif/core/lib/interfaces/parser.js").CustomOptions>;
|
|
7
|
+
flag: import("@oclif/core/lib/interfaces/parser.js").OptionFlag<string, import("@oclif/core/lib/interfaces/parser.js").CustomOptions>;
|
|
8
|
+
};
|
|
9
|
+
run(): Promise<void>;
|
|
10
|
+
}
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
import SkynetAPI from '../../lib/skynet.js';
|
|
2
|
+
import { Command } from '@heroku-cli/command';
|
|
3
|
+
import { color } from '@heroku-cli/color';
|
|
4
|
+
import { Flags, ux } from '@oclif/core';
|
|
5
|
+
export default class AddUserpass extends Command {
|
|
6
|
+
static description = 'adds a userpass flag to a given user';
|
|
7
|
+
static examples = [
|
|
8
|
+
'$ heroku skynet:userpass:add -u foo@bar.com -f cant-install-abused-addons'
|
|
9
|
+
];
|
|
10
|
+
static flags = {
|
|
11
|
+
user: Flags.string({
|
|
12
|
+
name: 'user',
|
|
13
|
+
char: 'u',
|
|
14
|
+
description: 'user to apply userpass flag to',
|
|
15
|
+
hasValue: true,
|
|
16
|
+
required: true
|
|
17
|
+
}),
|
|
18
|
+
flag: Flags.string({
|
|
19
|
+
name: 'flag',
|
|
20
|
+
char: 'f',
|
|
21
|
+
description: 'flag to add to the given user',
|
|
22
|
+
hasValue: true,
|
|
23
|
+
required: true
|
|
24
|
+
})
|
|
25
|
+
};
|
|
26
|
+
async run() {
|
|
27
|
+
const { flags } = await this.parse(AddUserpass);
|
|
28
|
+
const skynet = new SkynetAPI(this.heroku.auth);
|
|
29
|
+
ux.action.start(`adding ${color.cyan(flags.flag)} to ${color.cyan(flags.user)}`);
|
|
30
|
+
await skynet.addUserpass(flags.user, flags.flag);
|
|
31
|
+
ux.action.stop();
|
|
32
|
+
}
|
|
33
|
+
}
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
import { Command } from '@heroku-cli/command';
|
|
2
|
+
export default class RemoveUserpass extends Command {
|
|
3
|
+
static description: string;
|
|
4
|
+
static examples: string[];
|
|
5
|
+
static flags: {
|
|
6
|
+
user: import("@oclif/core/lib/interfaces/parser.js").OptionFlag<string, import("@oclif/core/lib/interfaces/parser.js").CustomOptions>;
|
|
7
|
+
flag: import("@oclif/core/lib/interfaces/parser.js").OptionFlag<string, import("@oclif/core/lib/interfaces/parser.js").CustomOptions>;
|
|
8
|
+
};
|
|
9
|
+
run(): Promise<void>;
|
|
10
|
+
}
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
import SkynetAPI from '../../lib/skynet.js';
|
|
2
|
+
import { Command } from '@heroku-cli/command';
|
|
3
|
+
import { color } from '@heroku-cli/color';
|
|
4
|
+
import { Flags, ux } from '@oclif/core';
|
|
5
|
+
export default class RemoveUserpass extends Command {
|
|
6
|
+
static description = 'removes given flag from a given user';
|
|
7
|
+
static examples = [
|
|
8
|
+
'$ heroku skynet:userpass:remove -u foo@bar.com -f cant-install-abused-addons'
|
|
9
|
+
];
|
|
10
|
+
static flags = {
|
|
11
|
+
user: Flags.string({
|
|
12
|
+
name: 'user',
|
|
13
|
+
char: 'u',
|
|
14
|
+
description: 'user to remove user_pass from',
|
|
15
|
+
hasValue: true,
|
|
16
|
+
required: true
|
|
17
|
+
}),
|
|
18
|
+
flag: Flags.string({
|
|
19
|
+
name: 'flag',
|
|
20
|
+
char: 'f',
|
|
21
|
+
description: 'flag to remove from given user',
|
|
22
|
+
hasValue: true,
|
|
23
|
+
required: true
|
|
24
|
+
})
|
|
25
|
+
};
|
|
26
|
+
async run() {
|
|
27
|
+
const { flags } = await this.parse(RemoveUserpass);
|
|
28
|
+
const skynet = new SkynetAPI(this.heroku.auth);
|
|
29
|
+
ux.action.start(`removing ${color.cyan(flags.flag)} from ${color.cyan(flags.user)}`);
|
|
30
|
+
await skynet.removeUserpass(flags.user, flags.flag);
|
|
31
|
+
ux.action.stop();
|
|
32
|
+
}
|
|
33
|
+
}
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
import { Method } from 'got';
|
|
2
|
+
interface RequestOptions {
|
|
3
|
+
method?: Method;
|
|
4
|
+
headers?: Record<string, string>;
|
|
5
|
+
body?: string;
|
|
6
|
+
json?: Record<string, any>;
|
|
7
|
+
}
|
|
8
|
+
export default class HerokuAPI {
|
|
9
|
+
private token;
|
|
10
|
+
constructor(token: string);
|
|
11
|
+
request(url: string, options?: RequestOptions): Promise<string>;
|
|
12
|
+
}
|
|
13
|
+
export {};
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
'use strict';
|
|
2
|
+
import got from 'got';
|
|
3
|
+
const apiHost = 'https://api.heroku.com';
|
|
4
|
+
export default class HerokuAPI {
|
|
5
|
+
token;
|
|
6
|
+
constructor(token) {
|
|
7
|
+
this.token = token;
|
|
8
|
+
}
|
|
9
|
+
async request(url, options = {}) {
|
|
10
|
+
const gotOptions = {
|
|
11
|
+
...options,
|
|
12
|
+
headers: Object.assign({
|
|
13
|
+
Authorization: `Bearer ${this.token}`,
|
|
14
|
+
Accept: 'application/json',
|
|
15
|
+
'Content-type': 'application/x-www-form-urlencoded',
|
|
16
|
+
'X-Heroku-Sudo': 'true'
|
|
17
|
+
}, options.headers)
|
|
18
|
+
};
|
|
19
|
+
switch (options.method) {
|
|
20
|
+
case 'delete':
|
|
21
|
+
try {
|
|
22
|
+
await got.delete(apiHost + url, gotOptions);
|
|
23
|
+
return 'done';
|
|
24
|
+
}
|
|
25
|
+
catch {
|
|
26
|
+
return 'failed';
|
|
27
|
+
}
|
|
28
|
+
default:
|
|
29
|
+
return '';
|
|
30
|
+
}
|
|
31
|
+
}
|
|
32
|
+
}
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
import FormData from 'form-data';
|
|
2
|
+
interface RequestOptions {
|
|
3
|
+
method?: 'GET' | 'POST' | 'DELETE';
|
|
4
|
+
headers?: Record<string, string>;
|
|
5
|
+
body?: FormData | any;
|
|
6
|
+
json?: any;
|
|
7
|
+
form?: any;
|
|
8
|
+
}
|
|
9
|
+
export default class SkynetAPI {
|
|
10
|
+
private version;
|
|
11
|
+
private token;
|
|
12
|
+
constructor(token: string);
|
|
13
|
+
request(url: string, options?: RequestOptions): Promise<any>;
|
|
14
|
+
categories(): Promise<any>;
|
|
15
|
+
addCategory(name: string, description: string): Promise<any>;
|
|
16
|
+
removeCategory(name: string): Promise<any>;
|
|
17
|
+
allowlists(): Promise<any>;
|
|
18
|
+
addAllowlist(appOrUserEmail: string, notes: string): Promise<any>;
|
|
19
|
+
removeAllowlist(appOrUserEmail: string): Promise<any>;
|
|
20
|
+
removeUserpass(user: string, flag: string): Promise<any>;
|
|
21
|
+
addUserpass(user: string, flag: string): Promise<any>;
|
|
22
|
+
suspendAppOwner(app: string, notes: string, category: string, force?: boolean, deprovision?: boolean, async?: boolean): Promise<any>;
|
|
23
|
+
suspendApp(app: string, notes: string, category: string, force?: boolean, async?: boolean): Promise<any>;
|
|
24
|
+
unsuspendApp(app: string, category: string, notes: string): Promise<any>;
|
|
25
|
+
suspendUser(user: string, notes: string, category: string, notify: boolean, force?: boolean, deprovision?: boolean, async?: boolean): Promise<any>;
|
|
26
|
+
unsuspendUser(user: string, category: string, notes: string): Promise<any>;
|
|
27
|
+
bulkSuspendUsers(file: string, notes: string, category: string, notify: boolean, force?: boolean, deprovision?: boolean): Promise<any>;
|
|
28
|
+
bulkSuspendAppOwner(apps: string, notes: string, category: string, deprovision?: boolean): Promise<any>;
|
|
29
|
+
deprovision(user: string, notes: string, category: string, notify?: boolean, force?: boolean): Promise<any>;
|
|
30
|
+
suspensions(account: string): Promise<any>;
|
|
31
|
+
}
|
|
32
|
+
export {};
|
|
@@ -0,0 +1,215 @@
|
|
|
1
|
+
import got from 'got';
|
|
2
|
+
import fs from 'fs';
|
|
3
|
+
import FormData from 'form-data';
|
|
4
|
+
import { readFileSync } from 'fs';
|
|
5
|
+
import { join, dirname } from 'path';
|
|
6
|
+
import { fileURLToPath } from 'url';
|
|
7
|
+
let skynetHost = 'https://skynet.risk.herokai.com';
|
|
8
|
+
// If test against local skynet environment, change skynet host to localhost:5000
|
|
9
|
+
// let skynetHost = 'http://localhost:5000'
|
|
10
|
+
if (process.env.SKYNET_HOST) {
|
|
11
|
+
skynetHost = process.env.SKYNET_HOST;
|
|
12
|
+
}
|
|
13
|
+
const SKYNET_BASE_URL = `${skynetHost}/api-h`;
|
|
14
|
+
export default class SkynetAPI {
|
|
15
|
+
version;
|
|
16
|
+
token;
|
|
17
|
+
constructor(token) {
|
|
18
|
+
const __filename = fileURLToPath(import.meta.url);
|
|
19
|
+
const __dirname = dirname(__filename);
|
|
20
|
+
const packageJSON = JSON.parse(readFileSync(join(__dirname, '../../package.json'), 'utf8'));
|
|
21
|
+
this.version = `skynet-${packageJSON.version}`;
|
|
22
|
+
this.token = token;
|
|
23
|
+
}
|
|
24
|
+
request(url, options = {}) {
|
|
25
|
+
if (options.body && options.body instanceof FormData) {
|
|
26
|
+
options.headers = Object.assign({
|
|
27
|
+
Authorization: `Bearer ${this.token}`,
|
|
28
|
+
'User-Agent': this.version
|
|
29
|
+
}, options.body.getHeaders(), options.headers);
|
|
30
|
+
}
|
|
31
|
+
else {
|
|
32
|
+
options.headers = Object.assign({
|
|
33
|
+
Authorization: `Bearer ${this.token}`,
|
|
34
|
+
'User-Agent': this.version
|
|
35
|
+
}, options.headers);
|
|
36
|
+
}
|
|
37
|
+
switch (options.method) {
|
|
38
|
+
case 'DELETE':
|
|
39
|
+
return got.delete(SKYNET_BASE_URL + url, options).then(res => res.body);
|
|
40
|
+
case 'GET':
|
|
41
|
+
return got.get(SKYNET_BASE_URL + url, options).then(res => res.body);
|
|
42
|
+
case 'POST':
|
|
43
|
+
return got.post(SKYNET_BASE_URL + url, options).then(res => res.body);
|
|
44
|
+
default:
|
|
45
|
+
return Promise.resolve(null);
|
|
46
|
+
}
|
|
47
|
+
}
|
|
48
|
+
categories() {
|
|
49
|
+
return this.request('/categories', {
|
|
50
|
+
method: 'GET'
|
|
51
|
+
});
|
|
52
|
+
}
|
|
53
|
+
addCategory(name, description) {
|
|
54
|
+
return this.request('/categories', {
|
|
55
|
+
method: 'POST',
|
|
56
|
+
json: {
|
|
57
|
+
category: name,
|
|
58
|
+
description
|
|
59
|
+
}
|
|
60
|
+
});
|
|
61
|
+
}
|
|
62
|
+
removeCategory(name) {
|
|
63
|
+
return this.request(`/categories/${name}`, {
|
|
64
|
+
method: 'DELETE'
|
|
65
|
+
});
|
|
66
|
+
}
|
|
67
|
+
allowlists() {
|
|
68
|
+
return this.request('/whitelist', {
|
|
69
|
+
method: 'GET'
|
|
70
|
+
});
|
|
71
|
+
}
|
|
72
|
+
addAllowlist(appOrUserEmail, notes) {
|
|
73
|
+
const body = {
|
|
74
|
+
value: appOrUserEmail,
|
|
75
|
+
notes
|
|
76
|
+
};
|
|
77
|
+
return this.request('/whitelist', {
|
|
78
|
+
method: 'POST',
|
|
79
|
+
form: body
|
|
80
|
+
});
|
|
81
|
+
}
|
|
82
|
+
removeAllowlist(appOrUserEmail) {
|
|
83
|
+
return this.request(`/whitelist/${appOrUserEmail}`, {
|
|
84
|
+
method: 'DELETE',
|
|
85
|
+
json: {}
|
|
86
|
+
});
|
|
87
|
+
}
|
|
88
|
+
removeUserpass(user, flag) {
|
|
89
|
+
const body = {
|
|
90
|
+
user,
|
|
91
|
+
flag
|
|
92
|
+
};
|
|
93
|
+
return this.request('/userpass/remove', {
|
|
94
|
+
method: 'POST',
|
|
95
|
+
form: body
|
|
96
|
+
});
|
|
97
|
+
}
|
|
98
|
+
addUserpass(user, flag) {
|
|
99
|
+
const body = {
|
|
100
|
+
user,
|
|
101
|
+
flag
|
|
102
|
+
};
|
|
103
|
+
return this.request('/userpass/add', {
|
|
104
|
+
method: 'POST',
|
|
105
|
+
form: body
|
|
106
|
+
});
|
|
107
|
+
}
|
|
108
|
+
suspendAppOwner(app, notes, category, force = false, deprovision = false, async = false) {
|
|
109
|
+
const body = {
|
|
110
|
+
value: app,
|
|
111
|
+
reason: notes,
|
|
112
|
+
method: 'skynet-cli',
|
|
113
|
+
category,
|
|
114
|
+
force,
|
|
115
|
+
deprovision,
|
|
116
|
+
sync: !async,
|
|
117
|
+
};
|
|
118
|
+
return this.request('/suspend/app-owner', {
|
|
119
|
+
method: 'POST',
|
|
120
|
+
form: body
|
|
121
|
+
});
|
|
122
|
+
}
|
|
123
|
+
suspendApp(app, notes, category, force = false, async = false) {
|
|
124
|
+
const body = {
|
|
125
|
+
value: app,
|
|
126
|
+
reason: notes,
|
|
127
|
+
category,
|
|
128
|
+
force,
|
|
129
|
+
method: 'skynet-cli',
|
|
130
|
+
sync: !async,
|
|
131
|
+
};
|
|
132
|
+
return this.request('/suspend/app', {
|
|
133
|
+
method: 'POST',
|
|
134
|
+
form: body
|
|
135
|
+
});
|
|
136
|
+
}
|
|
137
|
+
unsuspendApp(app, category, notes) {
|
|
138
|
+
return this.request(`/suspensions/app/${app}?category=${category}&reason=${notes}`, {
|
|
139
|
+
method: 'DELETE',
|
|
140
|
+
json: {}
|
|
141
|
+
});
|
|
142
|
+
}
|
|
143
|
+
suspendUser(user, notes, category, notify, force = false, deprovision = false, async = false) {
|
|
144
|
+
const body = {
|
|
145
|
+
value: user,
|
|
146
|
+
reason: notes,
|
|
147
|
+
method: 'skynet-cli',
|
|
148
|
+
category,
|
|
149
|
+
force,
|
|
150
|
+
notify,
|
|
151
|
+
deprovision,
|
|
152
|
+
sync: !async,
|
|
153
|
+
};
|
|
154
|
+
return this.request('/suspend/user', {
|
|
155
|
+
method: 'POST',
|
|
156
|
+
form: body
|
|
157
|
+
});
|
|
158
|
+
}
|
|
159
|
+
unsuspendUser(user, category, notes) {
|
|
160
|
+
return this.request(`/suspensions/user/${user}?category=${category}&reason=${notes}`, {
|
|
161
|
+
method: 'DELETE',
|
|
162
|
+
json: {}
|
|
163
|
+
});
|
|
164
|
+
}
|
|
165
|
+
bulkSuspendUsers(file, notes, category, notify, force = false, deprovision = false) {
|
|
166
|
+
const fileStream = fs.createReadStream(file);
|
|
167
|
+
const form = new FormData();
|
|
168
|
+
form.append('file', fileStream);
|
|
169
|
+
form.append('reason', notes);
|
|
170
|
+
form.append('method', 'skynet-cli');
|
|
171
|
+
form.append('category', category);
|
|
172
|
+
form.append('bulk', 'true');
|
|
173
|
+
form.append('force', String(force));
|
|
174
|
+
form.append('notify', String(notify));
|
|
175
|
+
form.append('deprovision', String(deprovision));
|
|
176
|
+
return this.request('/bulk-suspend/user', {
|
|
177
|
+
method: 'POST',
|
|
178
|
+
body: form
|
|
179
|
+
});
|
|
180
|
+
}
|
|
181
|
+
bulkSuspendAppOwner(apps, notes, category, deprovision = false) {
|
|
182
|
+
const body = {
|
|
183
|
+
value: apps,
|
|
184
|
+
reason: notes,
|
|
185
|
+
method: 'skynet-cli',
|
|
186
|
+
category,
|
|
187
|
+
bulk: 'true',
|
|
188
|
+
deprovision
|
|
189
|
+
};
|
|
190
|
+
return this.request('/suspend/app-owner', {
|
|
191
|
+
method: 'POST',
|
|
192
|
+
form: body
|
|
193
|
+
});
|
|
194
|
+
}
|
|
195
|
+
deprovision(user, notes, category, notify = true, force = false) {
|
|
196
|
+
const body = {
|
|
197
|
+
value: user,
|
|
198
|
+
reason: notes,
|
|
199
|
+
method: 'skynet-cli',
|
|
200
|
+
category,
|
|
201
|
+
force,
|
|
202
|
+
notify
|
|
203
|
+
};
|
|
204
|
+
return this.request('/deprovision', {
|
|
205
|
+
method: 'POST',
|
|
206
|
+
form: body
|
|
207
|
+
});
|
|
208
|
+
}
|
|
209
|
+
suspensions(account) {
|
|
210
|
+
return this.request(`/v2/suspensions/${account}`, {
|
|
211
|
+
method: 'GET'
|
|
212
|
+
});
|
|
213
|
+
}
|
|
214
|
+
}
|
|
215
|
+
;
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export declare function requireSudo(): void;
|
package/dist/lib/sudo.js
ADDED
|
@@ -0,0 +1,5 @@
|
|
|
1
|
+
export declare function readlines(file: string): Promise<string[]>;
|
|
2
|
+
export declare function arrayChunks<T>(array: T[], chunkSize: number): T[][];
|
|
3
|
+
export declare function processSuspensionResult(suspendObject: any, response: any): void;
|
|
4
|
+
export declare function processUnsuspendResult(unsuspendObject: any, response: any): void;
|
|
5
|
+
export declare function logError(response: any): void;
|
|
@@ -0,0 +1,57 @@
|
|
|
1
|
+
import split from 'split';
|
|
2
|
+
import fs from 'fs';
|
|
3
|
+
import { ux } from '@oclif/core';
|
|
4
|
+
import { color } from '@heroku-cli/color';
|
|
5
|
+
export function readlines(file) {
|
|
6
|
+
return new Promise(function (resolve, reject) {
|
|
7
|
+
const entries = [];
|
|
8
|
+
fs.createReadStream(file).pipe(split())
|
|
9
|
+
.on('data', function (line) {
|
|
10
|
+
line = line.trim();
|
|
11
|
+
if (line) {
|
|
12
|
+
entries.push(line);
|
|
13
|
+
}
|
|
14
|
+
})
|
|
15
|
+
.on('end', function () {
|
|
16
|
+
resolve(entries);
|
|
17
|
+
})
|
|
18
|
+
.on('error', function (err) {
|
|
19
|
+
reject(err);
|
|
20
|
+
});
|
|
21
|
+
});
|
|
22
|
+
}
|
|
23
|
+
export function arrayChunks(array, chunkSize) {
|
|
24
|
+
const chunks = [];
|
|
25
|
+
if (array.length <= chunkSize) {
|
|
26
|
+
chunks.push(array);
|
|
27
|
+
}
|
|
28
|
+
else {
|
|
29
|
+
for (let i = 0; i < array.length; i += chunkSize) {
|
|
30
|
+
chunks.push(array.slice(i, i + chunkSize));
|
|
31
|
+
}
|
|
32
|
+
}
|
|
33
|
+
return chunks;
|
|
34
|
+
}
|
|
35
|
+
export function processSuspensionResult(suspendObject, response) {
|
|
36
|
+
if (response.statusCode === 200) {
|
|
37
|
+
ux.action.stop(color.green(`Suspended ${suspendObject}`));
|
|
38
|
+
}
|
|
39
|
+
else {
|
|
40
|
+
logError(response);
|
|
41
|
+
ux.action.stop(color.bgRed(`Failed to suspend ${suspendObject}`));
|
|
42
|
+
}
|
|
43
|
+
}
|
|
44
|
+
export function processUnsuspendResult(unsuspendObject, response) {
|
|
45
|
+
if (response.statusCode === 200) {
|
|
46
|
+
ux.action.stop(color.green(`Unsuspended ${unsuspendObject}`));
|
|
47
|
+
}
|
|
48
|
+
else {
|
|
49
|
+
logError(response);
|
|
50
|
+
ux.action.stop(color.bgRed(`Failed to unsuspend ${unsuspendObject}`));
|
|
51
|
+
}
|
|
52
|
+
}
|
|
53
|
+
export function logError(response) {
|
|
54
|
+
ux.log(`${color.red(response.status)} \'${response.statusCode}\'.`);
|
|
55
|
+
ux.log(color.red(response.message));
|
|
56
|
+
ux.log(color.red(`Error: ${response.error}`));
|
|
57
|
+
}
|