@p0security/cli 0.3.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 (103) hide show
  1. package/CONTRIBUTING.md +23 -0
  2. package/LICENSE.md +675 -0
  3. package/README.md +201 -0
  4. package/dist/commands/__tests__/login.test.d.ts +1 -0
  5. package/dist/commands/__tests__/login.test.js +75 -0
  6. package/dist/commands/__tests__/ls.test.d.ts +1 -0
  7. package/dist/commands/__tests__/ls.test.js +84 -0
  8. package/dist/commands/__tests__/request.test.d.ts +1 -0
  9. package/dist/commands/__tests__/request.test.js +94 -0
  10. package/dist/commands/__tests__/ssh.test.d.ts +1 -0
  11. package/dist/commands/__tests__/ssh.test.js +107 -0
  12. package/dist/commands/aws/__tests__/__input__/saml-response.d.ts +11 -0
  13. package/dist/commands/aws/__tests__/__input__/saml-response.js +18 -0
  14. package/dist/commands/aws/__tests__/__input__/sts-response.d.ts +11 -0
  15. package/dist/commands/aws/__tests__/__input__/sts-response.js +37 -0
  16. package/dist/commands/aws/__tests__/role.test.d.ts +1 -0
  17. package/dist/commands/aws/__tests__/role.test.js +98 -0
  18. package/dist/commands/aws/index.d.ts +4 -0
  19. package/dist/commands/aws/index.js +26 -0
  20. package/dist/commands/aws/role.d.ts +27 -0
  21. package/dist/commands/aws/role.js +123 -0
  22. package/dist/commands/index.d.ts +2 -0
  23. package/dist/commands/index.js +49 -0
  24. package/dist/commands/login.d.ts +14 -0
  25. package/dist/commands/login.js +93 -0
  26. package/dist/commands/ls.d.ts +4 -0
  27. package/dist/commands/ls.js +78 -0
  28. package/dist/commands/request.d.ts +12 -0
  29. package/dist/commands/request.js +116 -0
  30. package/dist/commands/ssh.d.ts +11 -0
  31. package/dist/commands/ssh.js +154 -0
  32. package/dist/common/auth/oidc.d.ts +4 -0
  33. package/dist/common/auth/oidc.js +18 -0
  34. package/dist/common/auth/server.d.ts +15 -0
  35. package/dist/common/auth/server.js +73 -0
  36. package/dist/common/fetch.d.ts +16 -0
  37. package/dist/common/fetch.js +39 -0
  38. package/dist/common/mime.d.ts +14 -0
  39. package/dist/common/mime.js +17 -0
  40. package/dist/common/xml.d.ts +21 -0
  41. package/dist/common/xml.js +52 -0
  42. package/dist/drivers/__mocks__/auth.d.ts +30 -0
  43. package/dist/drivers/__mocks__/auth.js +46 -0
  44. package/dist/drivers/api.d.ts +3 -0
  45. package/dist/drivers/api.js +69 -0
  46. package/dist/drivers/auth.d.ts +11 -0
  47. package/dist/drivers/auth.js +122 -0
  48. package/dist/drivers/env.d.ts +15 -0
  49. package/dist/drivers/env.js +38 -0
  50. package/dist/drivers/firestore.d.ts +10 -0
  51. package/dist/drivers/firestore.js +53 -0
  52. package/dist/drivers/stdio.d.ts +25 -0
  53. package/dist/drivers/stdio.js +44 -0
  54. package/dist/index.d.ts +1 -0
  55. package/dist/index.js +23 -0
  56. package/dist/middlewares/version.d.ts +8 -0
  57. package/dist/middlewares/version.js +77 -0
  58. package/dist/plugins/__mocks__/login.d.ts +14 -0
  59. package/dist/plugins/__mocks__/login.js +24 -0
  60. package/dist/plugins/aws/__mocks__/assumeRole.d.ts +12 -0
  61. package/dist/plugins/aws/__mocks__/assumeRole.js +20 -0
  62. package/dist/plugins/aws/api.d.ts +12 -0
  63. package/dist/plugins/aws/api.js +16 -0
  64. package/dist/plugins/aws/assumeRole.d.ts +14 -0
  65. package/dist/plugins/aws/assumeRole.js +55 -0
  66. package/dist/plugins/aws/config.d.ts +5 -0
  67. package/dist/plugins/aws/config.js +38 -0
  68. package/dist/plugins/aws/ssm/index.d.ts +18 -0
  69. package/dist/plugins/aws/ssm/index.js +274 -0
  70. package/dist/plugins/aws/ssm/install.d.ts +7 -0
  71. package/dist/plugins/aws/ssm/install.js +133 -0
  72. package/dist/plugins/aws/types.d.ts +54 -0
  73. package/dist/plugins/aws/types.js +2 -0
  74. package/dist/plugins/google/login.d.ts +2 -0
  75. package/dist/plugins/google/login.js +76 -0
  76. package/dist/plugins/login.d.ts +13 -0
  77. package/dist/plugins/login.js +19 -0
  78. package/dist/plugins/okta/aws.d.ts +5 -0
  79. package/dist/plugins/okta/aws.js +42 -0
  80. package/dist/plugins/okta/login.d.ts +8 -0
  81. package/dist/plugins/okta/login.js +165 -0
  82. package/dist/plugins/ssh/types.d.ts +22 -0
  83. package/dist/plugins/ssh/types.js +2 -0
  84. package/dist/public/favicon.ico +0 -0
  85. package/dist/public/redirect-landing.html +40 -0
  86. package/dist/testing/firestore.d.ts +2 -0
  87. package/dist/testing/firestore.js +16 -0
  88. package/dist/testing/yargs.d.ts +12 -0
  89. package/dist/testing/yargs.js +23 -0
  90. package/dist/types/identity.d.ts +23 -0
  91. package/dist/types/identity.js +2 -0
  92. package/dist/types/index.d.ts +11 -0
  93. package/dist/types/index.js +15 -0
  94. package/dist/types/oidc.d.ts +41 -0
  95. package/dist/types/oidc.js +2 -0
  96. package/dist/types/org.d.ts +20 -0
  97. package/dist/types/org.js +2 -0
  98. package/dist/types/request.d.ts +35 -0
  99. package/dist/types/request.js +20 -0
  100. package/dist/util.d.ts +42 -0
  101. package/dist/util.js +87 -0
  102. package/p0 +16 -0
  103. package/package.json +70 -0
@@ -0,0 +1,37 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.stsResponse = void 0;
4
+ /** Copyright © 2024-present P0 Security
5
+
6
+ This file is part of @p0security/cli
7
+
8
+ @p0security/cli is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, version 3 of the License.
9
+
10
+ @p0security/cli is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details.
11
+
12
+ You should have received a copy of the GNU General Public License along with @p0security/cli. If not, see <https://www.gnu.org/licenses/>.
13
+ **/
14
+ exports.stsResponse = `<AssumeRoleWithSAMLResponse xmlns="https://sts.amazonaws.com/doc/2011-06-15/">
15
+ <AssumeRoleWithSAMLResult>
16
+ <Audience>https://signin.aws.amazon.com/saml</Audience>
17
+ <AssumedRoleUser>
18
+ <AssumedRoleId>ABCDEFGHIJLMNOPQRST:test-user@test.com</AssumedRoleId>
19
+ <Arn>arn:aws:sts::1:assumed-role/Role1/test-user@test.com</Arn>
20
+ </AssumedRoleUser>
21
+ <Credentials>
22
+ <AccessKeyId>test-access-key</AccessKeyId>
23
+ <SecretAccessKey>secret-access-key</SecretAccessKey>
24
+ <SessionToken>session-token</SessionToken>
25
+ <Expiration>2024-02-22T00:18:21Z</Expiration>
26
+ </Credentials>
27
+ <Subject>test-user@test.com</Subject>
28
+ <NameQualifier>abcdefghijklmnop</NameQualifier>
29
+ <SourceIdentity>test-user@test.com</SourceIdentity>
30
+ <PackedPolicySize>2</PackedPolicySize>
31
+ <SubjectType>unspecified</SubjectType>
32
+ <Issuer>http://www.okta.com/abc</Issuer>
33
+ </AssumeRoleWithSAMLResult>
34
+ <ResponseMetadata>
35
+ <RequestId>f5b94ad4-f322-4d7b-b568-84f2ec184cd7</RequestId>
36
+ </ResponseMetadata>
37
+ </AssumeRoleWithSAMLResponse>`;
@@ -0,0 +1 @@
1
+ export {};
@@ -0,0 +1,98 @@
1
+ "use strict";
2
+ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
3
+ function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
4
+ return new (P || (P = Promise))(function (resolve, reject) {
5
+ function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
6
+ function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
7
+ function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
8
+ step((generator = generator.apply(thisArg, _arguments || [])).next());
9
+ });
10
+ };
11
+ var __importDefault = (this && this.__importDefault) || function (mod) {
12
+ return (mod && mod.__esModule) ? mod : { "default": mod };
13
+ };
14
+ Object.defineProperty(exports, "__esModule", { value: true });
15
+ /** Copyright © 2024-present P0 Security
16
+
17
+ This file is part of @p0security/cli
18
+
19
+ @p0security/cli is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, version 3 of the License.
20
+
21
+ @p0security/cli is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details.
22
+
23
+ You should have received a copy of the GNU General Public License along with @p0security/cli. If not, see <https://www.gnu.org/licenses/>.
24
+ **/
25
+ const __1 = require("..");
26
+ const stdio_1 = require("../../../drivers/stdio");
27
+ const firestore_1 = require("../../../testing/firestore");
28
+ const yargs_1 = require("../../../testing/yargs");
29
+ const saml_response_1 = require("./__input__/saml-response");
30
+ const sts_response_1 = require("./__input__/sts-response");
31
+ const yargs_2 = __importDefault(require("yargs"));
32
+ jest.mock("fs/promises");
33
+ jest.mock("../../../drivers/auth");
34
+ jest.mock("../../../drivers/stdio");
35
+ jest.mock("typescript", () => (Object.assign(Object.assign({}, jest.requireActual("typescript")), { sys: {
36
+ writeOutputIsTTY: () => true,
37
+ } })));
38
+ const mockFetch = jest.spyOn(global, "fetch");
39
+ const mockPrint1 = stdio_1.print1;
40
+ const mockPrint2 = stdio_1.print2;
41
+ beforeEach(() => {
42
+ jest.clearAllMocks();
43
+ mockFetch.mockImplementation((url) => __awaiter(void 0, void 0, void 0, function* () {
44
+ return ({
45
+ ok: true,
46
+ // This is the token response from fetchSsoWebToken
47
+ json: () => __awaiter(void 0, void 0, void 0, function* () { return ({}); }),
48
+ // This is the XML response from fetchSamlResponse or stsAssumeRole
49
+ text: () => __awaiter(void 0, void 0, void 0, function* () { return url.match(/okta.com/) ? saml_response_1.samlResponse : sts_response_1.stsResponse; }),
50
+ });
51
+ }));
52
+ });
53
+ describe("aws role", () => {
54
+ describe("a single installed account", () => {
55
+ const item = {
56
+ account: {
57
+ id: "1",
58
+ description: "1 (test)",
59
+ },
60
+ state: "installed",
61
+ };
62
+ describe("without Okta SAML", () => {
63
+ (0, firestore_1.mockGetDoc)({ workflows: { items: [item] } });
64
+ describe.each([
65
+ ["ls", "aws role ls"],
66
+ ["assume", "aws role assume Role1"],
67
+ ])("%s", (_, command) => {
68
+ it("should print a friendly error message", () => __awaiter(void 0, void 0, void 0, function* () {
69
+ const error = yield (0, yargs_1.failure)((0, __1.awsCommand)((0, yargs_2.default)()), command);
70
+ expect(error).toMatchInlineSnapshot(`"Account 1 (test) is not configured for Okta SAML login."`);
71
+ }));
72
+ });
73
+ });
74
+ describe("with Okta SAML", () => {
75
+ beforeEach(() => {
76
+ (0, firestore_1.mockGetDoc)({
77
+ workflows: {
78
+ items: [Object.assign(Object.assign({}, item), { uidLocation: { id: "okta_saml_sso" } })],
79
+ },
80
+ });
81
+ });
82
+ describe("assume", () => {
83
+ it("should assume a role", () => __awaiter(void 0, void 0, void 0, function* () {
84
+ yield (0, __1.awsCommand)((0, yargs_2.default)()).parse("aws role assume Role1");
85
+ expect(mockPrint2.mock.calls).toMatchSnapshot("stderr");
86
+ expect(mockPrint1.mock.calls).toMatchSnapshot("stdout");
87
+ }));
88
+ });
89
+ describe("ls", () => {
90
+ it("lists roles", () => __awaiter(void 0, void 0, void 0, function* () {
91
+ yield (0, __1.awsCommand)((0, yargs_2.default)()).parse("aws role ls");
92
+ expect(mockPrint2.mock.calls).toMatchSnapshot("stderr");
93
+ expect(mockPrint1.mock.calls).toMatchSnapshot("stdout");
94
+ }));
95
+ });
96
+ });
97
+ });
98
+ });
@@ -0,0 +1,4 @@
1
+ import yargs from "yargs";
2
+ export declare const awsCommand: (yargs: yargs.Argv<{}>) => yargs.Argv<{
3
+ account: string | undefined;
4
+ }>;
@@ -0,0 +1,26 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.awsCommand = void 0;
4
+ /** Copyright © 2024-present P0 Security
5
+
6
+ This file is part of @p0security/cli
7
+
8
+ @p0security/cli is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, version 3 of the License.
9
+
10
+ @p0security/cli is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details.
11
+
12
+ You should have received a copy of the GNU General Public License along with @p0security/cli. If not, see <https://www.gnu.org/licenses/>.
13
+ **/
14
+ const role_1 = require("./role");
15
+ const awsCommands = [role_1.role];
16
+ const awsArgs = (yargs) => {
17
+ const base = yargs
18
+ .option("account", {
19
+ type: "string",
20
+ describe: "AWS account ID or alias (or set P0_AWS_ACCOUNT)",
21
+ })
22
+ .env("P0_AWS");
23
+ return awsCommands.reduce((m, c) => c(m), base).demandCommand(1);
24
+ };
25
+ const awsCommand = (yargs) => yargs.command("aws", "Execute AWS commands", awsArgs);
26
+ exports.awsCommand = awsCommand;
@@ -0,0 +1,27 @@
1
+ import { AwsItemConfig, AwsOktaSamlUidLocation } from "../../plugins/aws/types";
2
+ import { Authn } from "../../types/identity";
3
+ import yargs from "yargs";
4
+ export declare const role: (yargs: yargs.Argv<{
5
+ account: string | undefined;
6
+ }>) => yargs.Argv<{
7
+ account: string | undefined;
8
+ } & {
9
+ role: string;
10
+ }>;
11
+ /** Retrieves the configured Okta SAML response for the specified account
12
+ *
13
+ * If no account is passed, and the organization only has one account configured,
14
+ * assumes that account.
15
+ */
16
+ export declare const initOktaSaml: (authn: Authn, account: string | undefined) => Promise<{
17
+ samlResponse: string;
18
+ config: AwsItemConfig & {
19
+ uidLocation: AwsOktaSamlUidLocation;
20
+ };
21
+ account: string;
22
+ }>;
23
+ /** Extracts all roles from a SAML assertion */
24
+ export declare const rolesFromSaml: (account: string, saml: string) => {
25
+ arns: string[];
26
+ roles: string[];
27
+ };
@@ -0,0 +1,123 @@
1
+ "use strict";
2
+ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
3
+ function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
4
+ return new (P || (P = Promise))(function (resolve, reject) {
5
+ function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
6
+ function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
7
+ function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
8
+ step((generator = generator.apply(thisArg, _arguments || [])).next());
9
+ });
10
+ };
11
+ Object.defineProperty(exports, "__esModule", { value: true });
12
+ exports.rolesFromSaml = exports.initOktaSaml = exports.role = void 0;
13
+ /** Copyright © 2024-present P0 Security
14
+
15
+ This file is part of @p0security/cli
16
+
17
+ @p0security/cli is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, version 3 of the License.
18
+
19
+ @p0security/cli is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details.
20
+
21
+ You should have received a copy of the GNU General Public License along with @p0security/cli. If not, see <https://www.gnu.org/licenses/>.
22
+ **/
23
+ const xml_1 = require("../../common/xml");
24
+ const auth_1 = require("../../drivers/auth");
25
+ const firestore_1 = require("../../drivers/firestore");
26
+ const stdio_1 = require("../../drivers/stdio");
27
+ const config_1 = require("../../plugins/aws/config");
28
+ const aws_1 = require("../../plugins/okta/aws");
29
+ const login_1 = require("../../plugins/okta/login");
30
+ const lodash_1 = require("lodash");
31
+ const typescript_1 = require("typescript");
32
+ const role = (yargs) => yargs.command("role", "Interact with AWS roles", (yargs) => yargs
33
+ .command("ls", "List available AWS roles", lodash_1.identity,
34
+ // TODO: select based on uidLocation
35
+ (0, firestore_1.guard)(oktaAwsListRoles))
36
+ .command("assume <role>", "Assume an AWS role", (y) => y.positional("role", {
37
+ type: "string",
38
+ demandOption: true,
39
+ describe: "An AWS role name",
40
+ }),
41
+ // TODO: select based on uidLocation
42
+ (0, firestore_1.guard)(oktaAwsAssumeRole))
43
+ .demandCommand(1));
44
+ exports.role = role;
45
+ const isOktaSamlConfig = (config) => { var _a; return ((_a = config.uidLocation) === null || _a === void 0 ? void 0 : _a.id) === "okta_saml_sso"; };
46
+ /** Retrieves the configured Okta SAML response for the specified account
47
+ *
48
+ * If no account is passed, and the organization only has one account configured,
49
+ * assumes that account.
50
+ */
51
+ const initOktaSaml = (authn, account) => __awaiter(void 0, void 0, void 0, function* () {
52
+ const { identity, config } = yield (0, config_1.getAwsConfig)(authn, account);
53
+ if (!isOktaSamlConfig(config))
54
+ throw `Account ${config.account.description} is not configured for Okta SAML login.`;
55
+ const samlResponse = yield (0, login_1.getSamlResponse)(identity, config.uidLocation);
56
+ return {
57
+ samlResponse,
58
+ config,
59
+ account: config.account.id,
60
+ };
61
+ });
62
+ exports.initOktaSaml = initOktaSaml;
63
+ /** Extracts all roles from a SAML assertion */
64
+ const rolesFromSaml = (account, saml) => {
65
+ var _a;
66
+ const samlText = Buffer.from(saml, "base64").toString("ascii");
67
+ const samlObject = (0, xml_1.parseXml)(samlText);
68
+ const samlAttributes = samlObject["saml2p:Response"]["saml2:Assertion"]["saml2:AttributeStatement"]["saml2:Attribute"];
69
+ const roleAttribute = samlAttributes.find((a) => a._attributes.Name === "https://aws.amazon.com/SAML/Attributes/Role");
70
+ // Format:
71
+ // 'arn:aws:iam::391052057035:saml-provider/p0dev-ext_okta_sso,arn:aws:iam::391052057035:role/path/to/role/SSOAmazonS3FullAccess'
72
+ const arns = (_a = (0, lodash_1.flatten)([roleAttribute === null || roleAttribute === void 0 ? void 0 : roleAttribute["saml2:AttributeValue"]])) === null || _a === void 0 ? void 0 : _a.map((r) => r.split(",")[1]);
73
+ const roles = arns
74
+ .filter((r) => r.startsWith(`arn:aws:iam::${account}:role/`))
75
+ .map((r) => r.split("/").slice(1).join("/"));
76
+ return { arns, roles };
77
+ };
78
+ exports.rolesFromSaml = rolesFromSaml;
79
+ /** Assumes a role in AWS via Okta SAML federation.
80
+ *
81
+ * Prerequisites:
82
+ * - AWS is configured with a SAML identity provider
83
+ * - This identity provider is integrated with a
84
+ * "AWS SAML Account Federation" app in Okta
85
+ * - The AWS SAML identity provider name, Okta domain,
86
+ * and Okta SAML app identifier are all contained in
87
+ * the user's identity blob
88
+ * - The requested role is assigned to the user in Okta
89
+ */
90
+ const oktaAwsAssumeRole = (args) => __awaiter(void 0, void 0, void 0, function* () {
91
+ var _a;
92
+ const authn = yield (0, auth_1.authenticate)();
93
+ const awsCredential = yield (0, aws_1.assumeRoleWithOktaSaml)(authn, args);
94
+ const isTty = (_a = typescript_1.sys.writeOutputIsTTY) === null || _a === void 0 ? void 0 : _a.call(typescript_1.sys);
95
+ if (isTty)
96
+ (0, stdio_1.print2)("Execute the following commands:\n");
97
+ const indent = isTty ? " " : "";
98
+ (0, stdio_1.print1)(Object.entries(awsCredential)
99
+ .map(([key, value]) => `${indent}export ${key}=${value}`)
100
+ .join("\n"));
101
+ if (isTty)
102
+ (0, stdio_1.print2)(`
103
+ Or, populate these environment variables using BASH command substitution:
104
+
105
+ $(p0 aws${args.account ? ` --account ${args.account}` : ""} role assume ${args.role})
106
+ `);
107
+ });
108
+ /** Lists assigned AWS roles for this user on this account */
109
+ const oktaAwsListRoles = (args) => __awaiter(void 0, void 0, void 0, function* () {
110
+ var _b;
111
+ const authn = yield (0, auth_1.authenticate)();
112
+ const { account, samlResponse } = yield (0, exports.initOktaSaml)(authn, args.account);
113
+ const { arns, roles } = (0, exports.rolesFromSaml)(account, samlResponse);
114
+ const isTty = (_b = typescript_1.sys.writeOutputIsTTY) === null || _b === void 0 ? void 0 : _b.call(typescript_1.sys);
115
+ if (isTty)
116
+ (0, stdio_1.print2)(`Your available roles for account ${account}:`);
117
+ if (!(roles === null || roles === void 0 ? void 0 : roles.length)) {
118
+ const accounts = (0, lodash_1.uniq)(arns.map((a) => a.split(":")[4])).sort();
119
+ throw `No roles found. You have roles on these accounts:\n${accounts.join("\n")}`;
120
+ }
121
+ const indent = isTty ? " " : "";
122
+ (0, stdio_1.print1)(roles.map((r) => `${indent}${r}`).join("\n"));
123
+ });
@@ -0,0 +1,2 @@
1
+ import yargs from "yargs";
2
+ export declare const cli: yargs.Argv<{}>;
@@ -0,0 +1,49 @@
1
+ "use strict";
2
+ var __importDefault = (this && this.__importDefault) || function (mod) {
3
+ return (mod && mod.__esModule) ? mod : { "default": mod };
4
+ };
5
+ Object.defineProperty(exports, "__esModule", { value: true });
6
+ exports.cli = void 0;
7
+ /** Copyright © 2024-present P0 Security
8
+
9
+ This file is part of @p0security/cli
10
+
11
+ @p0security/cli is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, version 3 of the License.
12
+
13
+ @p0security/cli is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details.
14
+
15
+ You should have received a copy of the GNU General Public License along with @p0security/cli. If not, see <https://www.gnu.org/licenses/>.
16
+ **/
17
+ const stdio_1 = require("../drivers/stdio");
18
+ const version_1 = require("../middlewares/version");
19
+ const aws_1 = require("./aws");
20
+ const login_1 = require("./login");
21
+ const ls_1 = require("./ls");
22
+ const request_1 = require("./request");
23
+ const ssh_1 = require("./ssh");
24
+ const lodash_1 = require("lodash");
25
+ const typescript_1 = require("typescript");
26
+ const yargs_1 = __importDefault(require("yargs"));
27
+ const helpers_1 = require("yargs/helpers");
28
+ const commands = [
29
+ aws_1.awsCommand,
30
+ login_1.loginCommand,
31
+ ls_1.lsCommand,
32
+ request_1.requestCommand,
33
+ ssh_1.sshCommand,
34
+ ];
35
+ exports.cli = commands
36
+ .reduce((m, c) => c(m), (0, yargs_1.default)((0, helpers_1.hideBin)(process.argv)))
37
+ .middleware(version_1.checkVersion)
38
+ .strict()
39
+ .version(lodash_1.VERSION)
40
+ .demandCommand(1)
41
+ .fail((message, error, yargs) => {
42
+ if (error)
43
+ (0, stdio_1.print2)(error);
44
+ else {
45
+ (0, stdio_1.print2)(yargs.help());
46
+ (0, stdio_1.print2)(`\n${message}`);
47
+ }
48
+ typescript_1.sys.exit(1);
49
+ });
@@ -0,0 +1,14 @@
1
+ import yargs from "yargs";
2
+ /** Logs in the user
3
+ *
4
+ * Currently only supports login to a single organization. Login credentials, together
5
+ * with organization details, are saved to {@link IDENTITY_FILE_PATH}.
6
+ */
7
+ export declare const login: (args: {
8
+ org: string;
9
+ }, options?: {
10
+ skipAuthenticate?: boolean;
11
+ }) => Promise<void>;
12
+ export declare const loginCommand: (yargs: yargs.Argv<{}>) => yargs.Argv<{
13
+ org: string;
14
+ }>;
@@ -0,0 +1,93 @@
1
+ "use strict";
2
+ var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
3
+ if (k2 === undefined) k2 = k;
4
+ var desc = Object.getOwnPropertyDescriptor(m, k);
5
+ if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
6
+ desc = { enumerable: true, get: function() { return m[k]; } };
7
+ }
8
+ Object.defineProperty(o, k2, desc);
9
+ }) : (function(o, m, k, k2) {
10
+ if (k2 === undefined) k2 = k;
11
+ o[k2] = m[k];
12
+ }));
13
+ var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
14
+ Object.defineProperty(o, "default", { enumerable: true, value: v });
15
+ }) : function(o, v) {
16
+ o["default"] = v;
17
+ });
18
+ var __importStar = (this && this.__importStar) || function (mod) {
19
+ if (mod && mod.__esModule) return mod;
20
+ var result = {};
21
+ if (mod != null) for (var k in mod) if (k !== "default" && Object.prototype.hasOwnProperty.call(mod, k)) __createBinding(result, mod, k);
22
+ __setModuleDefault(result, mod);
23
+ return result;
24
+ };
25
+ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
26
+ function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
27
+ return new (P || (P = Promise))(function (resolve, reject) {
28
+ function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
29
+ function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
30
+ function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
31
+ step((generator = generator.apply(thisArg, _arguments || [])).next());
32
+ });
33
+ };
34
+ Object.defineProperty(exports, "__esModule", { value: true });
35
+ exports.loginCommand = exports.login = void 0;
36
+ /** Copyright © 2024-present P0 Security
37
+
38
+ This file is part of @p0security/cli
39
+
40
+ @p0security/cli is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, version 3 of the License.
41
+
42
+ @p0security/cli is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details.
43
+
44
+ You should have received a copy of the GNU General Public License along with @p0security/cli. If not, see <https://www.gnu.org/licenses/>.
45
+ **/
46
+ const auth_1 = require("../drivers/auth");
47
+ const firestore_1 = require("../drivers/firestore");
48
+ const stdio_1 = require("../drivers/stdio");
49
+ const login_1 = require("../plugins/login");
50
+ const firestore_2 = require("firebase/firestore");
51
+ const fs = __importStar(require("fs/promises"));
52
+ const path = __importStar(require("path"));
53
+ /** Logs in the user
54
+ *
55
+ * Currently only supports login to a single organization. Login credentials, together
56
+ * with organization details, are saved to {@link IDENTITY_FILE_PATH}.
57
+ */
58
+ const login = (args, options) => __awaiter(void 0, void 0, void 0, function* () {
59
+ const orgDoc = yield (0, firestore_2.getDoc)((0, firestore_1.doc)(`orgs/${args.org}`));
60
+ const orgData = orgDoc.data();
61
+ if (!orgData)
62
+ throw "Could not find organization";
63
+ const orgWithSlug = Object.assign(Object.assign({}, orgData), { slug: args.org });
64
+ const plugin = orgWithSlug === null || orgWithSlug === void 0 ? void 0 : orgWithSlug.ssoProvider;
65
+ const loginFn = login_1.pluginLoginMap[plugin];
66
+ if (!loginFn)
67
+ throw "Unsupported login for your organization";
68
+ const tokenResponse = yield loginFn(orgWithSlug);
69
+ yield writeIdentity(orgWithSlug, tokenResponse);
70
+ // validate auth
71
+ if (!(options === null || options === void 0 ? void 0 : options.skipAuthenticate))
72
+ yield (0, auth_1.authenticate)({ noRefresh: true });
73
+ (0, stdio_1.print2)(`You are now logged in, and can use the p0 CLI.`);
74
+ });
75
+ exports.login = login;
76
+ const writeIdentity = (org, credential) => __awaiter(void 0, void 0, void 0, function* () {
77
+ const expires_at = Date.now() * 1e-3 + credential.expires_in - 1; // Add 1 second safety margin
78
+ (0, stdio_1.print2)(`Saving authorization to ${auth_1.IDENTITY_FILE_PATH}.`);
79
+ const dir = path.dirname(auth_1.IDENTITY_FILE_PATH);
80
+ yield fs.mkdir(dir, { recursive: true });
81
+ yield fs.writeFile(auth_1.IDENTITY_FILE_PATH, JSON.stringify({
82
+ credential: Object.assign(Object.assign({}, credential), { expires_at }),
83
+ org,
84
+ }, null, 2), {
85
+ mode: "600",
86
+ });
87
+ });
88
+ const loginCommand = (yargs) => yargs.command("login <org>", "Log in to p0 using a web browser", (yargs) => yargs.positional("org", {
89
+ demandOption: true,
90
+ type: "string",
91
+ describe: "Your P0 organization ID",
92
+ }), (0, firestore_1.guard)(exports.login));
93
+ exports.loginCommand = loginCommand;
@@ -0,0 +1,4 @@
1
+ import yargs from "yargs";
2
+ export declare const lsCommand: (yargs: yargs.Argv<{}>) => yargs.Argv<{
3
+ arguments: string[];
4
+ }>;
@@ -0,0 +1,78 @@
1
+ "use strict";
2
+ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
3
+ function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
4
+ return new (P || (P = Promise))(function (resolve, reject) {
5
+ function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
6
+ function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
7
+ function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
8
+ step((generator = generator.apply(thisArg, _arguments || [])).next());
9
+ });
10
+ };
11
+ var __importDefault = (this && this.__importDefault) || function (mod) {
12
+ return (mod && mod.__esModule) ? mod : { "default": mod };
13
+ };
14
+ Object.defineProperty(exports, "__esModule", { value: true });
15
+ exports.lsCommand = void 0;
16
+ /** Copyright © 2024-present P0 Security
17
+
18
+ This file is part of @p0security/cli
19
+
20
+ @p0security/cli is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, version 3 of the License.
21
+
22
+ @p0security/cli is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details.
23
+
24
+ You should have received a copy of the GNU General Public License along with @p0security/cli. If not, see <https://www.gnu.org/licenses/>.
25
+ **/
26
+ const api_1 = require("../drivers/api");
27
+ const auth_1 = require("../drivers/auth");
28
+ const firestore_1 = require("../drivers/firestore");
29
+ const stdio_1 = require("../drivers/stdio");
30
+ const lodash_1 = require("lodash");
31
+ const pluralize_1 = __importDefault(require("pluralize"));
32
+ const lsArgs = (yargs) => yargs
33
+ .parserConfiguration({ "unknown-options-as-args": true })
34
+ .option("arguments", {
35
+ array: true,
36
+ string: true,
37
+ default: [],
38
+ });
39
+ const lsCommand = (yargs) => yargs.command("ls [arguments..]", "List request-command arguments", lsArgs, (0, firestore_1.guard)(ls));
40
+ exports.lsCommand = lsCommand;
41
+ const ls = (args) => __awaiter(void 0, void 0, void 0, function* () {
42
+ const authn = yield (0, auth_1.authenticate)();
43
+ const data = yield (0, api_1.fetchCommand)(authn, args, [
44
+ "ls",
45
+ ...args.arguments,
46
+ ]);
47
+ const allArguments = [...args._, ...args.arguments];
48
+ if (data && "ok" in data && data.ok) {
49
+ const label = (0, pluralize_1.default)(data.arg);
50
+ if (data.items.length === 0) {
51
+ (0, stdio_1.print2)(`No ${label}`);
52
+ return;
53
+ }
54
+ const truncationPart = data.isTruncated
55
+ ? ` the first ${data.items.length}`
56
+ : "";
57
+ const postfixPart = data.term
58
+ ? ` matching '${data.term}'`
59
+ : data.isTruncated
60
+ ? ` (use \`p0
61
+ ${allArguments.join(" ")} <like>\` to narrow results)`
62
+ : "";
63
+ (0, stdio_1.print2)(`Showing${truncationPart} ${label}${postfixPart}:`);
64
+ const isSameValue = data.items.every((i) => !i.group && i.key === i.value);
65
+ const maxLength = (0, lodash_1.max)(data.items.map((i) => i.key.length)) || 0;
66
+ for (const item of data.items) {
67
+ const tagPart = `${item.group ? `${item.group} / ` : ""}${item.value}`;
68
+ (0, stdio_1.print1)(isSameValue
69
+ ? item.key
70
+ : maxLength > 30
71
+ ? `${item.key}\n ${stdio_1.Ansi.Dim}${tagPart}${stdio_1.Ansi.Reset}`
72
+ : `${item.key.padEnd(maxLength)}${stdio_1.Ansi.Dim} - ${tagPart}${stdio_1.Ansi.Reset}`);
73
+ }
74
+ }
75
+ else {
76
+ throw data;
77
+ }
78
+ });
@@ -0,0 +1,12 @@
1
+ import { Authn } from "../types/identity";
2
+ import { RequestResponse } from "../types/request";
3
+ import yargs from "yargs";
4
+ export declare const requestCommand: (yargs: yargs.Argv<{}>) => yargs.Argv<{
5
+ arguments: string[];
6
+ }>;
7
+ export declare const request: (args: yargs.ArgumentsCamelCase<{
8
+ arguments: string[];
9
+ wait?: boolean;
10
+ }>, authn?: Authn, options?: {
11
+ message?: "all" | "approval-required" | "none";
12
+ }) => Promise<RequestResponse | undefined>;