@p0security/cli 0.6.2 → 0.8.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.
@@ -22,6 +22,7 @@ This file is part of @p0security/cli
22
22
 
23
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
24
  **/
25
+ const keys_1 = require("../../common/__mocks__/keys");
25
26
  const api_1 = require("../../drivers/api");
26
27
  const stdio_1 = require("../../drivers/stdio");
27
28
  const ssm_1 = require("../../plugins/aws/ssm");
@@ -35,10 +36,28 @@ jest.mock("../../drivers/api");
35
36
  jest.mock("../../drivers/auth");
36
37
  jest.mock("../../drivers/stdio");
37
38
  jest.mock("../../plugins/aws/ssm");
39
+ jest.mock("../../common/keys");
38
40
  const mockFetchCommand = api_1.fetchCommand;
39
- const mockSsm = ssm_1.ssm;
41
+ const mockSshOrScp = ssm_1.sshOrScp;
40
42
  const mockPrint1 = stdio_1.print1;
41
43
  const mockPrint2 = stdio_1.print2;
44
+ const MOCK_REQUEST = {
45
+ status: "DONE",
46
+ generated: {
47
+ name: "name",
48
+ ssh: {
49
+ linuxUserName: "linuxUserName",
50
+ publicKey: keys_1.TEST_PUBLIC_KEY,
51
+ },
52
+ },
53
+ permission: {
54
+ spec: {
55
+ instanceId: "instanceId",
56
+ accountId: "accountId",
57
+ region: "region",
58
+ },
59
+ },
60
+ };
42
61
  (0, firestore_1.mockGetDoc)({
43
62
  "iam-write": {
44
63
  ["aws:test-account"]: {
@@ -46,7 +65,6 @@ const mockPrint2 = stdio_1.print2;
46
65
  },
47
66
  },
48
67
  });
49
- mockSsm.mockResolvedValue({});
50
68
  describe("ssh", () => {
51
69
  describe.each([
52
70
  ["persistent", true],
@@ -69,9 +87,6 @@ describe("ssh", () => {
69
87
  },
70
88
  },
71
89
  },
72
- generated: {
73
- documentName: "documentName",
74
- },
75
90
  },
76
91
  });
77
92
  });
@@ -97,20 +112,31 @@ describe("ssh", () => {
97
112
  yield Promise.race([wait, promise]);
98
113
  yield expect(wait).resolves.toBeUndefined();
99
114
  }));
100
- it("should call ssm", () => __awaiter(void 0, void 0, void 0, function* () {
101
- const promise = (0, ssh_1.sshCommand)((0, yargs_1.default)()).parse(`ssh some-instance`);
115
+ it("should call sshOrScp with non-interactive command", () => __awaiter(void 0, void 0, void 0, function* () {
116
+ const promise = (0, ssh_1.sshCommand)((0, yargs_1.default)()).parse(`ssh some-instance do something`);
102
117
  yield (0, util_1.sleep)(100); // Need to wait for listen before trigger in tests
103
118
  firestore_2.onSnapshot.trigger({
104
119
  status: "APPROVED",
105
120
  });
106
121
  yield (0, util_1.sleep)(100); // Need to wait for listen before trigger in tests
122
+ firestore_2.onSnapshot.trigger(MOCK_REQUEST);
123
+ yield expect(promise).resolves.toBeDefined();
124
+ expect(mockPrint2.mock.calls).toMatchSnapshot("stderr");
125
+ expect(mockPrint1).not.toHaveBeenCalled();
126
+ expect(mockSshOrScp).toHaveBeenCalled();
127
+ }));
128
+ it("should call sshOrScp with interactive session", () => __awaiter(void 0, void 0, void 0, function* () {
129
+ const promise = (0, ssh_1.sshCommand)((0, yargs_1.default)()).parse(`ssh some-instance`);
130
+ yield (0, util_1.sleep)(100); // Need to wait for listen before trigger in tests
107
131
  firestore_2.onSnapshot.trigger({
108
- status: "DONE",
132
+ status: "APPROVED",
109
133
  });
134
+ yield (0, util_1.sleep)(100); // Need to wait for listen before trigger in tests
135
+ firestore_2.onSnapshot.trigger(MOCK_REQUEST);
110
136
  yield expect(promise).resolves.toBeDefined();
111
137
  expect(mockPrint2.mock.calls).toMatchSnapshot("stderr");
112
138
  expect(mockPrint1).not.toHaveBeenCalled();
113
- expect(mockSsm).toHaveBeenCalled();
139
+ expect(mockSshOrScp).toHaveBeenCalled();
114
140
  }));
115
141
  });
116
142
  });
@@ -0,0 +1,10 @@
1
+ import { AllowResponse } from "../types/allow";
2
+ import { Authn } from "../types/identity";
3
+ import yargs from "yargs";
4
+ export declare const allowCommand: (yargs: yargs.Argv<{}>) => yargs.Argv<{
5
+ arguments: string[];
6
+ }>;
7
+ export declare const allow: (args: yargs.ArgumentsCamelCase<{
8
+ arguments: string[];
9
+ wait?: boolean;
10
+ }>, authn?: Authn) => Promise<AllowResponse | undefined>;
@@ -0,0 +1,57 @@
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.allow = exports.allowCommand = 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 api_1 = require("../drivers/api");
24
+ const auth_1 = require("../drivers/auth");
25
+ const firestore_1 = require("../drivers/firestore");
26
+ const stdio_1 = require("../drivers/stdio");
27
+ const allowArgs = (yargs) => yargs
28
+ .parserConfiguration({ "unknown-options-as-args": true })
29
+ .help(false) // Turn off help in order to forward the --help command to the backend so P0 can provide the available requestable resources
30
+ .option("wait", {
31
+ alias: "w",
32
+ boolean: true,
33
+ default: false,
34
+ describe: "Block until the command is completed",
35
+ })
36
+ .option("arguments", {
37
+ array: true,
38
+ string: true,
39
+ default: [],
40
+ });
41
+ const allowCommand = (yargs) => yargs.command("allow [arguments..]", "Create standing access for a resource", allowArgs, (0, firestore_1.guard)(exports.allow));
42
+ exports.allowCommand = allowCommand;
43
+ const allow = (args, authn) => __awaiter(void 0, void 0, void 0, function* () {
44
+ const resolvedAuthn = authn !== null && authn !== void 0 ? authn : (yield (0, auth_1.authenticate)());
45
+ const data = yield (0, api_1.fetchCommand)(resolvedAuthn, args, [
46
+ "allow",
47
+ ...args.arguments,
48
+ ]);
49
+ if (data && "ok" in data && "message" in data && data.ok) {
50
+ (0, stdio_1.print2)(data.message);
51
+ return data;
52
+ }
53
+ else {
54
+ throw data;
55
+ }
56
+ });
57
+ exports.allow = allow;
@@ -16,6 +16,7 @@ You should have received a copy of the GNU General Public License along with @p0
16
16
  **/
17
17
  const stdio_1 = require("../drivers/stdio");
18
18
  const version_1 = require("../middlewares/version");
19
+ const allow_1 = require("./allow");
19
20
  const aws_1 = require("./aws");
20
21
  const login_1 = require("./login");
21
22
  const ls_1 = require("./ls");
@@ -30,6 +31,7 @@ const commands = [
30
31
  login_1.loginCommand,
31
32
  ls_1.lsCommand,
32
33
  request_1.requestCommand,
34
+ allow_1.allowCommand,
33
35
  ssh_1.sshCommand,
34
36
  scp_1.scpCommand,
35
37
  ];
@@ -8,9 +8,6 @@ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, ge
8
8
  step((generator = generator.apply(thisArg, _arguments || [])).next());
9
9
  });
10
10
  };
11
- var __importDefault = (this && this.__importDefault) || function (mod) {
12
- return (mod && mod.__esModule) ? mod : { "default": mod };
13
- };
14
11
  Object.defineProperty(exports, "__esModule", { value: true });
15
12
  exports.scpCommand = void 0;
16
13
  /** Copyright © 2024-present P0 Security
@@ -23,12 +20,10 @@ This file is part of @p0security/cli
23
20
 
24
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/>.
25
22
  **/
26
- const api_1 = require("../drivers/api");
27
23
  const auth_1 = require("../drivers/auth");
28
24
  const firestore_1 = require("../drivers/firestore");
29
25
  const ssm_1 = require("../plugins/aws/ssm");
30
26
  const shared_1 = require("./shared");
31
- const node_forge_1 = __importDefault(require("node-forge"));
32
27
  const scpCommand = (yargs) => yargs.command("scp <source> <destination>",
33
28
  // TODO (ENG-1930): support scp across multiple remote hosts.
34
29
  "SCP copies files between a local and remote host.", (yargs) => yargs
@@ -61,7 +56,7 @@ const scpCommand = (yargs) => yargs.command("scp <source> <destination>",
61
56
  })
62
57
  .option("debug", {
63
58
  type: "boolean",
64
- describe: "Print debug information, dangerous for sensitive data",
59
+ describe: "Print debug information. The ssh-agent subprocess is not terminated automatically.",
65
60
  }), (0, firestore_1.guard)(scpAction));
66
61
  exports.scpCommand = scpCommand;
67
62
  /** Transfers files between a local and remote hosts using SSH.
@@ -74,19 +69,15 @@ const scpAction = (args) => __awaiter(void 0, void 0, void 0, function* () {
74
69
  if (!host) {
75
70
  throw "Could not determine host identifier from source or destination";
76
71
  }
77
- const requestId = yield (0, shared_1.provisionRequest)(authn, args, host);
78
- if (!requestId) {
72
+ const result = yield (0, shared_1.provisionRequest)(authn, args, host);
73
+ if (!result) {
79
74
  throw "Server did not return a request id. Please contact support@p0.dev for assistance.";
80
75
  }
81
- const { publicKey, privateKey } = createKeyPair();
82
- const result = yield (0, api_1.fetchExerciseGrant)(authn, {
83
- requestId,
84
- destination: host,
85
- publicKey,
86
- });
76
+ const { request, privateKey } = result;
77
+ const data = (0, shared_1.requestToSsh)(request);
87
78
  // replace the host with the linuxUserName@instanceId
88
- const { source, destination } = replaceHostWithInstance(result, args);
89
- yield (0, ssm_1.scp)(authn, result, Object.assign(Object.assign({}, args), { source,
79
+ const { source, destination } = replaceHostWithInstance(data, args);
80
+ yield (0, ssm_1.sshOrScp)(authn, data, Object.assign(Object.assign({}, args), { source,
90
81
  destination }), privateKey);
91
82
  });
92
83
  /** If a path is not explicitly local, use this pattern to determine if it's remote */
@@ -110,16 +101,10 @@ const replaceHostWithInstance = (result, args) => {
110
101
  let source = args.source;
111
102
  let destination = args.destination;
112
103
  if (isExplicitlyRemote(source)) {
113
- source = `${result.linuxUserName}@${result.instance.id}:${source.split(":")[1]}`;
104
+ source = `${result.linuxUserName}@${result.id}:${source.split(":")[1]}`;
114
105
  }
115
106
  if (isExplicitlyRemote(destination)) {
116
- destination = `${result.linuxUserName}@${result.instance.id}:${destination.split(":")[1]}`;
107
+ destination = `${result.linuxUserName}@${result.id}:${destination.split(":")[1]}`;
117
108
  }
118
109
  return { source, destination };
119
110
  };
120
- const createKeyPair = () => {
121
- const rsaKeyPair = node_forge_1.default.pki.rsa.generateKeyPair({ bits: 2048 });
122
- const privateKey = node_forge_1.default.pki.privateKeyToPem(rsaKeyPair.privateKey);
123
- const publicKey = node_forge_1.default.ssh.publicKeyToOpenSSH(rsaKeyPair.publicKey);
124
- return { publicKey, privateKey };
125
- };
@@ -1,17 +1,13 @@
1
+ import { AwsSsh } from "../plugins/aws/types";
1
2
  import { Authn } from "../types/identity";
3
+ import { Request } from "../types/request";
2
4
  import yargs from "yargs";
3
- export declare type ExerciseGrantResponse = {
4
- documentName: string;
5
+ export declare type SshRequest = {
5
6
  linuxUserName: string;
6
- ok: true;
7
7
  role: string;
8
- instance: {
9
- arn: string;
10
- accountId: string;
11
- region: string;
12
- id: string;
13
- name?: string;
14
- };
8
+ accountId: string;
9
+ region: string;
10
+ id: string;
15
11
  };
16
12
  export declare type BaseSshCommandArgs = {
17
13
  sudo?: boolean;
@@ -29,7 +25,14 @@ export declare type SshCommandArgs = BaseSshCommandArgs & {
29
25
  destination: string;
30
26
  L?: string;
31
27
  N?: boolean;
28
+ A?: boolean;
32
29
  arguments: string[];
33
30
  command?: string;
31
+ debug?: boolean;
34
32
  };
35
- export declare const provisionRequest: (authn: Authn, args: yargs.ArgumentsCamelCase<BaseSshCommandArgs>, destination: string) => Promise<string | undefined>;
33
+ export declare const provisionRequest: (authn: Authn, args: yargs.ArgumentsCamelCase<BaseSshCommandArgs>, destination: string) => Promise<{
34
+ request: Request<AwsSsh>;
35
+ publicKey: string;
36
+ privateKey: string;
37
+ } | undefined>;
38
+ export declare const requestToSsh: (request: AwsSsh) => SshRequest;
@@ -9,7 +9,7 @@ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, ge
9
9
  });
10
10
  };
11
11
  Object.defineProperty(exports, "__esModule", { value: true });
12
- exports.provisionRequest = void 0;
12
+ exports.requestToSsh = exports.provisionRequest = void 0;
13
13
  /** Copyright © 2024-present P0 Security
14
14
 
15
15
  This file is part of @p0security/cli
@@ -20,6 +20,7 @@ This file is part of @p0security/cli
20
20
 
21
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
22
  **/
23
+ const keys_1 = require("../common/keys");
23
24
  const firestore_1 = require("../drivers/firestore");
24
25
  const stdio_1 = require("../drivers/stdio");
25
26
  const request_1 = require("../types/request");
@@ -78,10 +79,13 @@ const waitForProvisioning = (authn, requestId) => __awaiter(void 0, void 0, void
78
79
  });
79
80
  const provisionRequest = (authn, args, destination) => __awaiter(void 0, void 0, void 0, function* () {
80
81
  yield validateSshInstall(authn);
82
+ const { publicKey, privateKey } = yield (0, keys_1.createKeyPair)();
81
83
  const response = yield (0, request_2.request)(Object.assign(Object.assign({}, (0, lodash_1.pick)(args, "$0", "_")), { arguments: [
82
84
  "ssh",
83
85
  "session",
84
86
  destination,
87
+ "--public-key",
88
+ publicKey,
85
89
  // Prefix is required because the backend uses it to determine that this is an AWS request
86
90
  "--provider",
87
91
  "aws",
@@ -96,7 +100,20 @@ const provisionRequest = (authn, args, destination) => __awaiter(void 0, void 0,
96
100
  const { id, isPreexisting } = response;
97
101
  if (!isPreexisting)
98
102
  (0, stdio_1.print2)("Waiting for access to be provisioned");
99
- yield waitForProvisioning(authn, id);
100
- return id;
103
+ const provisionedRequest = yield waitForProvisioning(authn, id);
104
+ if (provisionedRequest.generated.ssh.publicKey !== publicKey) {
105
+ throw "Public key mismatch. Please revoke the request and try again.";
106
+ }
107
+ return { request: provisionedRequest, publicKey, privateKey };
101
108
  });
102
109
  exports.provisionRequest = provisionRequest;
110
+ const requestToSsh = (request) => {
111
+ return {
112
+ id: request.permission.spec.instanceId,
113
+ accountId: request.permission.spec.accountId,
114
+ region: request.permission.spec.region,
115
+ role: request.generated.name,
116
+ linuxUserName: request.generated.ssh.linuxUserName,
117
+ };
118
+ };
119
+ exports.requestToSsh = requestToSsh;
@@ -20,13 +20,10 @@ This file is part of @p0security/cli
20
20
 
21
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
22
  **/
23
- const api_1 = require("../drivers/api");
24
23
  const auth_1 = require("../drivers/auth");
25
24
  const firestore_1 = require("../drivers/firestore");
26
25
  const ssm_1 = require("../plugins/aws/ssm");
27
26
  const shared_1 = require("./shared");
28
- // Matches strings with the pattern "digits:digits" (e.g. 1234:5678)
29
- const LOCAL_PORT_FORWARD_PATTERN = /^\d+:\d+$/;
30
27
  const sshCommand = (yargs) => yargs.command("ssh <destination> [command [arguments..]]", "SSH into a virtual machine", (yargs) => yargs
31
28
  .positional("destination", {
32
29
  type: "string",
@@ -45,22 +42,19 @@ const sshCommand = (yargs) => yargs.command("ssh <destination> [command [argumen
45
42
  array: true,
46
43
  string: true,
47
44
  default: [],
48
- })
49
- .check((argv) => {
50
- if (argv.L == null)
51
- return true;
52
- return (argv.L.match(LOCAL_PORT_FORWARD_PATTERN) ||
53
- "Local port forward should be in the format `local_port:remote_port`");
54
45
  })
55
46
  .option("L", {
56
47
  type: "string",
57
- describe:
58
- // the order of the sockets in the address matches the ssh man page
59
- "Forward a local port to the remote host; `local_socket:remote_socket`",
48
+ // Copied from `man ssh`
49
+ describe: "Specifies that connections to the given TCP port or Unix socket on the local (client) host are to be forwarded to the given host and port, or Unix socket, on the remote side.",
60
50
  })
61
51
  .option("N", {
62
52
  type: "boolean",
63
53
  describe: "Do not execute a remote command. Useful for forwarding ports.",
54
+ })
55
+ .option("A", {
56
+ type: "boolean",
57
+ describe: "Enables forwarding of connections from an authentication agent such as ssh-agent",
64
58
  })
65
59
  // Match `p0 request --reason`
66
60
  .option("reason", {
@@ -70,7 +64,11 @@ const sshCommand = (yargs) => yargs.command("ssh <destination> [command [argumen
70
64
  .option("account", {
71
65
  type: "string",
72
66
  describe: "The account on which the instance is located",
73
- }), (0, firestore_1.guard)(ssh));
67
+ })
68
+ .option("debug", {
69
+ type: "boolean",
70
+ describe: "Print debug information. The ssh-agent subprocess is not terminated automatically.",
71
+ }), (0, firestore_1.guard)(sshAction));
74
72
  exports.sshCommand = sshCommand;
75
73
  /** Connect to an SSH backend
76
74
  *
@@ -79,17 +77,13 @@ exports.sshCommand = sshCommand;
79
77
  * Supported SSH mechanisms:
80
78
  * - AWS EC2 via SSM with Okta SAML
81
79
  */
82
- const ssh = (args) => __awaiter(void 0, void 0, void 0, function* () {
80
+ const sshAction = (args) => __awaiter(void 0, void 0, void 0, function* () {
83
81
  // Prefix is required because the backend uses it to determine that this is an AWS request
84
82
  const authn = yield (0, auth_1.authenticate)();
85
83
  const destination = args.destination;
86
- const requestId = yield (0, shared_1.provisionRequest)(authn, args, destination);
87
- if (!requestId) {
84
+ const result = yield (0, shared_1.provisionRequest)(authn, args, destination);
85
+ if (!result) {
88
86
  throw "Server did not return a request id. Please contact support@p0.dev for assistance.";
89
87
  }
90
- const result = yield (0, api_1.fetchExerciseGrant)(authn, {
91
- requestId,
92
- destination,
93
- });
94
- yield (0, ssm_1.ssm)(authn, result, args);
88
+ yield (0, ssm_1.sshOrScp)(authn, (0, shared_1.requestToSsh)(result.request), Object.assign(Object.assign({}, args), { destination }), result.privateKey);
95
89
  });
@@ -0,0 +1,13 @@
1
+ /// <reference types="jest" />
2
+ /** Copyright © 2024-present P0 Security
3
+
4
+ This file is part of @p0security/cli
5
+
6
+ @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.
7
+
8
+ @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.
9
+
10
+ You should have received a copy of the GNU General Public License along with @p0security/cli. If not, see <https://www.gnu.org/licenses/>.
11
+ **/
12
+ export declare const TEST_PUBLIC_KEY = "test-public-key";
13
+ export declare const createKeyPair: jest.Mock<any, any, any>;
@@ -0,0 +1,18 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.createKeyPair = exports.TEST_PUBLIC_KEY = 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.TEST_PUBLIC_KEY = "test-public-key";
15
+ exports.createKeyPair = jest.fn().mockImplementation(() => ({
16
+ publicKey: "test-public-key",
17
+ privateKey: "test-private-key",
18
+ }));
@@ -0,0 +1,9 @@
1
+ export declare const PUBLIC_KEY_PATH: string;
2
+ export declare const PRIVATE_KEY_PATH: string;
3
+ /**
4
+ * Search for a cached key pair, or create a new one if not found
5
+ */
6
+ export declare const createKeyPair: () => Promise<{
7
+ publicKey: string;
8
+ privateKey: string;
9
+ }>;
@@ -0,0 +1,84 @@
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
+ var __importDefault = (this && this.__importDefault) || function (mod) {
35
+ return (mod && mod.__esModule) ? mod : { "default": mod };
36
+ };
37
+ Object.defineProperty(exports, "__esModule", { value: true });
38
+ exports.createKeyPair = exports.PRIVATE_KEY_PATH = exports.PUBLIC_KEY_PATH = void 0;
39
+ /** Copyright © 2024-present P0 Security
40
+
41
+ This file is part of @p0security/cli
42
+
43
+ @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.
44
+
45
+ @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.
46
+
47
+ You should have received a copy of the GNU General Public License along with @p0security/cli. If not, see <https://www.gnu.org/licenses/>.
48
+ **/
49
+ const util_1 = require("../util");
50
+ const fs = __importStar(require("fs/promises"));
51
+ const node_forge_1 = __importDefault(require("node-forge"));
52
+ const path = __importStar(require("path"));
53
+ exports.PUBLIC_KEY_PATH = path.join(util_1.P0_PATH, "ssh", "id_rsa.pub");
54
+ exports.PRIVATE_KEY_PATH = path.join(util_1.P0_PATH, "ssh", "id_rsa");
55
+ /**
56
+ * Search for a cached key pair, or create a new one if not found
57
+ */
58
+ const createKeyPair = () => __awaiter(void 0, void 0, void 0, function* () {
59
+ if ((yield fileExists(exports.PUBLIC_KEY_PATH)) &&
60
+ (yield fileExists(exports.PRIVATE_KEY_PATH))) {
61
+ const publicKey = yield fs.readFile(exports.PUBLIC_KEY_PATH, "utf8");
62
+ const privateKey = yield fs.readFile(exports.PRIVATE_KEY_PATH, "utf8");
63
+ return { publicKey, privateKey };
64
+ }
65
+ else {
66
+ const rsaKeyPair = node_forge_1.default.pki.rsa.generateKeyPair({ bits: 2048 });
67
+ const privateKey = node_forge_1.default.pki.privateKeyToPem(rsaKeyPair.privateKey);
68
+ const publicKey = node_forge_1.default.ssh.publicKeyToOpenSSH(rsaKeyPair.publicKey);
69
+ yield fs.mkdir(path.dirname(exports.PUBLIC_KEY_PATH), { recursive: true });
70
+ yield fs.writeFile(exports.PUBLIC_KEY_PATH, publicKey, { mode: 0o600 });
71
+ yield fs.writeFile(exports.PRIVATE_KEY_PATH, privateKey, { mode: 0o600 });
72
+ return { publicKey, privateKey };
73
+ }
74
+ });
75
+ exports.createKeyPair = createKeyPair;
76
+ const fileExists = (path) => __awaiter(void 0, void 0, void 0, function* () {
77
+ try {
78
+ yield fs.access(path);
79
+ return true;
80
+ }
81
+ catch (error) {
82
+ return false;
83
+ }
84
+ });
@@ -1,20 +1,4 @@
1
- /** Copyright © 2024-present P0 Security
2
-
3
- This file is part of @p0security/cli
4
-
5
- @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.
6
-
7
- @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.
8
-
9
- You should have received a copy of the GNU General Public License along with @p0security/cli. If not, see <https://www.gnu.org/licenses/>.
10
- **/
11
- import { ExerciseGrantResponse } from "../commands/shared";
12
1
  import { Authn } from "../types/identity";
13
2
  import yargs from "yargs";
14
3
  export declare const fetchCommand: <T>(authn: Authn, args: yargs.ArgumentsCamelCase, argv: string[]) => Promise<T>;
15
- export declare const fetchExerciseGrant: (authn: Authn, args: {
16
- requestId: string;
17
- destination: string;
18
- publicKey?: string;
19
- }) => Promise<ExerciseGrantResponse>;
20
4
  export declare const baseFetch: <T>(authn: Authn, url: string, method: string, body: string) => Promise<T>;
@@ -32,12 +32,21 @@ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, ge
32
32
  });
33
33
  };
34
34
  Object.defineProperty(exports, "__esModule", { value: true });
35
- exports.baseFetch = exports.fetchExerciseGrant = exports.fetchCommand = void 0;
35
+ exports.baseFetch = exports.fetchCommand = 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
+ **/
36
46
  const env_1 = require("../drivers/env");
37
47
  const path = __importStar(require("node:path"));
38
48
  const tenantUrl = (tenant) => `${env_1.config.appUrl}/o/${tenant}`;
39
49
  const commandUrl = (tenant) => `${tenantUrl(tenant)}/command/`;
40
- const exerciseGrantUrl = (tenant) => `${tenantUrl(tenant)}/exercise-grant/`;
41
50
  const fetchCommand = (authn, args, argv) => __awaiter(void 0, void 0, void 0, function* () {
42
51
  return (0, exports.baseFetch)(authn, commandUrl(authn.identity.org.slug), "POST", JSON.stringify({
43
52
  argv,
@@ -45,10 +54,6 @@ const fetchCommand = (authn, args, argv) => __awaiter(void 0, void 0, void 0, fu
45
54
  }));
46
55
  });
47
56
  exports.fetchCommand = fetchCommand;
48
- const fetchExerciseGrant = (authn, args) => __awaiter(void 0, void 0, void 0, function* () {
49
- return (0, exports.baseFetch)(authn, exerciseGrantUrl(authn.identity.org.slug), "POST", JSON.stringify(args));
50
- });
51
- exports.fetchExerciseGrant = fetchExerciseGrant;
52
57
  const baseFetch = (authn, url, method, body) => __awaiter(void 0, void 0, void 0, function* () {
53
58
  const token = yield authn.userCredential.user.getIdToken();
54
59
  const response = yield fetch(url, {
@@ -26,9 +26,10 @@ const api_1 = require("./api");
26
26
  const api_2 = require("./api");
27
27
  const roleArn = (args) => `${(0, api_1.arnPrefix)(args.account)}:role/${args.role}`;
28
28
  const stsAssume = (params) => __awaiter(void 0, void 0, void 0, function* () {
29
- const url = `https://sts.amazonaws.com?${(0, fetch_1.urlEncode)(params)}`;
29
+ const url = `https://sts.amazonaws.com`;
30
30
  const response = yield fetch(url, {
31
- method: "GET",
31
+ method: "POST",
32
+ body: new URLSearchParams(params),
32
33
  });
33
34
  yield (0, fetch_1.validateResponse)(response);
34
35
  const stsXml = yield response.text();
@@ -8,8 +8,6 @@ This file is part of @p0security/cli
8
8
 
9
9
  You should have received a copy of the GNU General Public License along with @p0security/cli. If not, see <https://www.gnu.org/licenses/>.
10
10
  **/
11
- import { ExerciseGrantResponse, ScpCommandArgs, SshCommandArgs } from "../../../commands/shared";
11
+ import { ScpCommandArgs, SshCommandArgs, SshRequest } from "../../../commands/shared";
12
12
  import { Authn } from "../../../types/identity";
13
- /** Connect to an SSH backend using AWS Systems Manager (SSM) */
14
- export declare const ssm: (authn: Authn, request: ExerciseGrantResponse, args: SshCommandArgs) => Promise<void>;
15
- export declare const scp: (authn: Authn, data: ExerciseGrantResponse, args: ScpCommandArgs, privateKey: string) => Promise<number | null>;
13
+ export declare const sshOrScp: (authn: Authn, data: SshRequest, cmdArgs: ScpCommandArgs | SshCommandArgs, privateKey: string) => Promise<number | null>;