diff --git a/README.md b/README.md index fa4de36..2be7559 100644 --- a/README.md +++ b/README.md @@ -38,7 +38,7 @@ Additionally, you will need to [prepare the target device/emulator](#device-prep ### Host dependencies for Android -For Android, you need the [Android command line tools](https://developer.android.com/studio/command-line/) (can also be installed through [Android Studio](https://developer.android.com/studio)). Note that these need to be included in your `PATH`, e.g. by including something like this in your `.zshrc`/`.bashrc`: +For Android, you need the [Android SDK platform tools](https://developer.android.com/tools/releases/platform-tools) and [Android build tools](https://developer.android.com/tools/releases/build-tools) (can also be installed through [Android Studio](https://developer.android.com/studio)). Note that these need to be included in your `PATH`, e.g. by including something like this in your `.zshrc`/`.bashrc`: ```sh # Android SDK @@ -56,12 +56,10 @@ For the `certificate-pinning-bypass` capability, you need to install [`objection ### Host dependencies for iOS -For iOS, you need [`libimobiledevice`](https://libimobiledevice.org/) and `ideviceinstaller`. The distribution packages are fine, if available. +For iOS, you need [`libimobiledevice`](https://libimobiledevice.org/) and `ideviceinstaller`. The distribution packages are fine, if available. On Windows, you will additionally need the Apple Device Driver and the Apple Application Support service. You can get those by installing iTunes. For the `frida` capability, you need to install [`frida-tools`](https://frida.re/docs/installation/). -For the `ssh` capability, you need to install [`sshpass`](https://sourceforge.net/projects/sshpass). - ## Supported targets Appstraction supports the following targets. Note that it will likely also work on other versions of the targets, but these are the ones we have tested. diff --git a/docs/README.md b/docs/README.md index dd935ca..b731220 100644 --- a/docs/README.md +++ b/docs/README.md @@ -40,7 +40,7 @@ An ID of a known permission on Android. #### Defined in -[android.ts:769](https://github.com/tweaselORG/appstraction/blob/main/src/android.ts#L769) +[android.ts:768](https://github.com/tweaselORG/appstraction/blob/main/src/android.ts#L768) ___ @@ -58,7 +58,7 @@ A supported attribute for the `getDeviceAttribute()` function, depending on the #### Defined in -[index.ts:329](https://github.com/tweaselORG/appstraction/blob/main/src/index.ts#L329) +[index.ts:332](https://github.com/tweaselORG/appstraction/blob/main/src/index.ts#L332) ___ @@ -77,7 +77,7 @@ The options for each attribute available through the `getDeviceAttribute()` func #### Defined in -[index.ts:335](https://github.com/tweaselORG/appstraction/blob/main/src/index.ts#L335) +[index.ts:338](https://github.com/tweaselORG/appstraction/blob/main/src/index.ts#L338) ___ @@ -89,7 +89,7 @@ An ID of a known permission on iOS. #### Defined in -[ios.ts:398](https://github.com/tweaselORG/appstraction/blob/main/src/ios.ts#L398) +[ios.ts:382](https://github.com/tweaselORG/appstraction/blob/main/src/ios.ts#L382) ___ @@ -133,7 +133,7 @@ Functions that are available for the platforms. #### Defined in -[index.ts:18](https://github.com/tweaselORG/appstraction/blob/main/src/index.ts#L18) +[index.ts:19](https://github.com/tweaselORG/appstraction/blob/main/src/index.ts#L19) ___ @@ -153,7 +153,7 @@ The options for the `platformApi()` function. #### Defined in -[index.ts:267](https://github.com/tweaselORG/appstraction/blob/main/src/index.ts#L267) +[index.ts:270](https://github.com/tweaselORG/appstraction/blob/main/src/index.ts#L270) ___ @@ -172,7 +172,7 @@ Connection details for a proxy. #### Defined in -[index.ts:343](https://github.com/tweaselORG/appstraction/blob/main/src/index.ts#L343) +[index.ts:346](https://github.com/tweaselORG/appstraction/blob/main/src/index.ts#L346) ___ @@ -202,7 +202,7 @@ The options for a specific platform/run target combination. #### Defined in -[index.ts:294](https://github.com/tweaselORG/appstraction/blob/main/src/index.ts#L294) +[index.ts:297](https://github.com/tweaselORG/appstraction/blob/main/src/index.ts#L297) ___ @@ -220,7 +220,7 @@ A capability for the `platformApi()` function. #### Defined in -[index.ts:322](https://github.com/tweaselORG/appstraction/blob/main/src/index.ts#L322) +[index.ts:325](https://github.com/tweaselORG/appstraction/blob/main/src/index.ts#L325) ___ @@ -232,7 +232,7 @@ A platform that is supported by this library. #### Defined in -[index.ts:9](https://github.com/tweaselORG/appstraction/blob/main/src/index.ts#L9) +[index.ts:10](https://github.com/tweaselORG/appstraction/blob/main/src/index.ts#L10) ___ @@ -250,7 +250,7 @@ A run target that is supported by this library for the given platform. #### Defined in -[index.ts:11](https://github.com/tweaselORG/appstraction/blob/main/src/index.ts#L11) +[index.ts:12](https://github.com/tweaselORG/appstraction/blob/main/src/index.ts#L12) ___ @@ -262,7 +262,7 @@ Configuration string for WireGuard. #### Defined in -[index.ts:350](https://github.com/tweaselORG/appstraction/blob/main/src/index.ts#L350) +[index.ts:353](https://github.com/tweaselORG/appstraction/blob/main/src/index.ts#L353) ## Variables @@ -274,7 +274,7 @@ The IDs of known permissions on Android. #### Defined in -[android.ts:638](https://github.com/tweaselORG/appstraction/blob/main/src/android.ts#L638) +[android.ts:637](https://github.com/tweaselORG/appstraction/blob/main/src/android.ts#L637) ___ @@ -286,7 +286,7 @@ The IDs of known permissions on iOS. #### Defined in -[ios.ts:381](https://github.com/tweaselORG/appstraction/blob/main/src/ios.ts#L381) +[ios.ts:365](https://github.com/tweaselORG/appstraction/blob/main/src/ios.ts#L365) ## Functions @@ -373,4 +373,4 @@ The API object for the given platform and run target. #### Defined in -[index.ts:359](https://github.com/tweaselORG/appstraction/blob/main/src/index.ts#L359) +[index.ts:362](https://github.com/tweaselORG/appstraction/blob/main/src/index.ts#L362) diff --git a/package.json b/package.json index 4a9198f..cbf714e 100644 --- a/package.json +++ b/package.json @@ -57,6 +57,7 @@ "frida": "^16.0.8", "fs-extra": "^11.1.0", "ipa-extract-info": "^1.2.6", + "node-ssh": "^13.1.0", "p-retry": "^5.1.2", "pkijs": "^3.0.14", "semver": "^7.3.8", diff --git a/src/android.ts b/src/android.ts index 5853385..e8ed729 100644 --- a/src/android.ts +++ b/src/android.ts @@ -141,11 +141,8 @@ export const androidApi = >( } // Start `frida-server` if it's not already running. - const fridaCheck = await execa(`frida-ps -U | grep frida-server`, { - shell: true, - reject: false, - }); - if (fridaCheck.exitCode === 0) return; + const { stdout: fridaCheck } = await execa('frida-ps', ['-U'], { reject: false }); + if (fridaCheck.includes('frida-server')) return; await this.requireRoot('Frida'); @@ -153,8 +150,7 @@ export const androidApi = >( await execa('adb', ['shell', '-x', '/data/local/tmp/frida-server', '--daemonize']); const fridaIsStarted = await retryCondition( - async () => - (await execa(`frida-ps -U | grep frida-server`, { shell: true, reject: false })).exitCode === 0, + async () => (await execa('frida-ps', ['-U'], { reject: false })).stdout.includes('frida-server'), 100 ); if (!fridaIsStarted) throw new Error('Failed to start Frida.'); @@ -168,7 +164,9 @@ export const androidApi = >( getCertificateSubjectHashOld: (path: string) => execa('openssl', ['x509', '-inform', 'PEM', '-subject_hash_old', '-in', path]).then( - ({ stdout }) => stdout.split('\n')[0] + // The `trim()` is necessary for Windows: + // https://github.com/tweaselORG/meta/issues/25#issuecomment-1507665763 + ({ stdout }) => stdout.split('\n')[0]?.trim() ), hasCertificateAuthority: (filename) => execa('adb', ['shell', 'ls', `/system/etc/security/cacerts/${filename}`], { reject: false }).then( @@ -392,7 +390,8 @@ export const androidApi = >( if ( err.exitCode === 255 && (err.stderr.includes('not a changeable permission type') || - err.stderr.includes('has not requested permission')) + err.stderr.includes('has not requested permission') || + err.stderr.includes('Unknown permission')) ) return; diff --git a/src/index.ts b/src/index.ts index 16fdd04..aba576f 100644 --- a/src/index.ts +++ b/src/index.ts @@ -1,4 +1,5 @@ import type { ExecaChildProcess } from 'execa'; +import type { NodeSSH } from 'node-ssh'; import type { LiteralUnion } from 'type-fest'; import type { AndroidPermission } from './android'; import { androidApi } from './android'; @@ -259,7 +260,9 @@ export type PlatformApi< objectionProcesses: ExecaChildProcess[]; } : Platform extends 'ios' - ? undefined + ? { + ssh: NodeSSH['execCommand']; + } : never; }; diff --git a/src/ios.ts b/src/ios.ts index 085c3da..005638e 100644 --- a/src/ios.ts +++ b/src/ios.ts @@ -2,6 +2,7 @@ import { createHash } from 'crypto'; import { execa } from 'execa'; import frida from 'frida'; import { readFile } from 'fs/promises'; +import { NodeSSH } from 'node-ssh'; import { Certificate } from 'pkijs'; import type { PlatformApi, PlatformApiOptions, Proxy, SupportedCapability, SupportedRunTarget } from '.'; import { asyncUnimplemented, getObjFromFridaScript, isRecord } from './util'; @@ -120,10 +121,24 @@ send({ name: "get_obj_from_frida_script", payload: getProxySettingsForCurrentWif export const iosApi = >( options: PlatformApiOptions<'ios', RunTarget, SupportedCapability<'ios'>[]> ): PlatformApi<'ios', 'device', SupportedCapability<'ios'>[]> => ({ - _internal: undefined, + _internal: { + ssh: async (...args) => { + const ssh = await new NodeSSH().connect({ + host: options.targetOptions!.ip, + username: 'root', + password: options.targetOptions!.rootPw || 'alpine', + }); + const res = await ssh.execCommand(...args); + // Creating and disposing a new SSH connection for each command is not efficient but it replicates the + // previous behaviour of calling `ssh`. If we wanted to keep the connection open, we would also need a way + // to dispose of it at the very end, but we don't know when that is (cf. #24). + ssh.dispose(); + return res; + }, + }, resetDevice: asyncUnimplemented('resetDevice') as never, - ensureDevice: async () => { + async ensureDevice() { if ((await execa('ideviceinfo', ['-k', 'DeviceName'], { reject: false })).exitCode !== 0) throw new Error('You need to connect your device and trust this computer.'); @@ -139,13 +154,7 @@ export const iosApi = >( if (options.capabilities.includes('ssh')) { try { - const { stdout } = await execa('sshpass', [ - '-p', - options.targetOptions!.rootPw || 'alpine', - 'ssh', - `root@${options.targetOptions!.ip}`, - `uname`, - ]); + const { stdout } = await this._internal.ssh('uname'); if (stdout !== 'Darwin') throw new Error('Wrong uname output.'); } catch (err) { throw new Error('Cannot connect using SSH.', { cause: err }); @@ -155,7 +164,10 @@ export const iosApi = >( clearStuckModals: asyncUnimplemented('clearStuckModals') as never, isAppInstalled: async (appId) => { - const { stdout } = await execa('ideviceinstaller', ['-l', '-o', 'list_all']); + const { stdout } = + process.platform === 'win32' + ? await execa('ideviceinstaller', ['-l', '-o', 'list_all']) + : await execa('ideviceinstaller', ['list', '-o', 'list_all']); return ( stdout .split('\n') @@ -167,36 +179,26 @@ export const iosApi = >( // We're using `libimobiledevice` instead of `cfgutil` because the latter doesn't wait for the app to be fully // installed before exiting. installApp: async (ipaPath) => { - await execa('ideviceinstaller', ['--install', ipaPath]); + if (process.platform === 'win32') await execa('ideviceinstaller', ['install', ipaPath]); + else await execa('ideviceinstaller', ['--install', ipaPath]); }, uninstallApp: async (appId) => { - await execa('ideviceinstaller', ['--uninstall', appId]); + if (process.platform === 'win32') await execa('ideviceinstaller', ['uninstall', appId]); + else await execa('ideviceinstaller', ['--uninstall', appId]); }, - setAppPermissions: async (appId, _permissions) => { + async setAppPermissions(appId, _permissions) { if (!options.capabilities.includes('ssh') || !options.capabilities.includes('frida')) throw new Error('SSH and Frida are required for setting app permissions.'); const permissionValues = { allow: 2, deny: 0 } as const; const setPermission = (permission: string, value: 0 | 2) => - execa('sshpass', [ - '-p', - options.targetOptions!.rootPw || 'alpine', - 'ssh', - `root@${options.targetOptions!.ip}`, - 'sqlite3', - '/private/var/mobile/Library/TCC/TCC.db', - `'INSERT OR REPLACE INTO access (service, client, client_type, auth_value, auth_reason, auth_version) VALUES("${permission}", "${appId}", 0, ${value}, 2, 1);'`, - ]); + this._internal.ssh( + `sqlite3 /private/var/mobile/Library/TCC/TCC.db 'INSERT OR REPLACE INTO access (service, client, client_type, auth_value, auth_reason, auth_version) VALUES("${permission}", "${appId}", 0, ${value}, 2, 1);'` + ); const unsetPermission = (permission: string) => - execa('sshpass', [ - '-p', - options.targetOptions!.rootPw || 'alpine', - 'ssh', - `root@${options.targetOptions!.ip}`, - 'sqlite3', - '/private/var/mobile/Library/TCC/TCC.db', - `'DELETE FROM access WHERE service="${permission}" AND client="${appId}";'`, - ]); + this._internal.ssh( + `sqlite3 /private/var/mobile/Library/TCC/TCC.db 'DELETE FROM access WHERE service="${permission}" AND client="${appId}";'` + ); const locationPermissionValues = { ask: 0, never: 2, always: 3, 'while-using': 4 } as const; const grantLocationPermission = async (value: 0 | 2 | 3 | 4) => { const session = await frida.getUsbDevice().then((f) => f.attach('SpringBoard')); @@ -224,20 +226,14 @@ export const iosApi = >( } }, setAppBackgroundBatteryUsage: asyncUnimplemented('setAppBatteryOptimization') as never, - startApp: async (appId) => { + async startApp(appId) { if (options.capabilities.includes('frida')) { const session = await frida.getUsbDevice().then((f) => f.attach('SpringBoard')); const script = await session.createScript(fridaScripts.startApp(appId)); await script.load(); await session.detach(); } else if (options.capabilities.includes('ssh')) { - execa('sshpass', [ - '-p', - options.targetOptions!.rootPw || 'alpine', - 'ssh', - `root@${options.targetOptions!.ip}`, - `open ${appId}`, - ]); + this._internal.ssh(`open ${appId}`); } else { throw new Error('Frida or SSH (with the open package installed) is required for starting apps.'); } @@ -301,7 +297,7 @@ export const iosApi = >( await session.detach(); }, - installCertificateAuthority: async (path) => { + async installCertificateAuthority(path) { if (!options.capabilities.includes('ssh')) throw new Error('SSH is required for installing a certificate authority.'); @@ -324,17 +320,11 @@ export const iosApi = >( ).toString('hex'); const data = certDer.toString('hex'); - await execa('sshpass', [ - '-p', - options.targetOptions!.rootPw || 'alpine', - 'ssh', - `root@${options.targetOptions!.ip}`, - 'sqlite3', - '/private/var/protected/trustd/private/TrustStore.sqlite3', - `"INSERT OR REPLACE INTO tsettings (sha256, subj, tset, data) VALUES(x'${sha256}', x'${subj}', x'${tset}', x'${data}');"`, - ]); + await this._internal.ssh( + `sqlite3 /private/var/protected/trustd/private/TrustStore.sqlite3 "INSERT OR REPLACE INTO tsettings (sha256, subj, tset, data) VALUES(x'${sha256}', x'${subj}', x'${tset}', x'${data}');"` + ); }, - removeCertificateAuthority: async (path) => { + async removeCertificateAuthority(path) { if (!options.capabilities.includes('ssh')) throw new Error('SSH is required for removing a certificate authority.'); @@ -343,15 +333,9 @@ export const iosApi = >( const certDer = Buffer.from(certBase64, 'base64'); const sha256 = createHash('sha256').update(certDer).digest('hex'); - await execa('sshpass', [ - '-p', - options.targetOptions!.rootPw || 'alpine', - 'ssh', - `root@${options.targetOptions!.ip}`, - 'sqlite3', - '/private/var/protected/trustd/private/TrustStore.sqlite3', - `"DELETE FROM tsettings WHERE sha256=x'${sha256}';"`, - ]); + await this._internal.ssh( + `sqlite3 /private/var/protected/trustd/private/TrustStore.sqlite3 "DELETE FROM tsettings WHERE sha256=x'${sha256}';"` + ); }, setProxy: async (proxy) => { if (!options.capabilities.includes('frida')) throw new Error('Frida is required for configuring a proxy.'); diff --git a/yarn.lock b/yarn.lock index 12830bf..18e8733 100644 --- a/yarn.lock +++ b/yarn.lock @@ -1065,6 +1065,13 @@ resolved "https://registry.yarnpkg.com/@types/semver/-/semver-7.3.13.tgz#da4bfd73f49bd541d28920ab0e2bf0ee80f71c91" integrity sha512-21cFJr9z3g5dW8B0CVI9g2O9beqaThGQ6ZFBqHfwhzLDKUxaqTIy3vnfah/UPkfOiF2pLq+tGz+W8RyCskuslw== +"@types/ssh2@^1.11.9": + version "1.11.11" + resolved "https://registry.yarnpkg.com/@types/ssh2/-/ssh2-1.11.11.tgz#02fb707d821890a655fd27c2d842b0c7114078fb" + integrity sha512-LdnE7UBpvHCgUznvn2fwLt2hkaENcKPFqOyXGkvyTLfxCXBN6roc1RmECNYuzzbHePzD3PaAov5rri9hehzx9Q== + dependencies: + "@types/node" "^18.11.18" + "@types/unist@*", "@types/unist@^2.0.0": version "2.0.6" resolved "https://registry.yarnpkg.com/@types/unist/-/unist-2.0.6.tgz#250a7b16c3b91f672a24552ec64678eeb1d3a08d" @@ -1297,6 +1304,13 @@ array.prototype.flat@^1.2.5: es-abstract "^1.20.4" es-shim-unscopables "^1.0.0" +asn1@^0.2.4: + version "0.2.6" + resolved "https://registry.yarnpkg.com/asn1/-/asn1-0.2.6.tgz#0d3a7bb6e64e02a90c0303b31f292868ea09a08d" + integrity sha512-ix/FxPn0MDjeyJ7i/yoHGFt/EX6LyNbxSEhPPXODPL+KB0VPk86UYfL0lMdy+KCnv+fmvIzySwaK5COwqVbWTQ== + dependencies: + safer-buffer "~2.1.0" + asn1js@^3.0.5: version "3.0.5" resolved "https://registry.yarnpkg.com/asn1js/-/asn1js-3.0.5.tgz#5ea36820443dbefb51cc7f88a2ebb5b462114f38" @@ -1338,6 +1352,13 @@ base64-js@^1.3.1, base64-js@^1.5.1: resolved "https://registry.yarnpkg.com/base64-js/-/base64-js-1.5.1.tgz#1b1b440160a5bf7ad40b650f095963481903930a" integrity sha512-AKpaYlHn8t4SVbOHCy+b5+KKgvR4vrsD8vbvrbiQJps7fKDTkjkDry6ji0rUJjC0kzbNePLwzxq8iypo41qeWA== +bcrypt-pbkdf@^1.0.2: + version "1.0.2" + resolved "https://registry.yarnpkg.com/bcrypt-pbkdf/-/bcrypt-pbkdf-1.0.2.tgz#a4301d389b6a43f9b67ff3ca11a3f6637e360e9e" + integrity sha512-qeFIXtP4MSoi6NLqO12WfqARWWuCKi2Rn/9hJLEmtB5yTNr9DqFWkJRCf2qShWzPeAMRnOgCrq0sg/KLv5ES9w== + dependencies: + tweetnacl "^0.14.3" + big-integer@^1.6.7: version "1.6.51" resolved "https://registry.yarnpkg.com/big-integer/-/big-integer-1.6.51.tgz#0df92a5d9880560d3ff2d5fd20245c889d130686" @@ -1452,6 +1473,11 @@ buffer@^5.5.0: base64-js "^1.3.1" ieee754 "^1.1.13" +buildcheck@0.0.5: + version "0.0.5" + resolved "https://registry.yarnpkg.com/buildcheck/-/buildcheck-0.0.5.tgz#5b7c0830b25dc61422032eeb5c18bfcaa9eebb8d" + integrity sha512-jYWpRy8eedl/JZqkOeq0X0bNcaK04hXKhIi4gYsDKZUJWRjJJWViYfsMXO0BJQ40zSLcdLoa+iqe48Kz2PtQag== + bytestreamjs@^2.0.0: version "2.0.1" resolved "https://registry.yarnpkg.com/bytestreamjs/-/bytestreamjs-2.0.1.tgz#a32947c7ce389a6fa11a09a9a563d0a45889535e" @@ -1643,6 +1669,14 @@ cosmiconfig@^7.0.0, cosmiconfig@^7.0.1: path-type "^4.0.0" yaml "^1.10.0" +cpu-features@~0.0.4: + version "0.0.6" + resolved "https://registry.yarnpkg.com/cpu-features/-/cpu-features-0.0.6.tgz#607e82a4d563343f64b7dd90a33f2b1d821214b5" + integrity sha512-Rj33pk//oVNh25YjsBaKtOkXNW7IARYxejWJosJkXqVPpbK+FrdpThPk6f4m3d+CEh2qMlkGx/SFt2Y1XSWN6g== + dependencies: + buildcheck "0.0.5" + nan "^2.17.0" + create-require@^1.1.0: version "1.1.1" resolved "https://registry.yarnpkg.com/create-require/-/create-require-1.1.1.tgz#c1d7e8f1e5f6cfc9ff65f9cd352d37348756c333" @@ -2845,6 +2879,11 @@ is-shared-array-buffer@^1.0.2: dependencies: call-bind "^1.0.2" +is-stream@^2.0.0: + version "2.0.1" + resolved "https://registry.yarnpkg.com/is-stream/-/is-stream-2.0.1.tgz#fac1e3d53b97ad5a9d0ae9cef2389f5810a5c077" + integrity sha512-hFoiJiTl63nn+kstHGBtewWSKnQLpyb155KHheA1l39uvtO9nWIop1p3udqPcUd/xbF1VLMO4n7OI6p7RbngDg== + is-stream@^3.0.0: version "3.0.0" resolved "https://registry.yarnpkg.com/is-stream/-/is-stream-3.0.0.tgz#e6bfd7aa6bef69f4f472ce9bb681e3e57b4319ac" @@ -3144,6 +3183,13 @@ magic-string@^0.22.4: dependencies: vlq "^0.2.2" +make-dir@^3.1.0: + version "3.1.0" + resolved "https://registry.yarnpkg.com/make-dir/-/make-dir-3.1.0.tgz#415e967046b3a7f1d185277d84aa58203726a13f" + integrity sha512-g3FeP20LNwhALb/6Cz6Dd4F2ngze0jz7tbzrD2wAV+o9FeNHe4rL+yK2md0J/fiSf1sa1ADhXqi5+oVwOM/eGw== + dependencies: + semver "^6.0.0" + make-error@^1.1.1: version "1.3.6" resolved "https://registry.yarnpkg.com/make-error/-/make-error-1.3.6.tgz#2eb2e37ea9b67c4891f684a1394799af484cf7a2" @@ -3501,6 +3547,11 @@ msgpackr@^1.5.4: optionalDependencies: msgpackr-extract "^2.2.0" +nan@^2.16.0, nan@^2.17.0: + version "2.17.0" + resolved "https://registry.yarnpkg.com/nan/-/nan-2.17.0.tgz#c0150a2368a182f033e9aa5195ec76ea41a199cb" + integrity sha512-2ZTgtl0nJsO0KQCjEpxcIr5D+Yv90plTitZt9JBfQvVJDS5seMl3FOvsh3+9CoYWXf/1l5OaZzzF6nDm4cagaQ== + napi-build-utils@^1.0.1: version "1.0.2" resolved "https://registry.yarnpkg.com/napi-build-utils/-/napi-build-utils-1.0.2.tgz#b1fddc0b2c46e380a0b7a76f984dd47c41a13806" @@ -3553,6 +3604,19 @@ node-releases@^2.0.6: resolved "https://registry.yarnpkg.com/node-releases/-/node-releases-2.0.8.tgz#0f349cdc8fcfa39a92ac0be9bc48b7706292b9ae" integrity sha512-dFSmB8fFHEH/s81Xi+Y/15DQY6VHW81nXRj86EMSL3lmuTmK1e+aT4wrFCkTbm+gSwkw4KpX+rT/pMM2c1mF+A== +node-ssh@^13.1.0: + version "13.1.0" + resolved "https://registry.yarnpkg.com/node-ssh/-/node-ssh-13.1.0.tgz#fca947200d61db9a5f9915e27c252e133b79e6bf" + integrity sha512-GLcw49yFd9+rUpP+FgX6wrF/N90cmuDl2n0i8d3L828b6riRjkb9w3SS+XvviRWbrAhLxuMKywFqxvQDZQ1bug== + dependencies: + "@types/ssh2" "^1.11.9" + is-stream "^2.0.0" + make-dir "^3.1.0" + sb-promise-queue "^2.1.0" + sb-scandir "^3.1.0" + shell-escape "^0.2.0" + ssh2 "^1.11.0" + normalize-path@^3.0.0: version "3.0.0" resolved "https://registry.yarnpkg.com/normalize-path/-/normalize-path-3.0.0.tgz#0dcd69ff23a1c9b11fd0978316644a0388216a65" @@ -4126,6 +4190,23 @@ safe-regex-test@^1.0.0: get-intrinsic "^1.1.3" is-regex "^1.1.4" +safer-buffer@~2.1.0: + version "2.1.2" + resolved "https://registry.yarnpkg.com/safer-buffer/-/safer-buffer-2.1.2.tgz#44fa161b0187b9549dd84bb91802f9bd8385cd6a" + integrity sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg== + +sb-promise-queue@^2.1.0: + version "2.1.0" + resolved "https://registry.yarnpkg.com/sb-promise-queue/-/sb-promise-queue-2.1.0.tgz#7e44bebef643f75d809a3db7f605b815d877a04d" + integrity sha512-zwq4YuP1FQFkGx2Q7GIkZYZ6PqWpV+bg0nIO1sJhWOyGyhqbj0MsTvK6lCFo5TQwX5pZr6SCQ75e8PCDCuNvkg== + +sb-scandir@^3.1.0: + version "3.1.0" + resolved "https://registry.yarnpkg.com/sb-scandir/-/sb-scandir-3.1.0.tgz#31c346abb5184b73c5a25b286858f4299aa8756c" + integrity sha512-70BVm2xz9jn94zSQdpvYrEG101/UV9TVGcfWr9T5iob3QhCK4lYXeculfBqPGFv3XTeKgx4dpWyYIDeZUqo4kg== + dependencies: + sb-promise-queue "^2.1.0" + semver-compare@^1.0.0: version "1.0.0" resolved "https://registry.yarnpkg.com/semver-compare/-/semver-compare-1.0.0.tgz#0dee216a1c941ab37e9efb1788f6afc5ff5537fc" @@ -4141,6 +4222,11 @@ semver@^5.7.0, semver@^5.7.1: resolved "https://registry.yarnpkg.com/semver/-/semver-5.7.1.tgz#a954f931aeba508d307bbf069eff0c01c96116f7" integrity sha512-sauaDf/PZdVgrLTNYHRtpXa1iRiKcaebiKQ1BJdpQlWH2lCvexQdX55snPFyK7QzpudqbCI0qXFfOasHdyNDGQ== +semver@^6.0.0: + version "6.3.0" + resolved "https://registry.yarnpkg.com/semver/-/semver-6.3.0.tgz#ee0a64c8af5e8ceea67687b133761e1becbd1d3d" + integrity sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw== + semver@^7.3.5, semver@^7.3.7, semver@^7.3.8: version "7.3.8" resolved "https://registry.yarnpkg.com/semver/-/semver-7.3.8.tgz#07a78feafb3f7b32347d725e33de7e2a2df67798" @@ -4165,6 +4251,11 @@ shebang-regex@^3.0.0: resolved "https://registry.yarnpkg.com/shebang-regex/-/shebang-regex-3.0.0.tgz#ae16f1644d873ecad843b0307b143362d4c42172" integrity sha512-7++dFhtcx3353uBaq8DDR4NuxBetBzC7ZQOhmTQInHEd6bSrXdiEyzCvG07Z44UYdLShWUyXt5M/yhz8ekcb1A== +shell-escape@^0.2.0: + version "0.2.0" + resolved "https://registry.yarnpkg.com/shell-escape/-/shell-escape-0.2.0.tgz#68fd025eb0490b4f567a027f0bf22480b5f84133" + integrity sha512-uRRBT2MfEOyxuECseCZd28jC1AJ8hmqqneWQ4VWUTgCAFvb3wKU1jLqj6egC4Exrr88ogg3dp+zroH4wJuaXzw== + shiki@^0.14.1: version "0.14.1" resolved "https://registry.yarnpkg.com/shiki/-/shiki-0.14.1.tgz#9fbe082d0a8aa2ad63df4fbf2ee11ec924aa7ee1" @@ -4276,6 +4367,17 @@ source-map@~0.1.30: dependencies: amdefine ">=0.0.4" +ssh2@^1.11.0: + version "1.11.0" + resolved "https://registry.yarnpkg.com/ssh2/-/ssh2-1.11.0.tgz#ce60186216971e12f6deb553dcf82322498fe2e4" + integrity sha512-nfg0wZWGSsfUe/IBJkXVll3PEZ//YH2guww+mP88gTpuSU4FtZN7zu9JoeTGOyCNx2dTDtT9fOpWwlzyj4uOOw== + dependencies: + asn1 "^0.2.4" + bcrypt-pbkdf "^1.0.2" + optionalDependencies: + cpu-features "~0.0.4" + nan "^2.16.0" + stable@^0.1.8: version "0.1.8" resolved "https://registry.yarnpkg.com/stable/-/stable-0.1.8.tgz#836eb3c8382fe2936feaf544631017ce7d47a3cf" @@ -4593,6 +4695,11 @@ tunnel-agent@^0.6.0: dependencies: safe-buffer "^5.0.1" +tweetnacl@^0.14.3: + version "0.14.5" + resolved "https://registry.yarnpkg.com/tweetnacl/-/tweetnacl-0.14.5.tgz#5ae68177f192d4456269d108afa93ff8743f4f64" + integrity sha512-KXXFFdAbFXY4geFIwoyNK+f5Z1b7swfXABfL7HXCmoIWMKU3dmS26672A4EeQtDzLKy7SXmfBu51JolvEKwtGA== + type-check@^0.4.0, type-check@~0.4.0: version "0.4.0" resolved "https://registry.yarnpkg.com/type-check/-/type-check-0.4.0.tgz#07b8203bfa7056c0657050e3ccd2c37730bab8f1"