diff --git a/.github/workflows/main.yml b/.github/workflows/main.yml index 7f914038..68382201 100644 --- a/.github/workflows/main.yml +++ b/.github/workflows/main.yml @@ -42,6 +42,16 @@ jobs: run: npm run test working-directory: ./keeperapi + - name: SDK - Install + run: npm ci + working-directory: ./KeeperSdk + env: + NPM_TOKEN: "" + + - name: SDK - Check Formatting + run: npm run format:check + working-directory: ./KeeperSdk + - name: Examples (node) - Installation run: npm run link-local working-directory: ./examples/print-vault-node diff --git a/KeeperSdk/.prettierignore b/KeeperSdk/.prettierignore new file mode 100644 index 00000000..cdc33a5a --- /dev/null +++ b/KeeperSdk/.prettierignore @@ -0,0 +1,2 @@ +package-lock.json +dist/ diff --git a/KeeperSdk/.prettierrc b/KeeperSdk/.prettierrc new file mode 100644 index 00000000..596e874e --- /dev/null +++ b/KeeperSdk/.prettierrc @@ -0,0 +1,7 @@ +{ + "singleQuote": true, + "semi": false, + "tabWidth": 4, + "printWidth": 120, + "trailingComma": "es5" +} diff --git a/KeeperSdk/package-lock.json b/KeeperSdk/package-lock.json index c4740a6a..783ba11e 100644 --- a/KeeperSdk/package-lock.json +++ b/KeeperSdk/package-lock.json @@ -1,626 +1,626 @@ { - "name": "@keeper-security/keeper-sdk-javascript", - "version": "1.1.1", - "lockfileVersion": 3, - "requires": true, - "packages": { - "": { - "name": "@keeper-security/keeper-sdk-javascript", - "version": "1.1.1", - "license": "ISC", - "dependencies": { - "@keeper-security/keeperapi": "^18.0.4", - "ts-node": "^10.7.0", - "typescript": "^4.6.3" - }, - "devDependencies": { - "@types/node": "^25.6.0", - "prettier": "^3.8.1" - } - }, - "node_modules/@cspotcode/source-map-support": { - "version": "0.8.1", - "resolved": "https://registry.npmjs.org/@cspotcode/source-map-support/-/source-map-support-0.8.1.tgz", - "integrity": "sha512-IchNf6dN4tHoMFIn/7OE8LWZ19Y6q/67Bmf6vnGREv8RSbBVb9LPJxEcnwrcwX6ixSvaiGoomAUvu4YSxXrVgw==", - "license": "MIT", - "dependencies": { - "@jridgewell/trace-mapping": "0.3.9" - }, - "engines": { - "node": ">=12" - } - }, - "node_modules/@jridgewell/resolve-uri": { - "version": "3.1.2", - "resolved": "https://registry.npmjs.org/@jridgewell/resolve-uri/-/resolve-uri-3.1.2.tgz", - "integrity": "sha512-bRISgCIjP20/tbWSPWMEi54QVPRZExkuD9lJL+UIxUKtwVJA8wW1Trb1jMs1RFXo1CBTNZ/5hpC9QvmKWdopKw==", - "license": "MIT", - "engines": { - "node": ">=6.0.0" - } - }, - "node_modules/@jridgewell/sourcemap-codec": { - "version": "1.5.5", - "resolved": "https://registry.npmjs.org/@jridgewell/sourcemap-codec/-/sourcemap-codec-1.5.5.tgz", - "integrity": "sha512-cYQ9310grqxueWbl+WuIUIaiUaDcj7WOq5fVhEljNVgRfOUhY9fy2zTvfoqWsnebh8Sl70VScFbICvJnLKB0Og==", - "license": "MIT" - }, - "node_modules/@jridgewell/trace-mapping": { - "version": "0.3.9", - "resolved": "https://registry.npmjs.org/@jridgewell/trace-mapping/-/trace-mapping-0.3.9.tgz", - "integrity": "sha512-3Belt6tdc8bPgAtbcmdtNJlirVoTmEb5e2gC94PnkwEW9jI6CAHUeoG85tjWP5WquqfavoMtMwiG4P926ZKKuQ==", - "license": "MIT", - "dependencies": { - "@jridgewell/resolve-uri": "^3.0.3", - "@jridgewell/sourcemap-codec": "^1.4.10" - } - }, - "node_modules/@keeper-security/keeperapi": { - "version": "18.0.5", - "resolved": "https://registry.npmjs.org/@keeper-security/keeperapi/-/keeperapi-18.0.5.tgz", - "integrity": "sha512-13P0mDMgaeUsbsQxlUqV1SMX0X9VAQ5aGa2antZDJWifqNqkZbTQEX/5evuZQN/tsTBn30/2DANpsCQyB1uQmw==", - "license": "ISC", - "dependencies": { - "@noble/post-quantum": "^0.5.2", - "asmcrypto.js": "^2.3.2", - "faye-websocket": "^0.11.3", - "form-data": "^4.0.4", - "node-rsa": "^1.0.8" - }, - "engines": { - "node": ">=24.13.1" - } - }, - "node_modules/@noble/curves": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/@noble/curves/-/curves-2.0.1.tgz", - "integrity": "sha512-vs1Az2OOTBiP4q0pwjW5aF0xp9n4MxVrmkFBxc6EKZc6ddYx5gaZiAsZoq0uRRXWbi3AT/sBqn05eRPtn1JCPw==", - "license": "MIT", - "dependencies": { - "@noble/hashes": "2.0.1" - }, - "engines": { - "node": ">= 20.19.0" - }, - "funding": { - "url": "https://paulmillr.com/funding/" - } - }, - "node_modules/@noble/hashes": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/@noble/hashes/-/hashes-2.0.1.tgz", - "integrity": "sha512-XlOlEbQcE9fmuXxrVTXCTlG2nlRXa9Rj3rr5Ue/+tX+nmkgbX720YHh0VR3hBF9xDvwnb8D2shVGOwNx+ulArw==", - "license": "MIT", - "engines": { - "node": ">= 20.19.0" - }, - "funding": { - "url": "https://paulmillr.com/funding/" - } - }, - "node_modules/@noble/post-quantum": { - "version": "0.5.4", - "resolved": "https://registry.npmjs.org/@noble/post-quantum/-/post-quantum-0.5.4.tgz", - "integrity": "sha512-leww0zzIirrvwaYMPI9fj6aRIlA/c6Y0/lifQQ1YOOyHEr0MNH3yYpjXeiVG+tWdPps4XxGclFWX2INPO3Yo5w==", - "license": "MIT", - "dependencies": { - "@noble/curves": "~2.0.0", - "@noble/hashes": "~2.0.0" - }, - "engines": { - "node": ">= 20.19.0" - }, - "funding": { - "url": "https://paulmillr.com/funding/" - } - }, - "node_modules/@tsconfig/node10": { - "version": "1.0.12", - "resolved": "https://registry.npmjs.org/@tsconfig/node10/-/node10-1.0.12.tgz", - "integrity": "sha512-UCYBaeFvM11aU2y3YPZ//O5Rhj+xKyzy7mvcIoAjASbigy8mHMryP5cK7dgjlz2hWxh1g5pLw084E0a/wlUSFQ==", - "license": "MIT" - }, - "node_modules/@tsconfig/node12": { - "version": "1.0.11", - "resolved": "https://registry.npmjs.org/@tsconfig/node12/-/node12-1.0.11.tgz", - "integrity": "sha512-cqefuRsh12pWyGsIoBKJA9luFu3mRxCA+ORZvA4ktLSzIuCUtWVxGIuXigEwO5/ywWFMZ2QEGKWvkZG1zDMTag==", - "license": "MIT" - }, - "node_modules/@tsconfig/node14": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/@tsconfig/node14/-/node14-1.0.3.tgz", - "integrity": "sha512-ysT8mhdixWK6Hw3i1V2AeRqZ5WfXg1G43mqoYlM2nc6388Fq5jcXyr5mRsqViLx/GJYdoL0bfXD8nmF+Zn/Iow==", - "license": "MIT" - }, - "node_modules/@tsconfig/node16": { - "version": "1.0.4", - "resolved": "https://registry.npmjs.org/@tsconfig/node16/-/node16-1.0.4.tgz", - "integrity": "sha512-vxhUy4J8lyeyinH7Azl1pdd43GJhZH/tP2weN8TntQblOY+A0XbT8DJk1/oCPuOOyg/Ja757rG0CgHcWC8OfMA==", - "license": "MIT" - }, - "node_modules/@types/node": { - "version": "25.6.0", - "resolved": "https://registry.npmjs.org/@types/node/-/node-25.6.0.tgz", - "integrity": "sha512-+qIYRKdNYJwY3vRCZMdJbPLJAtGjQBudzZzdzwQYkEPQd+PJGixUL5QfvCLDaULoLv+RhT3LDkwEfKaAkgSmNQ==", - "license": "MIT", - "dependencies": { - "undici-types": "~7.19.0" - } - }, - "node_modules/acorn": { - "version": "8.16.0", - "resolved": "https://registry.npmjs.org/acorn/-/acorn-8.16.0.tgz", - "integrity": "sha512-UVJyE9MttOsBQIDKw1skb9nAwQuR5wuGD3+82K6JgJlm/Y+KI92oNsMNGZCYdDsVtRHSak0pcV5Dno5+4jh9sw==", - "license": "MIT", - "bin": { - "acorn": "bin/acorn" - }, - "engines": { - "node": ">=0.4.0" - } - }, - "node_modules/acorn-walk": { - "version": "8.3.5", - "resolved": "https://registry.npmjs.org/acorn-walk/-/acorn-walk-8.3.5.tgz", - "integrity": "sha512-HEHNfbars9v4pgpW6SO1KSPkfoS0xVOM/9UzkJltjlsHZmJasxg8aXkuZa7SMf8vKGIBhpUsPluQSqhJFCqebw==", - "license": "MIT", - "dependencies": { - "acorn": "^8.11.0" - }, - "engines": { - "node": ">=0.4.0" - } - }, - "node_modules/arg": { - "version": "4.1.3", - "resolved": "https://registry.npmjs.org/arg/-/arg-4.1.3.tgz", - "integrity": "sha512-58S9QDqG0Xx27YwPSt9fJxivjYl432YCwfDMfZ+71RAqUrZef7LrKQZ3LHLOwCS4FLNBplP533Zx895SeOCHvA==", - "license": "MIT" - }, - "node_modules/asmcrypto.js": { - "version": "2.3.2", - "resolved": "https://registry.npmjs.org/asmcrypto.js/-/asmcrypto.js-2.3.2.tgz", - "integrity": "sha512-3FgFARf7RupsZETQ1nHnhLUUvpcttcCq1iZCaVAbJZbCZ5VNRrNyvpDyHTOb0KC3llFcsyOT/a99NZcCbeiEsA==", - "license": "MIT" - }, - "node_modules/asn1": { - "version": "0.2.6", - "resolved": "https://registry.npmjs.org/asn1/-/asn1-0.2.6.tgz", - "integrity": "sha512-ix/FxPn0MDjeyJ7i/yoHGFt/EX6LyNbxSEhPPXODPL+KB0VPk86UYfL0lMdy+KCnv+fmvIzySwaK5COwqVbWTQ==", - "license": "MIT", - "dependencies": { - "safer-buffer": "~2.1.0" - } - }, - "node_modules/asynckit": { - "version": "0.4.0", - "resolved": "https://registry.npmjs.org/asynckit/-/asynckit-0.4.0.tgz", - "integrity": "sha512-Oei9OH4tRh0YqU3GxhX79dM/mwVgvbZJaSNaRk+bshkj0S5cfHcgYakreBjrHwatXKbz+IoIdYLxrKim2MjW0Q==", - "license": "MIT" - }, - "node_modules/call-bind-apply-helpers": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/call-bind-apply-helpers/-/call-bind-apply-helpers-1.0.2.tgz", - "integrity": "sha512-Sp1ablJ0ivDkSzjcaJdxEunN5/XvksFJ2sMBFfq6x0ryhQV/2b/KwFe21cMpmHtPOSij8K99/wSfoEuTObmuMQ==", - "license": "MIT", - "dependencies": { - "es-errors": "^1.3.0", - "function-bind": "^1.1.2" - }, - "engines": { - "node": ">= 0.4" - } - }, - "node_modules/combined-stream": { - "version": "1.0.8", - "resolved": "https://registry.npmjs.org/combined-stream/-/combined-stream-1.0.8.tgz", - "integrity": "sha512-FQN4MRfuJeHf7cBbBMJFXhKSDq+2kAArBlmRBvcvFE5BB1HZKXtSFASDhdlz9zOYwxh8lDdnvmMOe/+5cdoEdg==", - "license": "MIT", - "dependencies": { - "delayed-stream": "~1.0.0" - }, - "engines": { - "node": ">= 0.8" - } - }, - "node_modules/create-require": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/create-require/-/create-require-1.1.1.tgz", - "integrity": "sha512-dcKFX3jn0MpIaXjisoRvexIJVEKzaq7z2rZKxf+MSr9TkdmHmsU4m2lcLojrj/FHl8mk5VxMmYA+ftRkP/3oKQ==", - "license": "MIT" - }, - "node_modules/delayed-stream": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/delayed-stream/-/delayed-stream-1.0.0.tgz", - "integrity": "sha512-ZySD7Nf91aLB0RxL4KGrKHBXl7Eds1DAmEdcoVawXnLD7SDhpNgtuII2aAkg7a7QS41jxPSZ17p4VdGnMHk3MQ==", - "license": "MIT", - "engines": { - "node": ">=0.4.0" - } - }, - "node_modules/diff": { - "version": "4.0.4", - "resolved": "https://registry.npmjs.org/diff/-/diff-4.0.4.tgz", - "integrity": "sha512-X07nttJQkwkfKfvTPG/KSnE2OMdcUCao6+eXF3wmnIQRn2aPAHH3VxDbDOdegkd6JbPsXqShpvEOHfAT+nCNwQ==", - "license": "BSD-3-Clause", - "engines": { - "node": ">=0.3.1" - } - }, - "node_modules/dunder-proto": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/dunder-proto/-/dunder-proto-1.0.1.tgz", - "integrity": "sha512-KIN/nDJBQRcXw0MLVhZE9iQHmG68qAVIBg9CqmUYjmQIhgij9U5MFvrqkUL5FbtyyzZuOeOt0zdeRe4UY7ct+A==", - "license": "MIT", - "dependencies": { - "call-bind-apply-helpers": "^1.0.1", - "es-errors": "^1.3.0", - "gopd": "^1.2.0" - }, - "engines": { - "node": ">= 0.4" - } - }, - "node_modules/es-define-property": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/es-define-property/-/es-define-property-1.0.1.tgz", - "integrity": "sha512-e3nRfgfUZ4rNGL232gUgX06QNyyez04KdjFrF+LTRoOXmrOgFKDg4BCdsjW8EnT69eqdYGmRpJwiPVYNrCaW3g==", - "license": "MIT", - "engines": { - "node": ">= 0.4" - } - }, - "node_modules/es-errors": { - "version": "1.3.0", - "resolved": "https://registry.npmjs.org/es-errors/-/es-errors-1.3.0.tgz", - "integrity": "sha512-Zf5H2Kxt2xjTvbJvP2ZWLEICxA6j+hAmMzIlypy4xcBg1vKVnx89Wy0GbS+kf5cwCVFFzdCFh2XSCFNULS6csw==", - "license": "MIT", - "engines": { - "node": ">= 0.4" - } - }, - "node_modules/es-object-atoms": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/es-object-atoms/-/es-object-atoms-1.1.1.tgz", - "integrity": "sha512-FGgH2h8zKNim9ljj7dankFPcICIK9Cp5bm+c2gQSYePhpaG5+esrLODihIorn+Pe6FGJzWhXQotPv73jTaldXA==", - "license": "MIT", - "dependencies": { - "es-errors": "^1.3.0" - }, - "engines": { - "node": ">= 0.4" - } - }, - "node_modules/es-set-tostringtag": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/es-set-tostringtag/-/es-set-tostringtag-2.1.0.tgz", - "integrity": "sha512-j6vWzfrGVfyXxge+O0x5sh6cvxAog0a/4Rdd2K36zCMV5eJ+/+tOAngRO8cODMNWbVRdVlmGZQL2YS3yR8bIUA==", - "license": "MIT", - "dependencies": { - "es-errors": "^1.3.0", - "get-intrinsic": "^1.2.6", - "has-tostringtag": "^1.0.2", - "hasown": "^2.0.2" - }, - "engines": { - "node": ">= 0.4" - } - }, - "node_modules/faye-websocket": { - "version": "0.11.4", - "resolved": "https://registry.npmjs.org/faye-websocket/-/faye-websocket-0.11.4.tgz", - "integrity": "sha512-CzbClwlXAuiRQAlUyfqPgvPoNKTckTPGfwZV4ZdAhVcP2lh9KUxJg2b5GkE7XbjKQ3YJnQ9z6D9ntLAlB+tP8g==", - "license": "Apache-2.0", - "dependencies": { - "websocket-driver": ">=0.5.1" - }, - "engines": { - "node": ">=0.8.0" - } - }, - "node_modules/form-data": { - "version": "4.0.6", - "resolved": "https://registry.npmjs.org/form-data/-/form-data-4.0.6.tgz", - "integrity": "sha512-vKatAh4SlVfgbv+YtmhiRjhEMJsYpsG1Y2rMQtR+SVSbytsSD1YGzDIcrAJmdFec88u/+VoGmxnl+80gL1tRCQ==", - "dependencies": { - "asynckit": "^0.4.0", - "combined-stream": "^1.0.8", - "es-set-tostringtag": "^2.1.0", - "hasown": "^2.0.4", - "mime-types": "^2.1.35" - }, - "engines": { - "node": ">= 6" - } - }, - "node_modules/function-bind": { - "version": "1.1.2", - "resolved": "https://registry.npmjs.org/function-bind/-/function-bind-1.1.2.tgz", - "integrity": "sha512-7XHNxH7qX9xG5mIwxkhumTox/MIRNcOgDrxWsMt2pAr23WHp6MrRlN7FBSFpCpr+oVO0F744iUgR82nJMfG2SA==", - "license": "MIT", - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/get-intrinsic": { - "version": "1.3.0", - "resolved": "https://registry.npmjs.org/get-intrinsic/-/get-intrinsic-1.3.0.tgz", - "integrity": "sha512-9fSjSaos/fRIVIp+xSJlE6lfwhES7LNtKaCBIamHsjr2na1BiABJPo0mOjjz8GJDURarmCPGqaiVg5mfjb98CQ==", - "license": "MIT", - "dependencies": { - "call-bind-apply-helpers": "^1.0.2", - "es-define-property": "^1.0.1", - "es-errors": "^1.3.0", - "es-object-atoms": "^1.1.1", - "function-bind": "^1.1.2", - "get-proto": "^1.0.1", - "gopd": "^1.2.0", - "has-symbols": "^1.1.0", - "hasown": "^2.0.2", - "math-intrinsics": "^1.1.0" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/get-proto": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/get-proto/-/get-proto-1.0.1.tgz", - "integrity": "sha512-sTSfBjoXBp89JvIKIefqw7U2CCebsc74kiY6awiGogKtoSGbgjYE/G/+l9sF3MWFPNc9IcoOC4ODfKHfxFmp0g==", - "license": "MIT", - "dependencies": { - "dunder-proto": "^1.0.1", - "es-object-atoms": "^1.0.0" - }, - "engines": { - "node": ">= 0.4" - } - }, - "node_modules/gopd": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/gopd/-/gopd-1.2.0.tgz", - "integrity": "sha512-ZUKRh6/kUFoAiTAtTYPZJ3hw9wNxx+BIBOijnlG9PnrJsCcSjs1wyyD6vJpaYtgnzDrKYRSqf3OO6Rfa93xsRg==", - "license": "MIT", - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/has-symbols": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/has-symbols/-/has-symbols-1.1.0.tgz", - "integrity": "sha512-1cDNdwJ2Jaohmb3sg4OmKaMBwuC48sYni5HUw2DvsC8LjGTLK9h+eb1X6RyuOHe4hT0ULCW68iomhjUoKUqlPQ==", - "license": "MIT", - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/has-tostringtag": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/has-tostringtag/-/has-tostringtag-1.0.2.tgz", - "integrity": "sha512-NqADB8VjPFLM2V0VvHUewwwsw0ZWBaIdgo+ieHtK3hasLz4qeCRjYcqfB6AQrBggRKppKF8L52/VqdVsO47Dlw==", - "license": "MIT", - "dependencies": { - "has-symbols": "^1.0.3" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/hasown": { - "version": "2.0.4", - "resolved": "https://registry.npmjs.org/hasown/-/hasown-2.0.4.tgz", - "integrity": "sha512-T2UbfbBEF32wiepXIsMlTW9+dDYC6wMh/t/vYA4tuOMKqWz/n3vr1NFSxQiyP+zk2mXsoMA/i/7qV6LKut1t1A==", - "dependencies": { - "function-bind": "^1.1.2" - }, - "engines": { - "node": ">= 0.4" - } - }, - "node_modules/http-parser-js": { - "version": "0.5.10", - "resolved": "https://registry.npmjs.org/http-parser-js/-/http-parser-js-0.5.10.tgz", - "integrity": "sha512-Pysuw9XpUq5dVc/2SMHpuTY01RFl8fttgcyunjL7eEMhGM3cI4eOmiCycJDVCo/7O7ClfQD3SaI6ftDzqOXYMA==", - "license": "MIT" - }, - "node_modules/make-error": { - "version": "1.3.6", - "resolved": "https://registry.npmjs.org/make-error/-/make-error-1.3.6.tgz", - "integrity": "sha512-s8UhlNe7vPKomQhC1qFelMokr/Sc3AgNbso3n74mVPA5LTZwkB9NlXf4XPamLxJE8h0gh73rM94xvwRT2CVInw==", - "license": "ISC" - }, - "node_modules/math-intrinsics": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/math-intrinsics/-/math-intrinsics-1.1.0.tgz", - "integrity": "sha512-/IXtbwEk5HTPyEwyKX6hGkYXxM9nbj64B+ilVJnC/R6B0pH5G4V3b0pVbL7DBj4tkhBAppbQUlf6F6Xl9LHu1g==", - "license": "MIT", - "engines": { - "node": ">= 0.4" - } - }, - "node_modules/mime-db": { - "version": "1.52.0", - "resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.52.0.tgz", - "integrity": "sha512-sPU4uV7dYlvtWJxwwxHD0PuihVNiE7TyAbQ5SWxDCB9mUYvOgroQOwYQQOKPJ8CIbE+1ETVlOoK1UC2nU3gYvg==", - "license": "MIT", - "engines": { - "node": ">= 0.6" - } - }, - "node_modules/mime-types": { - "version": "2.1.35", - "resolved": "https://registry.npmjs.org/mime-types/-/mime-types-2.1.35.tgz", - "integrity": "sha512-ZDY+bPm5zTTF+YpCrAU9nK0UgICYPT0QtT1NZWFv4s++TNkcgVaT0g6+4R2uI4MjQjzysHB1zxuWL50hzaeXiw==", - "license": "MIT", - "dependencies": { - "mime-db": "1.52.0" - }, - "engines": { - "node": ">= 0.6" - } - }, - "node_modules/node-rsa": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/node-rsa/-/node-rsa-1.1.1.tgz", - "integrity": "sha512-Jd4cvbJMryN21r5HgxQOpMEqv+ooke/korixNNK3mGqfGJmy0M77WDDzo/05969+OkMy3XW1UuZsSmW9KQm7Fw==", - "license": "MIT", - "dependencies": { - "asn1": "^0.2.4" - } - }, - "node_modules/prettier": { - "version": "3.8.3", - "resolved": "https://registry.npmjs.org/prettier/-/prettier-3.8.3.tgz", - "integrity": "sha512-7igPTM53cGHMW8xWuVTydi2KO233VFiTNyF5hLJqpilHfmn8C8gPf+PS7dUT64YcXFbiMGZxS9pCSxL/Dxm/Jw==", - "dev": true, - "license": "MIT", - "bin": { - "prettier": "bin/prettier.cjs" - }, - "engines": { - "node": ">=14" - }, - "funding": { - "url": "https://github.com/prettier/prettier?sponsor=1" - } - }, - "node_modules/safe-buffer": { - "version": "5.2.1", - "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.2.1.tgz", - "integrity": "sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ==", - "funding": [ - { - "type": "github", - "url": "https://github.com/sponsors/feross" - }, - { - "type": "patreon", - "url": "https://www.patreon.com/feross" - }, - { - "type": "consulting", - "url": "https://feross.org/support" - } - ], - "license": "MIT" - }, - "node_modules/safer-buffer": { - "version": "2.1.2", - "resolved": "https://registry.npmjs.org/safer-buffer/-/safer-buffer-2.1.2.tgz", - "integrity": "sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg==", - "license": "MIT" - }, - "node_modules/ts-node": { - "version": "10.9.2", - "resolved": "https://registry.npmjs.org/ts-node/-/ts-node-10.9.2.tgz", - "integrity": "sha512-f0FFpIdcHgn8zcPSbf1dRevwt047YMnaiJM3u2w2RewrB+fob/zePZcrOyQoLMMO7aBIddLcQIEK5dYjkLnGrQ==", - "license": "MIT", - "dependencies": { - "@cspotcode/source-map-support": "^0.8.0", - "@tsconfig/node10": "^1.0.7", - "@tsconfig/node12": "^1.0.7", - "@tsconfig/node14": "^1.0.0", - "@tsconfig/node16": "^1.0.2", - "acorn": "^8.4.1", - "acorn-walk": "^8.1.1", - "arg": "^4.1.0", - "create-require": "^1.1.0", - "diff": "^4.0.1", - "make-error": "^1.1.1", - "v8-compile-cache-lib": "^3.0.1", - "yn": "3.1.1" - }, - "bin": { - "ts-node": "dist/bin.js", - "ts-node-cwd": "dist/bin-cwd.js", - "ts-node-esm": "dist/bin-esm.js", - "ts-node-script": "dist/bin-script.js", - "ts-node-transpile-only": "dist/bin-transpile.js", - "ts-script": "dist/bin-script-deprecated.js" - }, - "peerDependencies": { - "@swc/core": ">=1.2.50", - "@swc/wasm": ">=1.2.50", - "@types/node": "*", - "typescript": ">=2.7" - }, - "peerDependenciesMeta": { - "@swc/core": { - "optional": true - }, - "@swc/wasm": { - "optional": true - } - } - }, - "node_modules/typescript": { - "version": "4.9.5", - "resolved": "https://registry.npmjs.org/typescript/-/typescript-4.9.5.tgz", - "integrity": "sha512-1FXk9E2Hm+QzZQ7z+McJiHL4NW1F2EzMu9Nq9i3zAaGqibafqYwCVU6WyWAuyQRRzOlxou8xZSyXLEN8oKj24g==", - "license": "Apache-2.0", - "bin": { - "tsc": "bin/tsc", - "tsserver": "bin/tsserver" - }, - "engines": { - "node": ">=4.2.0" - } - }, - "node_modules/undici-types": { - "version": "7.19.2", - "resolved": "https://registry.npmjs.org/undici-types/-/undici-types-7.19.2.tgz", - "integrity": "sha512-qYVnV5OEm2AW8cJMCpdV20CDyaN3g0AjDlOGf1OW4iaDEx8MwdtChUp4zu4H0VP3nDRF/8RKWH+IPp9uW0YGZg==", - "license": "MIT" - }, - "node_modules/v8-compile-cache-lib": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/v8-compile-cache-lib/-/v8-compile-cache-lib-3.0.1.tgz", - "integrity": "sha512-wa7YjyUGfNZngI/vtK0UHAN+lgDCxBPCylVXGp0zu59Fz5aiGtNXaq3DhIov063MorB+VfufLh3JlF2KdTK3xg==", - "license": "MIT" - }, - "node_modules/websocket-driver": { - "version": "0.7.4", - "resolved": "https://registry.npmjs.org/websocket-driver/-/websocket-driver-0.7.4.tgz", - "integrity": "sha512-b17KeDIQVjvb0ssuSDF2cYXSg2iztliJ4B9WdsuB6J952qCPKmnVq4DyW5motImXHDC1cBT/1UezrJVsKw5zjg==", - "license": "Apache-2.0", - "dependencies": { - "http-parser-js": ">=0.5.1", - "safe-buffer": ">=5.1.0", - "websocket-extensions": ">=0.1.1" - }, - "engines": { - "node": ">=0.8.0" - } - }, - "node_modules/websocket-extensions": { - "version": "0.1.4", - "resolved": "https://registry.npmjs.org/websocket-extensions/-/websocket-extensions-0.1.4.tgz", - "integrity": "sha512-OqedPIGOfsDlo31UNwYbCFMSaO9m9G/0faIHj5/dZFDMFqPTcx6UwqyOy3COEaEOg/9VsGIpdqn62W5KhoKSpg==", - "license": "Apache-2.0", - "engines": { - "node": ">=0.8.0" - } - }, - "node_modules/yn": { - "version": "3.1.1", - "resolved": "https://registry.npmjs.org/yn/-/yn-3.1.1.tgz", - "integrity": "sha512-Ux4ygGWsu2c7isFWe8Yu1YluJmqVhxqK2cLXNQA5AcC3QfbGNpM7fu0Y8b/z16pXLnFxZYvWhd3fhBY9DLmC6Q==", - "license": "MIT", - "engines": { - "node": ">=6" - } + "name": "@keeper-security/keeper-sdk-javascript", + "version": "1.1.1", + "lockfileVersion": 3, + "requires": true, + "packages": { + "": { + "name": "@keeper-security/keeper-sdk-javascript", + "version": "1.1.1", + "license": "ISC", + "dependencies": { + "@keeper-security/keeperapi": "^18.0.4", + "ts-node": "^10.7.0", + "typescript": "^4.6.3" + }, + "devDependencies": { + "@types/node": "^25.6.0", + "prettier": "^3.8.1" + } + }, + "node_modules/@cspotcode/source-map-support": { + "version": "0.8.1", + "resolved": "https://registry.npmjs.org/@cspotcode/source-map-support/-/source-map-support-0.8.1.tgz", + "integrity": "sha512-IchNf6dN4tHoMFIn/7OE8LWZ19Y6q/67Bmf6vnGREv8RSbBVb9LPJxEcnwrcwX6ixSvaiGoomAUvu4YSxXrVgw==", + "license": "MIT", + "dependencies": { + "@jridgewell/trace-mapping": "0.3.9" + }, + "engines": { + "node": ">=12" + } + }, + "node_modules/@jridgewell/resolve-uri": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/@jridgewell/resolve-uri/-/resolve-uri-3.1.2.tgz", + "integrity": "sha512-bRISgCIjP20/tbWSPWMEi54QVPRZExkuD9lJL+UIxUKtwVJA8wW1Trb1jMs1RFXo1CBTNZ/5hpC9QvmKWdopKw==", + "license": "MIT", + "engines": { + "node": ">=6.0.0" + } + }, + "node_modules/@jridgewell/sourcemap-codec": { + "version": "1.5.5", + "resolved": "https://registry.npmjs.org/@jridgewell/sourcemap-codec/-/sourcemap-codec-1.5.5.tgz", + "integrity": "sha512-cYQ9310grqxueWbl+WuIUIaiUaDcj7WOq5fVhEljNVgRfOUhY9fy2zTvfoqWsnebh8Sl70VScFbICvJnLKB0Og==", + "license": "MIT" + }, + "node_modules/@jridgewell/trace-mapping": { + "version": "0.3.9", + "resolved": "https://registry.npmjs.org/@jridgewell/trace-mapping/-/trace-mapping-0.3.9.tgz", + "integrity": "sha512-3Belt6tdc8bPgAtbcmdtNJlirVoTmEb5e2gC94PnkwEW9jI6CAHUeoG85tjWP5WquqfavoMtMwiG4P926ZKKuQ==", + "license": "MIT", + "dependencies": { + "@jridgewell/resolve-uri": "^3.0.3", + "@jridgewell/sourcemap-codec": "^1.4.10" + } + }, + "node_modules/@keeper-security/keeperapi": { + "version": "18.0.5", + "resolved": "https://registry.npmjs.org/@keeper-security/keeperapi/-/keeperapi-18.0.5.tgz", + "integrity": "sha512-13P0mDMgaeUsbsQxlUqV1SMX0X9VAQ5aGa2antZDJWifqNqkZbTQEX/5evuZQN/tsTBn30/2DANpsCQyB1uQmw==", + "license": "ISC", + "dependencies": { + "@noble/post-quantum": "^0.5.2", + "asmcrypto.js": "^2.3.2", + "faye-websocket": "^0.11.3", + "form-data": "^4.0.4", + "node-rsa": "^1.0.8" + }, + "engines": { + "node": ">=24.13.1" + } + }, + "node_modules/@noble/curves": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/@noble/curves/-/curves-2.0.1.tgz", + "integrity": "sha512-vs1Az2OOTBiP4q0pwjW5aF0xp9n4MxVrmkFBxc6EKZc6ddYx5gaZiAsZoq0uRRXWbi3AT/sBqn05eRPtn1JCPw==", + "license": "MIT", + "dependencies": { + "@noble/hashes": "2.0.1" + }, + "engines": { + "node": ">= 20.19.0" + }, + "funding": { + "url": "https://paulmillr.com/funding/" + } + }, + "node_modules/@noble/hashes": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/@noble/hashes/-/hashes-2.0.1.tgz", + "integrity": "sha512-XlOlEbQcE9fmuXxrVTXCTlG2nlRXa9Rj3rr5Ue/+tX+nmkgbX720YHh0VR3hBF9xDvwnb8D2shVGOwNx+ulArw==", + "license": "MIT", + "engines": { + "node": ">= 20.19.0" + }, + "funding": { + "url": "https://paulmillr.com/funding/" + } + }, + "node_modules/@noble/post-quantum": { + "version": "0.5.4", + "resolved": "https://registry.npmjs.org/@noble/post-quantum/-/post-quantum-0.5.4.tgz", + "integrity": "sha512-leww0zzIirrvwaYMPI9fj6aRIlA/c6Y0/lifQQ1YOOyHEr0MNH3yYpjXeiVG+tWdPps4XxGclFWX2INPO3Yo5w==", + "license": "MIT", + "dependencies": { + "@noble/curves": "~2.0.0", + "@noble/hashes": "~2.0.0" + }, + "engines": { + "node": ">= 20.19.0" + }, + "funding": { + "url": "https://paulmillr.com/funding/" + } + }, + "node_modules/@tsconfig/node10": { + "version": "1.0.12", + "resolved": "https://registry.npmjs.org/@tsconfig/node10/-/node10-1.0.12.tgz", + "integrity": "sha512-UCYBaeFvM11aU2y3YPZ//O5Rhj+xKyzy7mvcIoAjASbigy8mHMryP5cK7dgjlz2hWxh1g5pLw084E0a/wlUSFQ==", + "license": "MIT" + }, + "node_modules/@tsconfig/node12": { + "version": "1.0.11", + "resolved": "https://registry.npmjs.org/@tsconfig/node12/-/node12-1.0.11.tgz", + "integrity": "sha512-cqefuRsh12pWyGsIoBKJA9luFu3mRxCA+ORZvA4ktLSzIuCUtWVxGIuXigEwO5/ywWFMZ2QEGKWvkZG1zDMTag==", + "license": "MIT" + }, + "node_modules/@tsconfig/node14": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/@tsconfig/node14/-/node14-1.0.3.tgz", + "integrity": "sha512-ysT8mhdixWK6Hw3i1V2AeRqZ5WfXg1G43mqoYlM2nc6388Fq5jcXyr5mRsqViLx/GJYdoL0bfXD8nmF+Zn/Iow==", + "license": "MIT" + }, + "node_modules/@tsconfig/node16": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/@tsconfig/node16/-/node16-1.0.4.tgz", + "integrity": "sha512-vxhUy4J8lyeyinH7Azl1pdd43GJhZH/tP2weN8TntQblOY+A0XbT8DJk1/oCPuOOyg/Ja757rG0CgHcWC8OfMA==", + "license": "MIT" + }, + "node_modules/@types/node": { + "version": "25.6.0", + "resolved": "https://registry.npmjs.org/@types/node/-/node-25.6.0.tgz", + "integrity": "sha512-+qIYRKdNYJwY3vRCZMdJbPLJAtGjQBudzZzdzwQYkEPQd+PJGixUL5QfvCLDaULoLv+RhT3LDkwEfKaAkgSmNQ==", + "license": "MIT", + "dependencies": { + "undici-types": "~7.19.0" + } + }, + "node_modules/acorn": { + "version": "8.16.0", + "resolved": "https://registry.npmjs.org/acorn/-/acorn-8.16.0.tgz", + "integrity": "sha512-UVJyE9MttOsBQIDKw1skb9nAwQuR5wuGD3+82K6JgJlm/Y+KI92oNsMNGZCYdDsVtRHSak0pcV5Dno5+4jh9sw==", + "license": "MIT", + "bin": { + "acorn": "bin/acorn" + }, + "engines": { + "node": ">=0.4.0" + } + }, + "node_modules/acorn-walk": { + "version": "8.3.5", + "resolved": "https://registry.npmjs.org/acorn-walk/-/acorn-walk-8.3.5.tgz", + "integrity": "sha512-HEHNfbars9v4pgpW6SO1KSPkfoS0xVOM/9UzkJltjlsHZmJasxg8aXkuZa7SMf8vKGIBhpUsPluQSqhJFCqebw==", + "license": "MIT", + "dependencies": { + "acorn": "^8.11.0" + }, + "engines": { + "node": ">=0.4.0" + } + }, + "node_modules/arg": { + "version": "4.1.3", + "resolved": "https://registry.npmjs.org/arg/-/arg-4.1.3.tgz", + "integrity": "sha512-58S9QDqG0Xx27YwPSt9fJxivjYl432YCwfDMfZ+71RAqUrZef7LrKQZ3LHLOwCS4FLNBplP533Zx895SeOCHvA==", + "license": "MIT" + }, + "node_modules/asmcrypto.js": { + "version": "2.3.2", + "resolved": "https://registry.npmjs.org/asmcrypto.js/-/asmcrypto.js-2.3.2.tgz", + "integrity": "sha512-3FgFARf7RupsZETQ1nHnhLUUvpcttcCq1iZCaVAbJZbCZ5VNRrNyvpDyHTOb0KC3llFcsyOT/a99NZcCbeiEsA==", + "license": "MIT" + }, + "node_modules/asn1": { + "version": "0.2.6", + "resolved": "https://registry.npmjs.org/asn1/-/asn1-0.2.6.tgz", + "integrity": "sha512-ix/FxPn0MDjeyJ7i/yoHGFt/EX6LyNbxSEhPPXODPL+KB0VPk86UYfL0lMdy+KCnv+fmvIzySwaK5COwqVbWTQ==", + "license": "MIT", + "dependencies": { + "safer-buffer": "~2.1.0" + } + }, + "node_modules/asynckit": { + "version": "0.4.0", + "resolved": "https://registry.npmjs.org/asynckit/-/asynckit-0.4.0.tgz", + "integrity": "sha512-Oei9OH4tRh0YqU3GxhX79dM/mwVgvbZJaSNaRk+bshkj0S5cfHcgYakreBjrHwatXKbz+IoIdYLxrKim2MjW0Q==", + "license": "MIT" + }, + "node_modules/call-bind-apply-helpers": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/call-bind-apply-helpers/-/call-bind-apply-helpers-1.0.2.tgz", + "integrity": "sha512-Sp1ablJ0ivDkSzjcaJdxEunN5/XvksFJ2sMBFfq6x0ryhQV/2b/KwFe21cMpmHtPOSij8K99/wSfoEuTObmuMQ==", + "license": "MIT", + "dependencies": { + "es-errors": "^1.3.0", + "function-bind": "^1.1.2" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/combined-stream": { + "version": "1.0.8", + "resolved": "https://registry.npmjs.org/combined-stream/-/combined-stream-1.0.8.tgz", + "integrity": "sha512-FQN4MRfuJeHf7cBbBMJFXhKSDq+2kAArBlmRBvcvFE5BB1HZKXtSFASDhdlz9zOYwxh8lDdnvmMOe/+5cdoEdg==", + "license": "MIT", + "dependencies": { + "delayed-stream": "~1.0.0" + }, + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/create-require": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/create-require/-/create-require-1.1.1.tgz", + "integrity": "sha512-dcKFX3jn0MpIaXjisoRvexIJVEKzaq7z2rZKxf+MSr9TkdmHmsU4m2lcLojrj/FHl8mk5VxMmYA+ftRkP/3oKQ==", + "license": "MIT" + }, + "node_modules/delayed-stream": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/delayed-stream/-/delayed-stream-1.0.0.tgz", + "integrity": "sha512-ZySD7Nf91aLB0RxL4KGrKHBXl7Eds1DAmEdcoVawXnLD7SDhpNgtuII2aAkg7a7QS41jxPSZ17p4VdGnMHk3MQ==", + "license": "MIT", + "engines": { + "node": ">=0.4.0" + } + }, + "node_modules/diff": { + "version": "4.0.4", + "resolved": "https://registry.npmjs.org/diff/-/diff-4.0.4.tgz", + "integrity": "sha512-X07nttJQkwkfKfvTPG/KSnE2OMdcUCao6+eXF3wmnIQRn2aPAHH3VxDbDOdegkd6JbPsXqShpvEOHfAT+nCNwQ==", + "license": "BSD-3-Clause", + "engines": { + "node": ">=0.3.1" + } + }, + "node_modules/dunder-proto": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/dunder-proto/-/dunder-proto-1.0.1.tgz", + "integrity": "sha512-KIN/nDJBQRcXw0MLVhZE9iQHmG68qAVIBg9CqmUYjmQIhgij9U5MFvrqkUL5FbtyyzZuOeOt0zdeRe4UY7ct+A==", + "license": "MIT", + "dependencies": { + "call-bind-apply-helpers": "^1.0.1", + "es-errors": "^1.3.0", + "gopd": "^1.2.0" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/es-define-property": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/es-define-property/-/es-define-property-1.0.1.tgz", + "integrity": "sha512-e3nRfgfUZ4rNGL232gUgX06QNyyez04KdjFrF+LTRoOXmrOgFKDg4BCdsjW8EnT69eqdYGmRpJwiPVYNrCaW3g==", + "license": "MIT", + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/es-errors": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/es-errors/-/es-errors-1.3.0.tgz", + "integrity": "sha512-Zf5H2Kxt2xjTvbJvP2ZWLEICxA6j+hAmMzIlypy4xcBg1vKVnx89Wy0GbS+kf5cwCVFFzdCFh2XSCFNULS6csw==", + "license": "MIT", + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/es-object-atoms": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/es-object-atoms/-/es-object-atoms-1.1.1.tgz", + "integrity": "sha512-FGgH2h8zKNim9ljj7dankFPcICIK9Cp5bm+c2gQSYePhpaG5+esrLODihIorn+Pe6FGJzWhXQotPv73jTaldXA==", + "license": "MIT", + "dependencies": { + "es-errors": "^1.3.0" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/es-set-tostringtag": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/es-set-tostringtag/-/es-set-tostringtag-2.1.0.tgz", + "integrity": "sha512-j6vWzfrGVfyXxge+O0x5sh6cvxAog0a/4Rdd2K36zCMV5eJ+/+tOAngRO8cODMNWbVRdVlmGZQL2YS3yR8bIUA==", + "license": "MIT", + "dependencies": { + "es-errors": "^1.3.0", + "get-intrinsic": "^1.2.6", + "has-tostringtag": "^1.0.2", + "hasown": "^2.0.2" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/faye-websocket": { + "version": "0.11.4", + "resolved": "https://registry.npmjs.org/faye-websocket/-/faye-websocket-0.11.4.tgz", + "integrity": "sha512-CzbClwlXAuiRQAlUyfqPgvPoNKTckTPGfwZV4ZdAhVcP2lh9KUxJg2b5GkE7XbjKQ3YJnQ9z6D9ntLAlB+tP8g==", + "license": "Apache-2.0", + "dependencies": { + "websocket-driver": ">=0.5.1" + }, + "engines": { + "node": ">=0.8.0" + } + }, + "node_modules/form-data": { + "version": "4.0.6", + "resolved": "https://registry.npmjs.org/form-data/-/form-data-4.0.6.tgz", + "integrity": "sha512-vKatAh4SlVfgbv+YtmhiRjhEMJsYpsG1Y2rMQtR+SVSbytsSD1YGzDIcrAJmdFec88u/+VoGmxnl+80gL1tRCQ==", + "dependencies": { + "asynckit": "^0.4.0", + "combined-stream": "^1.0.8", + "es-set-tostringtag": "^2.1.0", + "hasown": "^2.0.4", + "mime-types": "^2.1.35" + }, + "engines": { + "node": ">= 6" + } + }, + "node_modules/function-bind": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/function-bind/-/function-bind-1.1.2.tgz", + "integrity": "sha512-7XHNxH7qX9xG5mIwxkhumTox/MIRNcOgDrxWsMt2pAr23WHp6MrRlN7FBSFpCpr+oVO0F744iUgR82nJMfG2SA==", + "license": "MIT", + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/get-intrinsic": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/get-intrinsic/-/get-intrinsic-1.3.0.tgz", + "integrity": "sha512-9fSjSaos/fRIVIp+xSJlE6lfwhES7LNtKaCBIamHsjr2na1BiABJPo0mOjjz8GJDURarmCPGqaiVg5mfjb98CQ==", + "license": "MIT", + "dependencies": { + "call-bind-apply-helpers": "^1.0.2", + "es-define-property": "^1.0.1", + "es-errors": "^1.3.0", + "es-object-atoms": "^1.1.1", + "function-bind": "^1.1.2", + "get-proto": "^1.0.1", + "gopd": "^1.2.0", + "has-symbols": "^1.1.0", + "hasown": "^2.0.2", + "math-intrinsics": "^1.1.0" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/get-proto": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/get-proto/-/get-proto-1.0.1.tgz", + "integrity": "sha512-sTSfBjoXBp89JvIKIefqw7U2CCebsc74kiY6awiGogKtoSGbgjYE/G/+l9sF3MWFPNc9IcoOC4ODfKHfxFmp0g==", + "license": "MIT", + "dependencies": { + "dunder-proto": "^1.0.1", + "es-object-atoms": "^1.0.0" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/gopd": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/gopd/-/gopd-1.2.0.tgz", + "integrity": "sha512-ZUKRh6/kUFoAiTAtTYPZJ3hw9wNxx+BIBOijnlG9PnrJsCcSjs1wyyD6vJpaYtgnzDrKYRSqf3OO6Rfa93xsRg==", + "license": "MIT", + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/has-symbols": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/has-symbols/-/has-symbols-1.1.0.tgz", + "integrity": "sha512-1cDNdwJ2Jaohmb3sg4OmKaMBwuC48sYni5HUw2DvsC8LjGTLK9h+eb1X6RyuOHe4hT0ULCW68iomhjUoKUqlPQ==", + "license": "MIT", + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/has-tostringtag": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/has-tostringtag/-/has-tostringtag-1.0.2.tgz", + "integrity": "sha512-NqADB8VjPFLM2V0VvHUewwwsw0ZWBaIdgo+ieHtK3hasLz4qeCRjYcqfB6AQrBggRKppKF8L52/VqdVsO47Dlw==", + "license": "MIT", + "dependencies": { + "has-symbols": "^1.0.3" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/hasown": { + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/hasown/-/hasown-2.0.4.tgz", + "integrity": "sha512-T2UbfbBEF32wiepXIsMlTW9+dDYC6wMh/t/vYA4tuOMKqWz/n3vr1NFSxQiyP+zk2mXsoMA/i/7qV6LKut1t1A==", + "dependencies": { + "function-bind": "^1.1.2" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/http-parser-js": { + "version": "0.5.10", + "resolved": "https://registry.npmjs.org/http-parser-js/-/http-parser-js-0.5.10.tgz", + "integrity": "sha512-Pysuw9XpUq5dVc/2SMHpuTY01RFl8fttgcyunjL7eEMhGM3cI4eOmiCycJDVCo/7O7ClfQD3SaI6ftDzqOXYMA==", + "license": "MIT" + }, + "node_modules/make-error": { + "version": "1.3.6", + "resolved": "https://registry.npmjs.org/make-error/-/make-error-1.3.6.tgz", + "integrity": "sha512-s8UhlNe7vPKomQhC1qFelMokr/Sc3AgNbso3n74mVPA5LTZwkB9NlXf4XPamLxJE8h0gh73rM94xvwRT2CVInw==", + "license": "ISC" + }, + "node_modules/math-intrinsics": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/math-intrinsics/-/math-intrinsics-1.1.0.tgz", + "integrity": "sha512-/IXtbwEk5HTPyEwyKX6hGkYXxM9nbj64B+ilVJnC/R6B0pH5G4V3b0pVbL7DBj4tkhBAppbQUlf6F6Xl9LHu1g==", + "license": "MIT", + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/mime-db": { + "version": "1.52.0", + "resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.52.0.tgz", + "integrity": "sha512-sPU4uV7dYlvtWJxwwxHD0PuihVNiE7TyAbQ5SWxDCB9mUYvOgroQOwYQQOKPJ8CIbE+1ETVlOoK1UC2nU3gYvg==", + "license": "MIT", + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/mime-types": { + "version": "2.1.35", + "resolved": "https://registry.npmjs.org/mime-types/-/mime-types-2.1.35.tgz", + "integrity": "sha512-ZDY+bPm5zTTF+YpCrAU9nK0UgICYPT0QtT1NZWFv4s++TNkcgVaT0g6+4R2uI4MjQjzysHB1zxuWL50hzaeXiw==", + "license": "MIT", + "dependencies": { + "mime-db": "1.52.0" + }, + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/node-rsa": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/node-rsa/-/node-rsa-1.1.1.tgz", + "integrity": "sha512-Jd4cvbJMryN21r5HgxQOpMEqv+ooke/korixNNK3mGqfGJmy0M77WDDzo/05969+OkMy3XW1UuZsSmW9KQm7Fw==", + "license": "MIT", + "dependencies": { + "asn1": "^0.2.4" + } + }, + "node_modules/prettier": { + "version": "3.8.3", + "resolved": "https://registry.npmjs.org/prettier/-/prettier-3.8.3.tgz", + "integrity": "sha512-7igPTM53cGHMW8xWuVTydi2KO233VFiTNyF5hLJqpilHfmn8C8gPf+PS7dUT64YcXFbiMGZxS9pCSxL/Dxm/Jw==", + "dev": true, + "license": "MIT", + "bin": { + "prettier": "bin/prettier.cjs" + }, + "engines": { + "node": ">=14" + }, + "funding": { + "url": "https://github.com/prettier/prettier?sponsor=1" + } + }, + "node_modules/safe-buffer": { + "version": "5.2.1", + "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.2.1.tgz", + "integrity": "sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ], + "license": "MIT" + }, + "node_modules/safer-buffer": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/safer-buffer/-/safer-buffer-2.1.2.tgz", + "integrity": "sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg==", + "license": "MIT" + }, + "node_modules/ts-node": { + "version": "10.9.2", + "resolved": "https://registry.npmjs.org/ts-node/-/ts-node-10.9.2.tgz", + "integrity": "sha512-f0FFpIdcHgn8zcPSbf1dRevwt047YMnaiJM3u2w2RewrB+fob/zePZcrOyQoLMMO7aBIddLcQIEK5dYjkLnGrQ==", + "license": "MIT", + "dependencies": { + "@cspotcode/source-map-support": "^0.8.0", + "@tsconfig/node10": "^1.0.7", + "@tsconfig/node12": "^1.0.7", + "@tsconfig/node14": "^1.0.0", + "@tsconfig/node16": "^1.0.2", + "acorn": "^8.4.1", + "acorn-walk": "^8.1.1", + "arg": "^4.1.0", + "create-require": "^1.1.0", + "diff": "^4.0.1", + "make-error": "^1.1.1", + "v8-compile-cache-lib": "^3.0.1", + "yn": "3.1.1" + }, + "bin": { + "ts-node": "dist/bin.js", + "ts-node-cwd": "dist/bin-cwd.js", + "ts-node-esm": "dist/bin-esm.js", + "ts-node-script": "dist/bin-script.js", + "ts-node-transpile-only": "dist/bin-transpile.js", + "ts-script": "dist/bin-script-deprecated.js" + }, + "peerDependencies": { + "@swc/core": ">=1.2.50", + "@swc/wasm": ">=1.2.50", + "@types/node": "*", + "typescript": ">=2.7" + }, + "peerDependenciesMeta": { + "@swc/core": { + "optional": true + }, + "@swc/wasm": { + "optional": true } + } + }, + "node_modules/typescript": { + "version": "4.9.5", + "resolved": "https://registry.npmjs.org/typescript/-/typescript-4.9.5.tgz", + "integrity": "sha512-1FXk9E2Hm+QzZQ7z+McJiHL4NW1F2EzMu9Nq9i3zAaGqibafqYwCVU6WyWAuyQRRzOlxou8xZSyXLEN8oKj24g==", + "license": "Apache-2.0", + "bin": { + "tsc": "bin/tsc", + "tsserver": "bin/tsserver" + }, + "engines": { + "node": ">=4.2.0" + } + }, + "node_modules/undici-types": { + "version": "7.19.2", + "resolved": "https://registry.npmjs.org/undici-types/-/undici-types-7.19.2.tgz", + "integrity": "sha512-qYVnV5OEm2AW8cJMCpdV20CDyaN3g0AjDlOGf1OW4iaDEx8MwdtChUp4zu4H0VP3nDRF/8RKWH+IPp9uW0YGZg==", + "license": "MIT" + }, + "node_modules/v8-compile-cache-lib": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/v8-compile-cache-lib/-/v8-compile-cache-lib-3.0.1.tgz", + "integrity": "sha512-wa7YjyUGfNZngI/vtK0UHAN+lgDCxBPCylVXGp0zu59Fz5aiGtNXaq3DhIov063MorB+VfufLh3JlF2KdTK3xg==", + "license": "MIT" + }, + "node_modules/websocket-driver": { + "version": "0.7.4", + "resolved": "https://registry.npmjs.org/websocket-driver/-/websocket-driver-0.7.4.tgz", + "integrity": "sha512-b17KeDIQVjvb0ssuSDF2cYXSg2iztliJ4B9WdsuB6J952qCPKmnVq4DyW5motImXHDC1cBT/1UezrJVsKw5zjg==", + "license": "Apache-2.0", + "dependencies": { + "http-parser-js": ">=0.5.1", + "safe-buffer": ">=5.1.0", + "websocket-extensions": ">=0.1.1" + }, + "engines": { + "node": ">=0.8.0" + } + }, + "node_modules/websocket-extensions": { + "version": "0.1.4", + "resolved": "https://registry.npmjs.org/websocket-extensions/-/websocket-extensions-0.1.4.tgz", + "integrity": "sha512-OqedPIGOfsDlo31UNwYbCFMSaO9m9G/0faIHj5/dZFDMFqPTcx6UwqyOy3COEaEOg/9VsGIpdqn62W5KhoKSpg==", + "license": "Apache-2.0", + "engines": { + "node": ">=0.8.0" + } + }, + "node_modules/yn": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/yn/-/yn-3.1.1.tgz", + "integrity": "sha512-Ux4ygGWsu2c7isFWe8Yu1YluJmqVhxqK2cLXNQA5AcC3QfbGNpM7fu0Y8b/z16pXLnFxZYvWhd3fhBY9DLmC6Q==", + "license": "MIT", + "engines": { + "node": ">=6" + } } + } } diff --git a/KeeperSdk/src/auth/ConsoleLogin.ts b/KeeperSdk/src/auth/ConsoleLogin.ts index 3d0907e3..545932f9 100644 --- a/KeeperSdk/src/auth/ConsoleLogin.ts +++ b/KeeperSdk/src/auth/ConsoleLogin.ts @@ -236,7 +236,8 @@ function unsuppressLogs(): () => void { function unsuppressedAuthUI(): AuthUI3 { const ui = new ConsoleAuthUI() - const wrap = (fn: (...args: A) => Promise) => + const wrap = + (fn: (...args: A) => Promise) => async (...args: A): Promise => { const restore = unsuppressLogs() try { diff --git a/KeeperSdk/src/auth/SessionManager.ts b/KeeperSdk/src/auth/SessionManager.ts index ec3c7a9b..54d64d34 100644 --- a/KeeperSdk/src/auth/SessionManager.ts +++ b/KeeperSdk/src/auth/SessionManager.ts @@ -244,9 +244,7 @@ export class SessionManager implements SessionStorage { const keeperConfig = await this.loadKeeperConfig() if (keeperConfig.users && keeperConfig.devices) { - const user = keeperConfig.users.find( - (configUser) => configUser.user?.toLowerCase() === normalizedUsername - ) + const user = keeperConfig.users.find((configUser) => configUser.user?.toLowerCase() === normalizedUsername) if (user?.last_device?.device_token) { const deviceTokenStr = user.last_device.device_token const device = keeperConfig.devices.find((configDevice) => configDevice.device_token === deviceTokenStr) diff --git a/KeeperSdk/src/enterpriseReport/EnterpriseReportManager.ts b/KeeperSdk/src/enterpriseReport/EnterpriseReportManager.ts index 92b28e2d..d7862c7a 100644 --- a/KeeperSdk/src/enterpriseReport/EnterpriseReportManager.ts +++ b/KeeperSdk/src/enterpriseReport/EnterpriseReportManager.ts @@ -2,12 +2,7 @@ import type { Auth } from '@keeper-security/keeperapi' import { KeeperSdkError, ResultCodes } from '../utils' import { runAuditReport } from './auditReport' import { runActionReport } from './actionReport' -import type { - ActionReportOptions, - ActionReportResult, - AuditReportOptions, - AuditReportResult, -} from './reportTypes' +import type { ActionReportOptions, ActionReportResult, AuditReportOptions, AuditReportResult } from './reportTypes' import type { AuthProvider } from './reportUtils' export class EnterpriseReportManager { diff --git a/KeeperSdk/src/enterpriseReport/actionReport.ts b/KeeperSdk/src/enterpriseReport/actionReport.ts index c59fb2d3..aeece149 100644 --- a/KeeperSdk/src/enterpriseReport/actionReport.ts +++ b/KeeperSdk/src/enterpriseReport/actionReport.ts @@ -3,12 +3,7 @@ import { getAuditEventReportsCommand } from '@keeper-security/keeperapi' import { KeeperSdkError, ResultCodes, extractErrorMessage } from '../utils' import { actionUsers, UserAction } from '../users/actionUser' import { deleteUsers } from '../users/deleteUser' -import { - DeleteUserStatus, - EnterpriseUserStatus, - formatTransferStatus, - formatUserStatus, -} from '../users/userTypes' +import { DeleteUserStatus, EnterpriseUserStatus, formatTransferStatus, formatUserStatus } from '../users/userTypes' import { EnterpriseDataInclude, EnterpriseDataManager, @@ -70,9 +65,7 @@ const ALLOWED_ACTIONS: Readonly EnterpriseUser[] -): TargetAuditConfig { +function usernameTargetConfig(pickCandidates: (users: EnterpriseUser[]) => EnterpriseUser[]): TargetAuditConfig { return { auditColumn: 'username', auditFilterField: 'username', @@ -102,10 +95,7 @@ const TARGET_AUDIT_CONFIG: Record = { ), } -export async function runActionReport( - auth: Auth, - options: ActionReportOptions = {} -): Promise { +export async function runActionReport(auth: Auth, options: ActionReportOptions = {}): Promise { const target = options.target ?? TargetUserStatus.NoLogon const daysSince = options.daysSince ?? ACTION_DEFAULT_DAYS_BY_TARGET[target] ?? ACTION_DEFAULT_DAYS const applyAction = options.applyAction ?? AdminAction.None @@ -165,9 +155,7 @@ async function generateActionReportEntries( let candidates = config.pickCandidates(data.users || []) if (options.nodeIds) { - candidates = candidates.filter( - (user) => user.node_id != null && options.nodeIds!.has(user.node_id) - ) + candidates = candidates.filter((user) => user.node_id != null && options.nodeIds!.has(user.node_id)) } if (candidates.length === 0) return [] @@ -245,11 +233,15 @@ function buildActionEntryContext(data: GetEnterpriseDataResponse): ActionEntryCo const nodePaths = new Map( nodes.map((node) => [ node.node_id, - EnterpriseDataManager.getNodePath(nodes, node.node_id, { omitRoot: false }), + EnterpriseDataManager.getNodePath(nodes, node.node_id, { + omitRoot: false, + }), ]) ) const teamNames = new Map((data.teams || []).map((team) => [team.team_uid, team.name])) - const roleNames = new Map((data.roles || []).map((role) => [role.role_id, role.displayName || String(role.role_id)])) + const roleNames = new Map( + (data.roles || []).map((role) => [role.role_id, role.displayName || String(role.role_id)]) + ) return { nodePaths, @@ -274,10 +266,7 @@ function buildActionEntry(user: EnterpriseUser, context: ActionEntryContext): Ac } } -function buildUserTeamNames( - links: EnterpriseTeamUserLink[], - teamNames: Map -): Map { +function buildUserTeamNames(links: EnterpriseTeamUserLink[], teamNames: Map): Map { const map = new Map>() for (const link of links) { if (!link.team_uid) continue @@ -347,13 +336,28 @@ async function applyAdminAction( const { applyAction, targetUser, dryRun } = options if (applyAction === AdminAction.None) { - return { action: AdminAction.None, status: 'none', affectedCount: 0, serverMessage: 'n/a' } + return { + action: AdminAction.None, + status: 'none', + affectedCount: 0, + serverMessage: 'n/a', + } } if (entries.length === 0) { - return { action: applyAction, status: 'no users matched', affectedCount: 0, serverMessage: 'n/a' } + return { + action: applyAction, + status: 'no users matched', + affectedCount: 0, + serverMessage: 'n/a', + } } if (dryRun) { - return { action: applyAction, status: 'dry run', affectedCount: entries.length, serverMessage: 'n/a' } + return { + action: applyAction, + status: 'dry run', + affectedCount: entries.length, + serverMessage: 'n/a', + } } const emails = entries.map((entry) => entry.email) @@ -361,7 +365,10 @@ async function applyAdminAction( try { switch (applyAction) { case AdminAction.Lock: { - const result = await actionUsers(auth, { action: UserAction.Lock, emails }) + const result = await actionUsers(auth, { + action: UserAction.Lock, + emails, + }) return { action: AdminAction.Lock, status: result.success ? 'success' : 'partial', @@ -392,7 +399,12 @@ async function applyAdminAction( ) } default: - return { action: applyAction, status: 'unsupported', affectedCount: 0, serverMessage: 'n/a' } + return { + action: applyAction, + status: 'unsupported', + affectedCount: 0, + serverMessage: 'n/a', + } } } catch (err) { return { diff --git a/KeeperSdk/src/enterpriseReport/auditReport.ts b/KeeperSdk/src/enterpriseReport/auditReport.ts index c0a975cd..81bb4bc9 100644 --- a/KeeperSdk/src/enterpriseReport/auditReport.ts +++ b/KeeperSdk/src/enterpriseReport/auditReport.ts @@ -103,18 +103,15 @@ async function runDimensionReport(auth: Auth, options: AuditReportOptions): Prom } } -async function runRawReport( - auth: Auth, - options: AuditReportOptions, - hasAram: boolean -): Promise { +async function runRawReport(auth: Auth, options: AuditReportOptions, hasAram: boolean): Promise { let filter = await resolveFilter(auth, options.filter ?? {}) let limit = options.limit let order = options.order if (!hasAram) { const requested = options.limit - limit = requested != null && requested > 0 ? Math.min(requested, AUDIT_NO_ARAM_RAW_LIMIT) : AUDIT_NO_ARAM_RAW_LIMIT + limit = + requested != null && requested > 0 ? Math.min(requested, AUDIT_NO_ARAM_RAW_LIMIT) : AUDIT_NO_ARAM_RAW_LIMIT order = order ?? AuditReportOrder.Desc if (!filter.created) { filter.created = 'last_30_days' @@ -147,7 +144,9 @@ async function runRawReport( } rows.push( fields.map((field) => - field === 'message' ? eventMessage(event, templates) : formatFieldValue(field, getAuditEventField(event, field), 'raw') + field === 'message' + ? eventMessage(event, templates) + : formatFieldValue(field, getAuditEventField(event, field), 'raw') ) ) } @@ -178,8 +177,7 @@ async function runSummaryReport( throw new KeeperSdkError('"columns" parameter cannot be empty.', ResultCodes.AUDIT_COLUMNS_REQUIRED) } - const aggregates = - options.aggregates?.length ? options.aggregates : [AuditAggregate.Occurrences] + const aggregates = options.aggregates?.length ? options.aggregates : [AuditAggregate.Occurrences] const events = await fetchSummaryEvents(auth, { reportType, filter: await resolveFilter(auth, options.filter), @@ -320,7 +318,9 @@ async function resolveFilter(auth: Auth, filter: AuditReportFilter = {}): Promis const city = (parts.pop() || '').trim().toLowerCase() for (const geo of await loadDimension(auth, 'geo_location')) { if (!geo || typeof geo !== 'object') continue - const row = geo as AuditDimensionIpAddress & { ip_addresses?: string[] } + const row = geo as AuditDimensionIpAddress & { + ip_addresses?: string[] + } if ((row.country_code || '').toLowerCase() !== country) continue if (region && (row.region || '').toLowerCase() !== region) continue if (city && (row.city || '').toLowerCase() !== city) continue @@ -353,7 +353,9 @@ async function resolveFilter(auth: Auth, filter: AuditReportFilter = {}): Promis } for (const row of await loadDimension(auth, 'device_type')) { if (!row || typeof row !== 'object') continue - const ver = row as AuditDimensionKeeperVersion & { version_ids?: number[] } + const ver = row as AuditDimensionKeeperVersion & { + version_ids?: number[] + } if (deviceType) { const typeName = (ver.type_name || '').toLowerCase() const typeCategory = (ver.type_category || '').toLowerCase() @@ -415,7 +417,10 @@ async function fetchDimensionRows(auth: Auth, dimension: string): Promise>() for (const row of sourceRows) { if (!row || typeof row !== 'object') continue - const ipRow = row as AuditDimensionIpAddress & { ip_addresses?: string[] } + const ipRow = row as AuditDimensionIpAddress & { + ip_addresses?: string[] + } if (!ipRow.geo_location || !ipRow.ip_address) continue const existing = geoMap.get(ipRow.geo_location) if (existing) (existing.ip_addresses as string[]).push(ipRow.ip_address) @@ -445,7 +452,9 @@ function buildVirtualDimension(dimension: string, sourceRows: AuditDimensionRow[ const deviceMap = new Map>() for (const row of sourceRows) { if (!row || typeof row !== 'object') continue - const versionRow = row as AuditDimensionKeeperVersion & { version_ids?: number[] } + const versionRow = row as AuditDimensionKeeperVersion & { + version_ids?: number[] + } if (!versionRow.type_id || !versionRow.version_id) continue const existing = deviceMap.get(versionRow.type_id) if (existing) (existing.version_ids as number[]).push(versionRow.version_id) @@ -544,9 +553,7 @@ function advanceCreatedFilter( ): AuditReportFilter { const next: AuditReportFilter = { ...(filter || {}) } const criteria: CreatedFilterCriteria = - next.created && typeof next.created === 'object' && !Array.isArray(next.created) - ? { ...next.created } - : {} + next.created && typeof next.created === 'object' && !Array.isArray(next.created) ? { ...next.created } : {} if (order === AuditReportOrder.Asc) { criteria.fromDate = timestamp criteria.excludeFrom = false diff --git a/KeeperSdk/src/enterpriseReport/index.ts b/KeeperSdk/src/enterpriseReport/index.ts index 3acf2bfd..60706a9a 100644 --- a/KeeperSdk/src/enterpriseReport/index.ts +++ b/KeeperSdk/src/enterpriseReport/index.ts @@ -1,11 +1,5 @@ -export { - runAuditReport, -} from './auditReport' -export { - runActionReport, - getAllowedActions, - getDefaultDaysSince, -} from './actionReport' +export { runAuditReport } from './auditReport' +export { runActionReport, getAllowedActions, getDefaultDaysSince } from './actionReport' export { runPasswordReport, getPasswordStrength, @@ -15,7 +9,10 @@ export { buildPasswordPolicySummary, } from './passwordReport' export { EnterpriseReportManager } from './EnterpriseReportManager' -export { EnterpriseReportManager as AuditReportManager, EnterpriseReportManager as ActionReportManager } from './EnterpriseReportManager' +export { + EnterpriseReportManager as AuditReportManager, + EnterpriseReportManager as ActionReportManager, +} from './EnterpriseReportManager' export type { AuthProvider } from './reportUtils' export { AuditReportOrder, diff --git a/KeeperSdk/src/enterpriseReport/passwordReport.ts b/KeeperSdk/src/enterpriseReport/passwordReport.ts index 3cac6a4b..f6cfa47f 100644 --- a/KeeperSdk/src/enterpriseReport/passwordReport.ts +++ b/KeeperSdk/src/enterpriseReport/passwordReport.ts @@ -2,11 +2,7 @@ import type { DBWRecord, DRecord } from '@keeper-security/keeperapi' import { InMemoryStorage } from '../storage/InMemoryStorage' import { resolveSingleFolder, type VaultFolderSession } from '../folders/changeDirectory' import { listFolder } from '../folders/listFolder' -import { - getRecordPassword, - getRecordSummary, - getRecordTitle, -} from '../records/RecordUtils' +import { getRecordPassword, getRecordSummary, getRecordTitle } from '../records/RecordUtils' import { KeeperSdkError, ResultCodes } from '../utils' import { DEFAULT_TRUNCATION_LENGTH, @@ -23,7 +19,10 @@ import { const POLICY_FIELD_COUNT = 5 const SPECIAL_CHAR_SET = new Set(PW_SPECIAL_CHARACTERS.split('')) -const POLICY_SUMMARY_LABELS: ReadonlyArray<{ key: keyof PasswordPolicy; label: string }> = [ +const POLICY_SUMMARY_LABELS: ReadonlyArray<{ + key: keyof PasswordPolicy + label: string +}> = [ { key: 'length', label: 'length' }, { key: 'lower', label: 'lowercase' }, { key: 'upper', label: 'uppercase' }, @@ -250,9 +249,7 @@ export async function runPasswordReport( breachWatchPasswordCounts, } - const rows = targetRecords.flatMap((record) => - buildNonCompliantRow(record, policy, verbose, verboseContext) - ) + const rows = targetRecords.flatMap((record) => buildNonCompliantRow(record, policy, verbose, verboseContext)) return { policy, diff --git a/KeeperSdk/src/enterpriseReport/reportTypes.ts b/KeeperSdk/src/enterpriseReport/reportTypes.ts index f3cde4f6..df782e1c 100644 --- a/KeeperSdk/src/enterpriseReport/reportTypes.ts +++ b/KeeperSdk/src/enterpriseReport/reportTypes.ts @@ -96,13 +96,7 @@ export enum AuditAggregate { LastCreated = 'last_created', } -export const SUMMARY_REPORT_TYPES: readonly AuditSummaryReportType[] = [ - 'hour', - 'day', - 'week', - 'month', - 'span', -] +export const SUMMARY_REPORT_TYPES: readonly AuditSummaryReportType[] = ['hour', 'day', 'week', 'month', 'span'] export const CREATED_PRESETS = [ 'today', diff --git a/KeeperSdk/src/enterpriseReport/reportUtils.ts b/KeeperSdk/src/enterpriseReport/reportUtils.ts index cf647d99..dbe43d01 100644 --- a/KeeperSdk/src/enterpriseReport/reportUtils.ts +++ b/KeeperSdk/src/enterpriseReport/reportUtils.ts @@ -10,11 +10,7 @@ export function resolveTimezone(timezone: string | undefined): string { return `Etc/GMT${hours >= 0 ? '+' : ''}${hours}` } -export function assertSucceeded( - response: KeeperResponse, - fallbackMessage: string, - fallbackCode: string -): void { +export function assertSucceeded(response: KeeperResponse, fallbackMessage: string, fallbackCode: string): void { if ((response.result || '').toLowerCase() === 'fail') { throw new KeeperSdkError( response.message || response.result_code || fallbackMessage, diff --git a/KeeperSdk/src/folders/addFolder.ts b/KeeperSdk/src/folders/addFolder.ts index c90b724c..80d40bee 100644 --- a/KeeperSdk/src/folders/addFolder.ts +++ b/KeeperSdk/src/folders/addFolder.ts @@ -56,7 +56,10 @@ function resolveParentContext(storage: InMemoryStorage, parentUid: string | null } const sharedFolder = storage.getByUid(FolderKind.SharedFolder, parentUid) if (sharedFolder) { - return { kind: ParentFolderKind.SharedFolder, sharedScopeUid: sharedFolder.uid } + return { + kind: ParentFolderKind.SharedFolder, + sharedScopeUid: sharedFolder.uid, + } } const sharedFolderFolder = storage.getByUid(FolderKind.SharedFolderFolder, parentUid) if (sharedFolderFolder) { diff --git a/KeeperSdk/src/folders/changeDirectory.ts b/KeeperSdk/src/folders/changeDirectory.ts index 7f8aeb96..9137ee4a 100644 --- a/KeeperSdk/src/folders/changeDirectory.ts +++ b/KeeperSdk/src/folders/changeDirectory.ts @@ -25,7 +25,11 @@ export function createVaultFolderSession(): VaultFolderSession { function getFolderEntryByUid(storage: InMemoryStorage, uid: string): ListFolderFolderSimple | undefined { const userFolder = storage.getByUid(FolderKind.UserFolder, uid) if (userFolder) { - return { uid: userFolder.uid, name: userFolderName(userFolder), folderKind: FolderKind.UserFolder } + return { + uid: userFolder.uid, + name: userFolderName(userFolder), + folderKind: FolderKind.UserFolder, + } } const sharedFolder = storage.getByUid(FolderKind.SharedFolder, uid) if (sharedFolder) { @@ -88,10 +92,7 @@ async function listFolderChildrenForCd( return result.folders } -function findChildFolder( - children: ListFolderFolderSimple[], - component: string -): ListFolderFolderSimple | undefined { +function findChildFolder(children: ListFolderFolderSimple[], component: string): ListFolderFolderSimple | undefined { const trimmedComponent = component.trim() if (!trimmedComponent) return undefined const matchByUid = children.find((child) => child.uid === trimmedComponent) diff --git a/KeeperSdk/src/folders/deleteFolder.ts b/KeeperSdk/src/folders/deleteFolder.ts index 93a512fe..09731a54 100644 --- a/KeeperSdk/src/folders/deleteFolder.ts +++ b/KeeperSdk/src/folders/deleteFolder.ts @@ -116,10 +116,7 @@ export async function buildFolderDeleteObject( return null } -async function buildDeleteObjectForFolderRef( - storage: InMemoryStorage, - ref: string -): Promise { +async function buildDeleteObjectForFolderRef(storage: InMemoryStorage, ref: string): Promise { const trimmed = ref.trim() if (!trimmed) return null @@ -143,10 +140,7 @@ export async function deleteFolder( if (deleteObject) objects.push(deleteObject) } if (objects.length === 0) { - throw new KeeperSdkError( - 'No folders found to delete (not a folder UID or name).', - 'delete_nothing' - ) + throw new KeeperSdkError('No folders found to delete (not a folder UID or name).', 'delete_nothing') } const targetUids = objects.map((deleteObject) => deleteObject.object_uid).join(', ') diff --git a/KeeperSdk/src/folders/folderTree.ts b/KeeperSdk/src/folders/folderTree.ts index 03f1dfd2..d1594c72 100644 --- a/KeeperSdk/src/folders/folderTree.ts +++ b/KeeperSdk/src/folders/folderTree.ts @@ -264,7 +264,10 @@ function gatherItems(node: FolderTreeNode): TreeItem[] { const items: TreeItem[] = [] if (node.permissions) { for (const permission of node.permissions) { - items.push({ kind: TreeItemKind.Permission, display: permission.display }) + items.push({ + kind: TreeItemKind.Permission, + display: permission.display, + }) } } for (const child of node.children) { diff --git a/KeeperSdk/src/folders/listFolder.ts b/KeeperSdk/src/folders/listFolder.ts index 619dd4f9..ca60f8a1 100644 --- a/KeeperSdk/src/folders/listFolder.ts +++ b/KeeperSdk/src/folders/listFolder.ts @@ -289,13 +289,21 @@ export async function listFolder(storage: InMemoryStorage, options: ListFolderOp if (!userFolder) continue const name = userFolderName(userFolder) if (!matches(name, userFolder.uid)) continue - folderRows.push({ uid: userFolder.uid, name, folderKind: FolderKind.UserFolder }) + folderRows.push({ + uid: userFolder.uid, + name, + folderKind: FolderKind.UserFolder, + }) } else if (dependency.kind === FolderKind.SharedFolder && showFolders && parentKey !== null) { const sharedFolder = storage.getByUid(FolderKind.SharedFolder, dependency.uid) if (!sharedFolder) continue const name = sharedFolderName(sharedFolder) if (!matches(name, sharedFolder.uid)) continue - folderRows.push({ uid: sharedFolder.uid, name, folderKind: FolderKind.SharedFolder }) + folderRows.push({ + uid: sharedFolder.uid, + name, + folderKind: FolderKind.SharedFolder, + }) } else if (dependency.kind === FolderKind.SharedFolderFolder && showFolders && parentKey !== null) { const sharedFolderFolder = storage.getByUid( FolderKind.SharedFolderFolder, diff --git a/KeeperSdk/src/folders/updateFolder.ts b/KeeperSdk/src/folders/updateFolder.ts index d444c56f..09ff36ad 100644 --- a/KeeperSdk/src/folders/updateFolder.ts +++ b/KeeperSdk/src/folders/updateFolder.ts @@ -1,10 +1,5 @@ import type { Auth, FolderUpdateRequest } from '@keeper-security/keeperapi' -import { - encryptForStorage, - encryptObjectForStorage, - folderUpdateCommand, - platform, -} from '@keeper-security/keeperapi' +import { encryptForStorage, encryptObjectForStorage, folderUpdateCommand, platform } from '@keeper-security/keeperapi' import type { DSharedFolder, DSharedFolderFolder, DUserFolder } from '@keeper-security/keeperapi' import { InMemoryStorage } from '../storage/InMemoryStorage' import { anyIsBoolean, isBoolean, isObject, KeeperSdkError, extractErrorMessage } from '../utils' @@ -81,12 +76,7 @@ export async function updateFolder( const trimmedName = input.folderName?.trim() || '' if (trimmedName) validateFolderName(trimmedName) - const hasPermissionUpdate = anyIsBoolean( - input.manageUsers, - input.manageRecords, - input.canShare, - input.canEdit - ) + const hasPermissionUpdate = anyIsBoolean(input.manageUsers, input.manageRecords, input.canShare, input.canEdit) if (resolved.kind === FolderKind.UserFolder || resolved.kind === FolderKind.SharedFolderFolder) { if (!trimmedName) { diff --git a/KeeperSdk/src/index.ts b/KeeperSdk/src/index.ts index 17ee6f53..33ce69a1 100644 --- a/KeeperSdk/src/index.ts +++ b/KeeperSdk/src/index.ts @@ -163,12 +163,7 @@ export type { AddFolderInput, AddFolderResult, MkdirOptions } from './folders/ad export { updateFolder, renameFolder, updateSharedFolderPermissions } from './folders/updateFolder' export type { UpdateFolderInput, UpdateFolderResult, RenameFolderResult } from './folders/updateFolder' -export { - deleteFolder, - rmdir, - resolveRmdirPatternsToFolderUids, - buildFolderDeleteObject, -} from './folders/deleteFolder' +export { deleteFolder, rmdir, resolveRmdirPatternsToFolderUids, buildFolderDeleteObject } from './folders/deleteFolder' export type { DeleteFolderResult, RmdirOptions } from './folders/deleteFolder' export { @@ -202,10 +197,7 @@ export type { FormatTeamsTableOptions, } from './teams/listTeams' -export { - EnterpriseDataInclude, - EnterpriseDataManager, -} from './teams/enterpriseData' +export { EnterpriseDataInclude, EnterpriseDataManager } from './teams/enterpriseData' export type { EnterpriseDataManagerApi, GetEnterpriseDataResponse, @@ -368,12 +360,7 @@ export type { FormattedAddTeamRow, } from './teams/addTeam' -export { - updateTeams, - formatUpdateTeamResult, - renderUpdateTeamAsciiTable, - UpdateTeamStatus, -} from './teams/updateTeam' +export { updateTeams, formatUpdateTeamResult, renderUpdateTeamAsciiTable, UpdateTeamStatus } from './teams/updateTeam' export type { UpdateTeamInput, UpdateTeamResult, @@ -382,12 +369,7 @@ export type { FormattedUpdateTeamRow, } from './teams/updateTeam' -export { - deleteTeams, - formatDeleteTeamResult, - renderDeleteTeamAsciiTable, - DeleteTeamStatus, -} from './teams/deleteTeam' +export { deleteTeams, formatDeleteTeamResult, renderDeleteTeamAsciiTable, DeleteTeamStatus } from './teams/deleteTeam' export type { DeleteTeamInput, DeleteTeamResult, @@ -417,19 +399,9 @@ export { AddUserSkipReason, } from './users/addUser' -export { - updateUsers, - formatUpdateUserResult, - renderUpdateUserAsciiTable, - UpdateUserStatus, -} from './users/updateUser' +export { updateUsers, formatUpdateUserResult, renderUpdateUserAsciiTable, UpdateUserStatus } from './users/updateUser' -export { - deleteUsers, - formatDeleteUserResult, - renderDeleteUserAsciiTable, - DeleteUserStatus, -} from './users/deleteUser' +export { deleteUsers, formatDeleteUserResult, renderDeleteUserAsciiTable, DeleteUserStatus } from './users/deleteUser' export { actionUsers, @@ -481,10 +453,7 @@ export type { export { EnterpriseUserStatus } from './users/userTypes' -export { - aliasUser, - AliasOperation, -} from './users/aliasUser' +export { aliasUser, AliasOperation } from './users/aliasUser' export { addUsersToTeams, @@ -698,4 +667,4 @@ export type { AuthUI3, KeeperError, LoginError, -} from '@keeper-security/keeperapi' \ No newline at end of file +} from '@keeper-security/keeperapi' diff --git a/KeeperSdk/src/nestedShareFolders/NestedShareFolderManager.ts b/KeeperSdk/src/nestedShareFolders/NestedShareFolderManager.ts index f3c9d4b8..48032775 100644 --- a/KeeperSdk/src/nestedShareFolders/NestedShareFolderManager.ts +++ b/KeeperSdk/src/nestedShareFolders/NestedShareFolderManager.ts @@ -100,9 +100,7 @@ export class NestedShareFolderManager { return removeNestedShareFolders(this.storage, this.requireAuth(), input) } - public async getNestedShareRecordDetails( - input: GetNsfRecordDetailsInput - ): Promise { + public async getNestedShareRecordDetails(input: GetNsfRecordDetailsInput): Promise { return getNestedShareRecordDetails(this.storage, this.requireAuth(), input) } @@ -128,15 +126,11 @@ export class NestedShareFolderManager { return updateNestedShareFolder(this.storage, this.requireAuth(), input) } - public async shareNestedShareFolder( - input: ShareNestedShareFolderInput - ): Promise { + public async shareNestedShareFolder(input: ShareNestedShareFolderInput): Promise { return shareNestedShareFolder(this.storage, this.requireAuth(), input) } - public async shareNestedShareRecord( - input: ShareNestedShareRecordInput - ): Promise { + public async shareNestedShareRecord(input: ShareNestedShareRecordInput): Promise { return shareNestedShareRecord(this.storage, this.requireAuth(), input) } diff --git a/KeeperSdk/src/nestedShareFolders/addNsfRecord.ts b/KeeperSdk/src/nestedShareFolders/addNsfRecord.ts index e6e26009..bf2103f8 100644 --- a/KeeperSdk/src/nestedShareFolders/addNsfRecord.ts +++ b/KeeperSdk/src/nestedShareFolders/addNsfRecord.ts @@ -10,10 +10,7 @@ import { import type { InMemoryStorage } from '../storage/InMemoryStorage' import { KeeperSdkError, ResultCodes, extractErrorMessage } from '../utils' import { NSF_MAX_RECORD_BATCH } from './nsfConstants' -import { - buildNsfRecordData, - getPaddedJsonBytes, -} from './nsfRecordData' +import { buildNsfRecordData, getPaddedJsonBytes } from './nsfRecordData' import { ensureNestedShareFolder, nsfToNumber, @@ -45,10 +42,7 @@ function resolveFolderUid(storage: InMemoryStorage, folderInput?: string): strin async function requireFolderKey(storage: InMemoryStorage, folderUid: string): Promise { const folderKey = await storage.getKeyBytes(folderUid) if (folderKey) return folderKey - throw new KeeperSdkError( - `Folder key not found for ${folderUid}. Run sync() first.`, - ResultCodes.NSF_MISSING_KEY - ) + throw new KeeperSdkError(`Folder key not found for ${folderUid}. Run sync() first.`, ResultCodes.NSF_MISSING_KEY) } async function buildRecordAddPayload( @@ -185,7 +179,9 @@ export async function addNestedShareRecord( auth: Auth, input: AddNsfRecordInput ): Promise { - const { added } = await addNestedShareRecords(storage, auth, { records: [input] }) + const { added } = await addNestedShareRecords(storage, auth, { + records: [input], + }) if (!added[0]) { throw new KeeperSdkError('Failed to add nested share record.', ResultCodes.NSF_ADD_FAILED) } diff --git a/KeeperSdk/src/nestedShareFolders/getNsf.ts b/KeeperSdk/src/nestedShareFolders/getNsf.ts index 91ce48d7..fba51e7f 100644 --- a/KeeperSdk/src/nestedShareFolders/getNsf.ts +++ b/KeeperSdk/src/nestedShareFolders/getNsf.ts @@ -161,7 +161,10 @@ function ensureFolderOwnerListed( folder: DKdFolder, userPermissions: NsfFolderAccessRow[], shareAdmins: NsfFolderAccessRow[] -): { userPermissions: NsfFolderAccessRow[]; shareAdmins: NsfFolderAccessRow[] } { +): { + userPermissions: NsfFolderAccessRow[] + shareAdmins: NsfFolderAccessRow[] +} { const ownerUsername = folder.ownerInfo?.username?.trim() if (!ownerUsername) return { userPermissions, shareAdmins } return { @@ -188,10 +191,7 @@ function fieldValueToStrings(values: unknown[], fieldType?: string): string[] { }) } -function resolveRecordFolder( - storage: InMemoryStorage, - recordUid: string -): NsfRecordFolderView | undefined { +function resolveRecordFolder(storage: InMemoryStorage, recordUid: string): NsfRecordFolderView | undefined { const folderUids = findNestedShareFoldersForRecord(storage, recordUid) if (folderUids.length === 0) return undefined @@ -276,7 +276,10 @@ export function toNsfRecordJsonView(view: NsfRecordView): NsfRecordJsonView { version: view.version, revision: view.revision, ...(view.folder ? { folder: view.folder } : {}), - fields: view.fields.map(({ type, value }) => ({ type, value: jsonFieldValues(type, value) })), + fields: view.fields.map(({ type, value }) => ({ + type, + value: jsonFieldValues(type, value), + })), ...(view.notes ? { notes: view.notes } : {}), user_permissions: view.userPermissions.map((entry) => ({ username: entry.username, @@ -327,9 +330,7 @@ async function fetchRecordPermissions( async function fetchRecordShareAdmins(auth: Auth, recordUid: string): Promise { try { - const response = await auth.executeRest( - getSharingAdminsMessage({ recordUid: normal64Bytes(recordUid) }) - ) + const response = await auth.executeRest(getSharingAdminsMessage({ recordUid: normal64Bytes(recordUid) })) return (response.userProfileExts ?? []) .flatMap((ext) => (ext?.email ? [ext.email] : [])) .sort((a, b) => a.localeCompare(b, undefined, { sensitivity: 'base' })) @@ -340,20 +341,14 @@ async function fetchRecordShareAdmins(auth: Auth, recordUid: string): Promise { try { - const response = await auth.executeRest( - recordDetailsMessage(recordUid, Records.RecordDetailsInclude.DATA_ONLY) - ) + const response = await auth.executeRest(recordDetailsMessage(recordUid, Records.RecordDetailsInclude.DATA_ONLY)) return response.recordDataWithAccessInfo?.[0]?.recordData as DRecord['data'] | undefined } catch { return undefined } } -async function buildFolderView( - auth: Auth, - storage: InMemoryStorage, - folderUid: string -): Promise { +async function buildFolderView(auth: Auth, storage: InMemoryStorage, folderUid: string): Promise { const folder = getKeeperDriveFolder(storage, folderUid) if (!folder) { throw new KeeperSdkError(`Nested share folder not found: ${folderUid}`, ResultCodes.NSF_NOT_FOUND) @@ -362,11 +357,7 @@ async function buildFolderView( const entries = getFolderAccessEntries(storage, folderUid) const shareUsers = await loadShareUserMap(auth, storage) const split = splitFolderPermissions(storage, folder, entries, shareUsers) - const { userPermissions, shareAdmins } = ensureFolderOwnerListed( - folder, - split.userPermissions, - split.shareAdmins - ) + const { userPermissions, shareAdmins } = ensureFolderOwnerListed(folder, split.userPermissions, split.shareAdmins) return { objectType: NsfObjectKind.Folder, @@ -455,7 +446,10 @@ export async function getNestedShareFolder( const folderUid = resolveNsfFolder(storage, trimmed) if (folderUid) { - return { kind: NsfObjectKind.Folder, view: await buildFolderView(auth, storage, folderUid) } + return { + kind: NsfObjectKind.Folder, + view: await buildFolderView(auth, storage, folderUid), + } } const recordUid = resolveNsfRecord(storage, trimmed) @@ -527,9 +521,7 @@ export function formatNsfRecordDetail(view: NsfRecordView, verbose = false): str const total = view.shareAdmins.length const preview = view.shareAdmins.slice(0, NSF_SHARE_ADMINS_PREVIEW_LIMIT) const headingSuffix = - total > NSF_SHARE_ADMINS_PREVIEW_LIMIT - ? `, showing first ${NSF_SHARE_ADMINS_PREVIEW_LIMIT}` - : '' + total > NSF_SHARE_ADMINS_PREVIEW_LIMIT ? `, showing first ${NSF_SHARE_ADMINS_PREVIEW_LIMIT}` : '' lines.push('', `Share Admins (${total}${headingSuffix}):`) for (const admin of preview) { lines.push(` ${admin}`) diff --git a/KeeperSdk/src/nestedShareFolders/index.ts b/KeeperSdk/src/nestedShareFolders/index.ts index da1fd6e8..468f92c3 100644 --- a/KeeperSdk/src/nestedShareFolders/index.ts +++ b/KeeperSdk/src/nestedShareFolders/index.ts @@ -154,21 +154,13 @@ export type { NsfResolvedShareRecipient, } from './nsfTypes' -export { - fetchNsfTeamPublicKeys, - encryptNsfFolderKeyForTeam, - resolveNsfShareRecipient, -} from './nsfTeamShare' +export { fetchNsfTeamPublicKeys, encryptNsfFolderKeyForTeam, resolveNsfShareRecipient } from './nsfTeamShare' export type { UserShareKeys } from './nsfShareKeys' export { linkNestedShareRecord } from './linkNsfRecord' -export { - removeNestedShareRecords, - formatRemoveNsfPreview, - collectRemoveNsfWarnings, -} from './removeNsfRecord' +export { removeNestedShareRecords, formatRemoveNsfPreview, collectRemoveNsfWarnings } from './removeNsfRecord' export { mkdirNestedShareFolder } from './mkdirNsf' export { @@ -182,10 +174,7 @@ export { } from './nsfConstants' export type { NsfFolderColor } from './nsfConstants' -export { - removeNestedShareFolders, - formatRemoveNsfFolderPreview, -} from './removeNsfFolder' +export { removeNestedShareFolders, formatRemoveNsfFolderPreview } from './removeNsfFolder' export { getNestedShareRecordDetails, @@ -235,15 +224,9 @@ export { formatKeepNsfShortcutPlan, } from './nsfShortcut' -export { - transferNestedShareRecords, - formatTransferNestedShareRecordResults, -} from './nsfTransferRecord' +export { transferNestedShareRecords, formatTransferNestedShareRecordResults } from './nsfTransferRecord' export { updateNestedShareFolder } from './updateNsfFolder' -export { - NSF_RECORD_PERMISSION_ROLES, - getFolderPermissionsForRole, -} from './nsfConstants' +export { NSF_RECORD_PERMISSION_ROLES, getFolderPermissionsForRole } from './nsfConstants' export type { NsfRecordPermissionRole } from './nsfConstants' diff --git a/KeeperSdk/src/nestedShareFolders/listNsf.ts b/KeeperSdk/src/nestedShareFolders/listNsf.ts index 0e21e178..a822fb86 100644 --- a/KeeperSdk/src/nestedShareFolders/listNsf.ts +++ b/KeeperSdk/src/nestedShareFolders/listNsf.ts @@ -51,10 +51,7 @@ function collectRecordRows(storage: InMemoryStorage): ListNsfRow[] { title: getRecordTitle(record), type: getRecordType(record), description: getRecordDescription(record), - parentOrFolder: resolveListParentOrFolder( - storage, - findRecordFolderLocation(storage, record.uid) || 'root' - ), + parentOrFolder: resolveListParentOrFolder(storage, findRecordFolderLocation(storage, record.uid) || 'root'), })) } @@ -73,10 +70,7 @@ function truncateText(text: string, maxLength: number): string { return `${text.slice(0, maxLength - NSF_LIST_MIN_TRUNCATE_PREFIX)}...` } -export function formatListNsfTable( - rows: ListNsfRow[], - options: { columnWidth?: number } = {} -): FormattedListNsfTable { +export function formatListNsfTable(rows: ListNsfRow[], options: { columnWidth?: number } = {}): FormattedListNsfTable { const columnWidth = options.columnWidth ?? NSF_LIST_DEFAULT_COLUMN_WIDTH const outRows = rows.map((row, index) => [ String(index + 1), @@ -89,10 +83,7 @@ export function formatListNsfTable( return { headers: [...NSF_LIST_TABLE_HEADERS], rows: outRows } } -export function renderListNsfAsciiTable( - table: FormattedListNsfTable, - options: { minColWidth?: number } = {} -): string { +export function renderListNsfAsciiTable(table: FormattedListNsfTable, options: { minColWidth?: number } = {}): string { const { minColWidth = 2 } = options const { headers, rows } = table const columnCount = headers.length @@ -103,8 +94,7 @@ export function renderListNsfAsciiTable( } return width }) - const padCell = (cell: string, columnIndex: number) => - cell + ' '.repeat(columnWidths[columnIndex] - cell.length) + const padCell = (cell: string, columnIndex: number) => cell + ' '.repeat(columnWidths[columnIndex] - cell.length) const formatRow = (cells: string[]) => cells.map((cell, columnIndex) => padCell(cell, columnIndex)).join(' ') const ruleRow = columnWidths.map((width, columnIndex) => padCell('-'.repeat(width), columnIndex)).join(' ') return [formatRow(headers), ruleRow, ...rows.map(formatRow)].join('\n') @@ -119,14 +109,7 @@ export function formatListNsfCsv(rows: ListNsfRow[]): string { const lines = [NSF_LIST_FULL_HEADERS.join(',')] for (const row of rows) { lines.push( - [ - row.itemType, - row.uid, - row.title, - row.type, - row.description, - row.parentOrFolder, - ] + [row.itemType, row.uid, row.title, row.type, row.description, row.parentOrFolder] .map(escapeCsvCell) .join(',') ) diff --git a/KeeperSdk/src/nestedShareFolders/mkdirNsf.ts b/KeeperSdk/src/nestedShareFolders/mkdirNsf.ts index b8350d7b..83bf2297 100644 --- a/KeeperSdk/src/nestedShareFolders/mkdirNsf.ts +++ b/KeeperSdk/src/nestedShareFolders/mkdirNsf.ts @@ -44,10 +44,7 @@ function normalizeColor(color?: NsfFolderColorInput): NsfFolderColor | undefined return color } -function resolveBaseFolderUid( - storage: InMemoryStorage, - baseFolderUid: string | null | undefined -): string | null { +function resolveBaseFolderUid(storage: InMemoryStorage, baseFolderUid: string | null | undefined): string | null { if (!baseFolderUid) return null return isNestedShareFolder(storage, baseFolderUid) ? baseFolderUid : null } @@ -80,10 +77,7 @@ async function buildFolderCreatePayload( if (color && color !== 'none') metadata.color = color const resolvedParentUid = resolveKeeperDriveParentUid(storage, parentUid) - const encryptedData = await platform.aesGcmEncrypt( - platform.stringToBytes(JSON.stringify(metadata)), - folderKey - ) + const encryptedData = await platform.aesGcmEncrypt(platform.stringToBytes(JSON.stringify(metadata)), folderKey) const encryptionKey = await resolveFolderKeyEncryptionKey(storage, auth, resolvedParentUid) const encryptedFolderKey = await platform.aesGcmEncrypt(folderKey, encryptionKey) @@ -128,9 +122,7 @@ async function createFolderSegmentsBatch( currentParentUid = payload.folderUid } - const response = await auth.executeRest( - folderAddMessage({ folderData: payloads.map((entry) => entry.folderData) }) - ) + const response = await auth.executeRest(folderAddMessage({ folderData: payloads.map((entry) => entry.folderData) })) for (let index = 0; index < payloads.length; index++) { const payload = payloads[index] @@ -210,9 +202,7 @@ export async function mkdirNestedShareFolder( folderUid: createdUid, created: true, message: - segments.length > 1 - ? `Created folder path "${folderPath}".` - : `Created folder "${segments[lastIdx]}".`, + segments.length > 1 ? `Created folder path "${folderPath}".` : `Created folder "${segments[lastIdx]}".`, } } catch (err) { if (err instanceof KeeperSdkError) throw err diff --git a/KeeperSdk/src/nestedShareFolders/nsfConstants.ts b/KeeperSdk/src/nestedShareFolders/nsfConstants.ts index 24c6b2d4..e36b15c8 100644 --- a/KeeperSdk/src/nestedShareFolders/nsfConstants.ts +++ b/KeeperSdk/src/nestedShareFolders/nsfConstants.ts @@ -32,14 +32,7 @@ export const NSF_FOLDER_SHARE_ADMINS_HEADING = 'Share Administrators:' export const NSF_SHARE_ADMINS_PREVIEW_LIMIT = 10 export const NSF_LIST_TABLE_HEADERS = ['#', 'Item Type', 'UID', 'Title', 'Type', 'Description'] as const -export const NSF_LIST_FULL_HEADERS = [ - 'Item Type', - 'UID', - 'Title', - 'Type', - 'Description', - 'Parent/Folder', -] as const +export const NSF_LIST_FULL_HEADERS = ['Item Type', 'UID', 'Title', 'Type', 'Description', 'Parent/Folder'] as const export const NSF_LIST_DEFAULT_COLUMN_WIDTH = 40 export const NSF_LIST_MIN_TRUNCATE_PREFIX = 3 @@ -51,7 +44,6 @@ export const NSF_PATH_SENTINEL = '\x00' export const NSF_FOLDER_COLORS = ['none', 'red', 'orange', 'yellow', 'green', 'blue', 'gray'] as const export type NsfFolderColor = (typeof NSF_FOLDER_COLORS)[number] - export const NSF_KNOWN_FIELD_TYPES = new Set([ 'login', 'password', @@ -76,7 +68,6 @@ export const NSF_KNOWN_FIELD_TYPES = new Set([ 'pincode', ]) - export const NSF_STRUCTURED_SUBKEYS: Record> = { name: new Set(['first', 'middle', 'last']), host: new Set(['hostName', 'port', 'host']), @@ -254,10 +245,7 @@ const NSF_FOLDER_ROLE_PERMISSIONS: Record = { export function getFolderPermissionsForRole(roleType: Folder.AccessRoleType): Folder.IFolderPermissions { const flags = NSF_FOLDER_ROLE_PERMISSIONS[roleType] if (!flags) { - throw new KeeperSdkError( - `Unknown folder access role type: ${roleType}`, - ResultCodes.NSF_SHARE_FAILED - ) + throw new KeeperSdkError(`Unknown folder access role type: ${roleType}`, ResultCodes.NSF_SHARE_FAILED) } return Folder.FolderPermissions.create(flags) } diff --git a/KeeperSdk/src/nestedShareFolders/nsfHelpers.ts b/KeeperSdk/src/nestedShareFolders/nsfHelpers.ts index abd3510a..36151cbc 100644 --- a/KeeperSdk/src/nestedShareFolders/nsfHelpers.ts +++ b/KeeperSdk/src/nestedShareFolders/nsfHelpers.ts @@ -95,10 +95,7 @@ export function parseFolderModifyStatus( const status = result.status ?? Folder.FolderModifyStatus.SUCCESS const statusName = Folder.FolderModifyStatus[status] ?? String(status) if (status !== Folder.FolderModifyStatus.SUCCESS) { - throw new KeeperSdkError( - result.message || `Folder operation failed (${statusName}).`, - failureCode - ) + throw new KeeperSdkError(result.message || `Folder operation failed (${statusName}).`, failureCode) } return result.message || 'Folder operation succeeded' } @@ -116,10 +113,7 @@ export function parseRecordModifyStatus( ? 'SUCCESS' : (Records.RecordModifyResult[status] ?? String(status)) if (status !== Records.RecordModifyResult.RS_SUCCESS) { - throw new KeeperSdkError( - result.message || `Record operation failed (${statusName}).`, - failureCode - ) + throw new KeeperSdkError(result.message || `Record operation failed (${statusName}).`, failureCode) } return { statusName, @@ -146,20 +140,14 @@ export function resolveKeeperDriveRootParentUid(storage: InMemoryStorage): strin return undefined } -export function isRootFolderUid( - storage: InMemoryStorage, - folderUid: string | undefined | null -): boolean { +export function isRootFolderUid(storage: InMemoryStorage, folderUid: string | undefined | null): boolean { const value = (folderUid ?? '').trim() if (!value) return true const driveRoot = resolveKeeperDriveRootParentUid(storage) return !!driveRoot && value === driveRoot } -export function normalizeParentUid( - storage: InMemoryStorage, - parentUid: string | undefined | null -): string { +export function normalizeParentUid(storage: InMemoryStorage, parentUid: string | undefined | null): string { return isRootFolderUid(storage, parentUid) ? 'root' : (parentUid ?? '').trim() } @@ -370,9 +358,7 @@ export async function cacheNewNsfFolder( inheritPermissions: boolean ): Promise { const normalizedParent = - parentUid && !isRootFolderUid(storage, parentUid) - ? parentUid.trim() - : resolveKeeperDriveRootParentUid(storage) + parentUid && !isRootFolderUid(storage, parentUid) ? parentUid.trim() : resolveKeeperDriveRootParentUid(storage) await storage.put({ kind: 'keeper_drive_folder', uid: folderUid, @@ -406,15 +392,9 @@ export function checkFolderDeletePermission( for (const entry of entries) { if (!isCurrentUserFolderAccess(storage, entry, username, accountUidStr)) continue if (entry.accessType === Folder.AccessType.AT_OWNER || entry.permission?.canDelete) return - throw new KeeperSdkError( - 'You do not have permission to delete this folder.', - ResultCodes.NSF_PERMISSION_DENIED - ) + throw new KeeperSdkError('You do not have permission to delete this folder.', ResultCodes.NSF_PERMISSION_DENIED) } - throw new KeeperSdkError( - 'You do not have permission to delete this folder.', - ResultCodes.NSF_PERMISSION_DENIED - ) + throw new KeeperSdkError('You do not have permission to delete this folder.', ResultCodes.NSF_PERMISSION_DENIED) } export function findNestedShareFoldersForRecord(storage: InMemoryStorage, recordUid: string): string[] { @@ -437,20 +417,19 @@ function isCurrentUserRecordAccess( username: string, accountUidStr: string ): boolean { - if ( - entry.accessType !== Folder.AccessType.AT_USER && - entry.accessType !== Folder.AccessType.AT_OWNER - ) { + if (entry.accessType !== Folder.AccessType.AT_USER && entry.accessType !== Folder.AccessType.AT_OWNER) { return false } return ( entry.accessTypeUid === accountUidStr || (username.length > 0 && - storage.getAll('user').some( - (user) => - user.username.toLowerCase() === username.toLowerCase() && - webSafe64FromBytes(user.accountUid) === entry.accessTypeUid - )) + storage + .getAll('user') + .some( + (user) => + user.username.toLowerCase() === username.toLowerCase() && + webSafe64FromBytes(user.accountUid) === entry.accessTypeUid + )) ) } @@ -460,20 +439,17 @@ function isCurrentUserFolderAccess( username: string, accountUidStr: string ): boolean { - if ( - entry.accessType !== Folder.AccessType.AT_USER && - entry.accessType !== Folder.AccessType.AT_OWNER - ) { + if (entry.accessType !== Folder.AccessType.AT_USER && entry.accessType !== Folder.AccessType.AT_OWNER) { return false } return ( entry.accessTypeUid === accountUidStr || (username.length > 0 && - storage.getAll('user').some( - (user) => - user.username === username && - webSafe64FromBytes(user.accountUid) === entry.accessTypeUid - )) + storage + .getAll('user') + .some( + (user) => user.username === username && webSafe64FromBytes(user.accountUid) === entry.accessTypeUid + )) ) } @@ -664,10 +640,7 @@ export function checkRecordDeletePermission( folderUid?: string ): void { if (canRecordBeDeleted(storage, recordUid, username, accountUid, folderUid)) return - throw new KeeperSdkError( - 'You do not have permission to delete this record.', - ResultCodes.NSF_PERMISSION_DENIED - ) + throw new KeeperSdkError('You do not have permission to delete this record.', ResultCodes.NSF_PERMISSION_DENIED) } export function checkRecordEditPermission( @@ -683,15 +656,9 @@ export function checkRecordEditPermission( for (const entry of entries) { if (!isCurrentUserRecordAccess(storage, entry, username, accountUidStr)) continue if (entry.owner || entry.canEdit) return - throw new KeeperSdkError( - 'You do not have permission to edit this record.', - ResultCodes.NSF_PERMISSION_DENIED - ) + throw new KeeperSdkError('You do not have permission to edit this record.', ResultCodes.NSF_PERMISSION_DENIED) } - throw new KeeperSdkError( - 'You do not have permission to edit this record.', - ResultCodes.NSF_PERMISSION_DENIED - ) + throw new KeeperSdkError('You do not have permission to edit this record.', ResultCodes.NSF_PERMISSION_DENIED) } export function formatAccessRoleType(role: Folder.AccessRoleType | null | undefined): NsfAccessRoleLabel { @@ -834,17 +801,12 @@ export async function loadShareUserMap(auth: Auth, storage: InMemoryStorage): Pr } } } - } catch { - } + } catch {} return map } -export function isFolderOwnerAccessor( - folder: DKdFolder, - entry: DKdFolderAccess, - username: string -): boolean { +export function isFolderOwnerAccessor(folder: DKdFolder, entry: DKdFolderAccess, username: string): boolean { const ownerUsername = folder.ownerInfo?.username?.trim().toLowerCase() if (ownerUsername && username.toLowerCase() === ownerUsername) return true if (folder.ownerInfo?.accountUid && folder.ownerInfo.accountUid === entry.accessTypeUid) return true @@ -917,10 +879,7 @@ export function isFolderShareAdministrator(entry: DKdFolderAccess): boolean { } export function isFolderUserPermission(entry: DKdFolderAccess): boolean { - return ( - entry.accessType === Folder.AccessType.AT_USER || - entry.accessType === Folder.AccessType.AT_OWNER - ) + return entry.accessType === Folder.AccessType.AT_USER || entry.accessType === Folder.AccessType.AT_OWNER } export async function patchNsfFolderMetadata( @@ -947,10 +906,7 @@ export function checkFolderEditPermission( accountUid: Uint8Array ): void { if (hasFolderPermission(storage, folderUid, username, accountUid, 'canUpdateSetting')) return - throw new KeeperSdkError( - 'You do not have permission to edit this folder.', - ResultCodes.NSF_PERMISSION_DENIED - ) + throw new KeeperSdkError('You do not have permission to edit this folder.', ResultCodes.NSF_PERMISSION_DENIED) } export function checkFolderSharePermission( @@ -960,10 +916,7 @@ export function checkFolderSharePermission( accountUid: Uint8Array ): void { if (hasFolderPermission(storage, folderUid, username, accountUid, 'canUpdateAccess')) return - throw new KeeperSdkError( - 'You do not have permission to share this folder.', - ResultCodes.NSF_PERMISSION_DENIED - ) + throw new KeeperSdkError('You do not have permission to share this folder.', ResultCodes.NSF_PERMISSION_DENIED) } export function checkRecordSharePermission( @@ -973,10 +926,7 @@ export function checkRecordSharePermission( accountUid: Uint8Array ): void { if (canShareRecord(storage, recordUid, username, accountUid)) return - throw new KeeperSdkError( - 'You do not have permission to share this record.', - ResultCodes.NSF_PERMISSION_DENIED - ) + throw new KeeperSdkError('You do not have permission to share this record.', ResultCodes.NSF_PERMISSION_DENIED) } export function checkRecordChangeOwnershipPermission( @@ -1017,23 +967,16 @@ function toFolderAccessEntry(folderUid: string, accessor: Folder.IFolderAccessDa } } -export async function fetchLiveFolderAccessEntries( - auth: Auth, - folderUid: string -): Promise { +export async function fetchLiveFolderAccessEntries(auth: Auth, folderUid: string): Promise { try { - const response = await auth.executeRest( - getFolderAccessMessage({ folderUid: [normal64Bytes(folderUid)] }) - ) + const response = await auth.executeRest(getFolderAccessMessage({ folderUid: [normal64Bytes(folderUid)] })) const result = response.folderAccessResults?.find( (entry) => entry.folderUid?.length && webSafe64FromBytes(entry.folderUid) === folderUid ) return (result?.accessors ?? []) .filter( (accessor) => - accessor.accessTypeUid?.length && - accessor.accessType != null && - accessor.accessRoleType != null + accessor.accessTypeUid?.length && accessor.accessType != null && accessor.accessRoleType != null ) .map((accessor) => toFolderAccessEntry(folderUid, accessor)) } catch (err) { @@ -1056,9 +999,7 @@ export async function findFolderAccessEntryOrLive( try { const liveEntries = await fetchLiveFolderAccessEntries(auth, folderUid) - return liveEntries.find( - (entry) => entry.accessTypeUid === accessTypeUid && entry.accessType === accessType - ) + return liveEntries.find((entry) => entry.accessTypeUid === accessTypeUid && entry.accessType === accessType) } catch { return undefined } @@ -1069,16 +1010,28 @@ export function collectExistingFolderShareTargets( folderUid: string, currentUsername: string ): Array<{ recipient: string; isTeam: boolean; accountUid?: string }> { - const targets: Array<{ recipient: string; isTeam: boolean; accountUid?: string }> = [] + const targets: Array<{ + recipient: string + isTeam: boolean + accountUid?: string + }> = [] for (const entry of getFolderAccessEntries(storage, folderUid)) { if (entry.accessType === Folder.AccessType.AT_TEAM) { - targets.push({ recipient: entry.accessTypeUid, isTeam: true, accountUid: entry.accessTypeUid }) + targets.push({ + recipient: entry.accessTypeUid, + isTeam: true, + accountUid: entry.accessTypeUid, + }) continue } if (entry.accessType !== Folder.AccessType.AT_USER) continue const username = resolveAccessUsername(storage, entry.accessTypeUid) if (!username || username.toLowerCase() === currentUsername.toLowerCase()) continue - targets.push({ recipient: username, isTeam: false, accountUid: entry.accessTypeUid }) + targets.push({ + recipient: username, + isTeam: false, + accountUid: entry.accessTypeUid, + }) } return targets } @@ -1148,11 +1101,7 @@ function mapLiveRecordAccessEntry( if (!data?.recordUid?.length || !data.accessTypeUid?.length || data.accessType == null) return undefined const accessType = data.accessType - if ( - accessType !== Folder.AccessType.AT_USER && - accessType !== Folder.AccessType.AT_OWNER && - !data.owner - ) { + if (accessType !== Folder.AccessType.AT_USER && accessType !== Folder.AccessType.AT_OWNER && !data.owner) { return undefined } @@ -1188,7 +1137,10 @@ export async function fetchLiveRecordAccessesV3( auth: Auth, storage: InMemoryStorage, recordUids: string[] -): Promise<{ recordAccesses: NsfLiveRecordAccessEntry[]; forbiddenRecords: string[] }> { +): Promise<{ + recordAccesses: NsfLiveRecordAccessEntry[] + forbiddenRecords: string[] +}> { if (recordUids.length === 0) { return { recordAccesses: [], forbiddenRecords: [] } } @@ -1202,7 +1154,9 @@ export async function fetchLiveRecordAccessesV3( let response: record.v3.details.IRecordAccessResponse try { response = await auth.executeRest( - getRecordAccessMessage({ recordUids: chunk.map((uid) => normal64Bytes(uid)) }) + getRecordAccessMessage({ + recordUids: chunk.map((uid) => normal64Bytes(uid)), + }) ) } catch (err) { throw new KeeperSdkError( @@ -1248,7 +1202,14 @@ export function findDirectUserRecordShare( storage: InMemoryStorage, recordUid: string, email: string -): { recordUid: string; email: string; accessRoleType: number; expiration?: number } | undefined { +): + | { + recordUid: string + email: string + accessRoleType: number + expiration?: number + } + | undefined { const entry = findUserRecordShareEntry(storage, recordUid, email) if (!entry || entry.inherited) return undefined return { @@ -1259,10 +1220,7 @@ export function findDirectUserRecordShare( } } -export function validateShareExpirationTimestamp( - expirationMs: number | null | undefined, - cmdName: string -): void { +export function validateShareExpirationTimestamp(expirationMs: number | null | undefined, cmdName: string): void { if (expirationMs == null || expirationMs === -1) return const minAllowed = Date.now() + MIN_SHARE_EXPIRATION_MS if (expirationMs < minAllowed) { @@ -1306,10 +1264,7 @@ export function parseShareExpiration(input: ParseShareExpirationInput): number | const normalized = raw.replace('Z', '+00:00') const dt = new Date(normalized) if (Number.isNaN(dt.getTime())) { - throw new KeeperSdkError( - `[${cmdName}] Invalid expire-at datetime '${raw}'.`, - ResultCodes.NSF_SHARE_FAILED - ) + throw new KeeperSdkError(`[${cmdName}] Invalid expire-at datetime '${raw}'.`, ResultCodes.NSF_SHARE_FAILED) } const expirationMs = dt.getTime() validateShareExpirationTimestamp(expirationMs, cmdName) @@ -1327,10 +1282,7 @@ export function parseShareExpiration(input: ParseShareExpirationInput): number | const amount = Number.parseInt(match[1], 10) const unitMs = NSF_SHARE_EXPIRATION_UNIT_MS[match[2].toLowerCase()] if (!unitMs) { - throw new KeeperSdkError( - `[${cmdName}] Invalid expire-in period '${raw}'.`, - ResultCodes.NSF_SHARE_FAILED - ) + throw new KeeperSdkError(`[${cmdName}] Invalid expire-in period '${raw}'.`, ResultCodes.NSF_SHARE_FAILED) } const expirationMs = Date.now() + amount * unitMs diff --git a/KeeperSdk/src/nestedShareFolders/nsfRecordCrypto.ts b/KeeperSdk/src/nestedShareFolders/nsfRecordCrypto.ts index ffb33c22..32bb094e 100644 --- a/KeeperSdk/src/nestedShareFolders/nsfRecordCrypto.ts +++ b/KeeperSdk/src/nestedShareFolders/nsfRecordCrypto.ts @@ -75,13 +75,7 @@ export async function decryptRecordTitleAndType( recordData: Records.IRecordData ): Promise<{ title: string; type: string }> { const uid = recordData.recordUid?.length ? webSafe64FromBytes(recordData.recordUid) : recordUid - const recordKey = await resolveRecordKeyBytes( - storage, - auth, - uid, - recordData.recordKey, - recordData.recordKeyType - ) + const recordKey = await resolveRecordKeyBytes(storage, auth, uid, recordData.recordKey, recordData.recordKeyType) if (!recordKey) { logger.debug(`NSF record key unavailable for ${uid}`) return { title: UNKNOWN_RECORD_LABEL, type: UNKNOWN_RECORD_LABEL } diff --git a/KeeperSdk/src/nestedShareFolders/nsfRecordData.ts b/KeeperSdk/src/nestedShareFolders/nsfRecordData.ts index b664d279..1d4ce413 100644 --- a/KeeperSdk/src/nestedShareFolders/nsfRecordData.ts +++ b/KeeperSdk/src/nestedShareFolders/nsfRecordData.ts @@ -42,10 +42,7 @@ type ParsedFieldKey = { function stripSurroundingQuotes(value: string): string { const trimmed = value.trim() - if ( - (trimmed.startsWith("'") && trimmed.endsWith("'")) || - (trimmed.startsWith('"') && trimmed.endsWith('"')) - ) { + if ((trimmed.startsWith("'") && trimmed.endsWith("'")) || (trimmed.startsWith('"') && trimmed.endsWith('"'))) { return trimmed.slice(1, -1) } return trimmed @@ -59,10 +56,7 @@ export function resolveNsfFieldValue(raw: string): NsfFieldValue { try { return JSON.parse(jsonStr) as Record } catch (err) { - throw new KeeperSdkError( - `Invalid $JSON value: ${extractErrorMessage(err)}`, - ResultCodes.NSF_ADD_FAILED - ) + throw new KeeperSdkError(`Invalid $JSON value: ${extractErrorMessage(err)}`, ResultCodes.NSF_ADD_FAILED) } } return trimmed @@ -275,7 +269,10 @@ function buildRecordFieldEntries(assignments: FieldAssignment[]): { const fields: RecordFieldEntry[] = [] for (const [fieldType, value] of simpleByType) { if (typeof value === 'string' && NSF_STRUCTURED_SUBKEYS[fieldType]) { - fields.push({ type: fieldType, value: [wrapPlainStructuredValue(fieldType, value)] }) + fields.push({ + type: fieldType, + value: [wrapPlainStructuredValue(fieldType, value)], + }) continue } fields.push({ type: fieldType, value: toFieldValueArray(value) }) @@ -288,10 +285,7 @@ function buildRecordFieldEntries(assignments: FieldAssignment[]): { return { fields, custom } } -function mergeFieldEntries( - existing: RecordFieldEntry[], - incoming: RecordFieldEntry[] -): RecordFieldEntry[] { +function mergeFieldEntries(existing: RecordFieldEntry[], incoming: RecordFieldEntry[]): RecordFieldEntry[] { const merged = new Map() for (const field of existing) { merged.set(fieldEntryKey(field), { diff --git a/KeeperSdk/src/nestedShareFolders/nsfRecordPermission.ts b/KeeperSdk/src/nestedShareFolders/nsfRecordPermission.ts index 1f6f3f7f..0029abe7 100644 --- a/KeeperSdk/src/nestedShareFolders/nsfRecordPermission.ts +++ b/KeeperSdk/src/nestedShareFolders/nsfRecordPermission.ts @@ -1,10 +1,5 @@ import type { Auth, DKdFolderRecord } from '@keeper-security/keeperapi' -import { - Folder, - platform, - record, - recordsShareV3Message, -} from '@keeper-security/keeperapi' +import { Folder, platform, record, recordsShareV3Message } from '@keeper-security/keeperapi' import type { InMemoryStorage } from '../storage/InMemoryStorage' import { getRecordTitle } from '../records/RecordUtils' import { @@ -156,23 +151,21 @@ function recordTitle(storage: InMemoryStorage, recordUid: string): string { return getRecordTitle(recordEntry).slice(0, 32) } - async function getRecordAccessesV3( auth: Auth, storage: InMemoryStorage, recordUids: string[] -): Promise<{ recordAccesses: NsfRecordAccessEntry[]; forbiddenRecords: string[] }> { +): Promise<{ + recordAccesses: NsfRecordAccessEntry[] + forbiddenRecords: string[] +}> { if (recordUids.length === 0) { throw new KeeperSdkError('At least one record UID required.', ResultCodes.NSF_RECORD_PERMISSION_FAILED) } return fetchLiveRecordAccessesV3(auth, storage, recordUids) } -async function requireRecordKey( - storage: InMemoryStorage, - auth: Auth, - recordUid: string -): Promise { +async function requireRecordKey(storage: InMemoryStorage, auth: Auth, recordUid: string): Promise { const recordKey = await resolveRecordKeyBytes(storage, auth, recordUid) if (!recordKey) { throw new KeeperSdkError( @@ -211,10 +204,7 @@ async function buildRevokePermission( const emailKey = item.email.trim().toLowerCase() const userKeys = userKeysByEmail.get(emailKey) if (!userKeys) { - throw new KeeperSdkError( - `User ${item.email} not found`, - ResultCodes.NSF_RECORD_PERMISSION_FAILED - ) + throw new KeeperSdkError(`User ${item.email} not found`, ResultCodes.NSF_RECORD_PERMISSION_FAILED) } return buildNsfRevokePermissionFromKeys(item.recordUid, userKeys) } @@ -483,11 +473,7 @@ export function buildNsfRecordPermissionPlan( } } -function formatPermissionPlanTable( - title: string, - headers: string[], - rows: string[][] -): string[] { +function formatPermissionPlanTable(title: string, headers: string[], rows: string[][]): string[] { if (rows.length === 0) return [] const columnCount = headers.length @@ -498,8 +484,7 @@ function formatPermissionPlanTable( } return width }) - const pad = (cell: string, columnIndex: number) => - cell + ' '.repeat(Math.max(0, widths[columnIndex] - cell.length)) + const pad = (cell: string, columnIndex: number) => cell + ' '.repeat(Math.max(0, widths[columnIndex] - cell.length)) const formatRow = (cells: string[]) => cells.map((cell, columnIndex) => pad(cell, columnIndex)).join(' ') const rule = widths.map((width, columnIndex) => pad('-'.repeat(width), columnIndex)).join(' ') @@ -580,10 +565,7 @@ export function formatNsfRecordPermissionPlan(plan: NsfRecordPermissionPlan): st return lines.join('\n').trimEnd() } -function mapFailures( - outcomes: NsfShareOperationOutcome[], - defaultCode: string -): NsfRecordPermissionFailure[] { +function mapFailures(outcomes: NsfShareOperationOutcome[], defaultCode: string): NsfRecordPermissionFailure[] { return outcomes .filter((outcome) => !outcome.success) .map((outcome) => ({ @@ -619,9 +601,7 @@ export async function updateNestedShareRecordPermissions( } const accessRoleType = - action === NsfRecordPermissionAction.Grant && normalizedRole - ? resolveNsfRoleName(normalizedRole) - : undefined + action === NsfRecordPermissionAction.Grant && normalizedRole ? resolveNsfRoleName(normalizedRole) : undefined const { folderUid, displayName } = resolveFolderForPermission(storage, input.folder) const recordUids = collectNsfRecordUidsInFolder(storage, folderUid, recursive) @@ -665,9 +645,7 @@ export async function updateNestedShareRecordPermissions( plan, grantFailures: [], revokeFailures: [], - message: dryRun - ? undefined - : 'Confirmation required. Set force=true to proceed.', + message: dryRun ? undefined : 'Confirmation required. Set force=true to proceed.', } } @@ -679,8 +657,7 @@ export async function updateNestedShareRecordPermissions( grantOutcomes.push(...(await batchCreateRecordSharesV3(storage, auth, buckets.creates))) } - const revokeOutcomes = - buckets.revokes.length > 0 ? await batchUnshareRecordsV3(auth, buckets.revokes) : [] + const revokeOutcomes = buckets.revokes.length > 0 ? await batchUnshareRecordsV3(auth, buckets.revokes) : [] return { confirmed: true, diff --git a/KeeperSdk/src/nestedShareFolders/nsfRecordTypes.ts b/KeeperSdk/src/nestedShareFolders/nsfRecordTypes.ts index 2d95a7cf..7748c2d8 100644 --- a/KeeperSdk/src/nestedShareFolders/nsfRecordTypes.ts +++ b/KeeperSdk/src/nestedShareFolders/nsfRecordTypes.ts @@ -52,17 +52,11 @@ async function loadRecordTypes(auth: Auth): Promise { cachedAt = now return cachedRecordTypes } catch (err) { - throw new KeeperSdkError( - `Failed to load record types: ${extractErrorMessage(err)}`, - ResultCodes.NSF_ADD_FAILED - ) + throw new KeeperSdkError(`Failed to load record types: ${extractErrorMessage(err)}`, ResultCodes.NSF_ADD_FAILED) } } -export async function getNsfRecordTypeFields( - auth: Auth, - recordType: string -): Promise { +export async function getNsfRecordTypeFields(auth: Auth, recordType: string): Promise { const normalized = recordType.trim() if (!normalized || NSF_LEGACY_RECORD_TYPES.has(normalized)) return undefined diff --git a/KeeperSdk/src/nestedShareFolders/nsfShare.ts b/KeeperSdk/src/nestedShareFolders/nsfShare.ts index 8b0f7ec2..1e8ffcfd 100644 --- a/KeeperSdk/src/nestedShareFolders/nsfShare.ts +++ b/KeeperSdk/src/nestedShareFolders/nsfShare.ts @@ -42,11 +42,7 @@ import { resolveNsfRecordIdentifier, resolveNsfRoleName, } from './nsfHelpers' -import { - encryptNsfFolderKeyForTeam, - fetchNsfTeamPublicKeys, - resolveNsfShareRecipient, -} from './nsfTeamShare' +import { encryptNsfFolderKeyForTeam, fetchNsfTeamPublicKeys, resolveNsfShareRecipient } from './nsfTeamShare' import type { NsfDirectUserRecordShare, NsfFolderAccessOperationResult, @@ -95,7 +91,12 @@ function parseFolderAccessResult( recipient: string ): NsfFolderAccessOperationResult { if (!result) { - return { folderUid, recipient, success: false, message: 'No folder access result returned' } + return { + folderUid, + recipient, + success: false, + message: 'No folder access result returned', + } } const status = result.status ?? Folder.FolderModifyStatus.SUCCESS const statusName = Folder.FolderModifyStatus[status] ?? String(status) @@ -198,9 +199,7 @@ function buildFolderAccessUpdateData( ): Folder.IFolderAccessData { if (!target.accountUid?.length) { throw new KeeperSdkError( - target.isTeam - ? `Team ${target.recipient} not found` - : `User ${target.recipient} not found`, + target.isTeam ? `Team ${target.recipient} not found` : `User ${target.recipient} not found`, target.isTeam ? ResultCodes.TEAM_NOT_FOUND : SHARE_ERROR ) } @@ -278,13 +277,7 @@ async function grantFolderAccess( const accessType = target.isTeam ? Folder.AccessType.AT_TEAM : Folder.AccessType.AT_USER const accessTypeUid = target.accountUid ? webSafe64FromBytes(target.accountUid) : target.recipient - const existing = await findFolderAccessEntryOrLive( - storage, - auth, - folderUid, - accessTypeUid, - accessType - ) + const existing = await findFolderAccessEntryOrLive(storage, auth, folderUid, accessTypeUid, accessType) if (existing && existing.accessRoleType === accessRoleType && expirationTimestamp == null) { return { folderUid, @@ -299,14 +292,7 @@ async function grantFolderAccess( const request = existing != null ? buildFolderAccessUpdateData(folderUid, target, accessRoleType, expirationTimestamp) - : await buildFolderAccessGrantData( - auth, - storage, - folderUid, - target, - accessRoleType, - expirationTimestamp - ) + : await buildFolderAccessGrantData(auth, storage, folderUid, target, accessRoleType, expirationTimestamp) const response = await auth.executeRest( folderAccessUpdateMessage({ @@ -314,11 +300,7 @@ async function grantFolderAccess( }) ) - const parsed = parseFolderAccessResult( - response.folderAccessResults?.[0], - folderUid, - target.recipient - ) + const parsed = parseFolderAccessResult(response.folderAccessResults?.[0], folderUid, target.recipient) return { folderUid, recipient: target.recipient, @@ -347,11 +329,7 @@ async function removeFolderAccess( }) ) - const parsed = parseFolderAccessResult( - response.folderAccessResults?.[0], - folderUid, - target.recipient - ) + const parsed = parseFolderAccessResult(response.folderAccessResults?.[0], folderUid, target.recipient) return { folderUid, recipient: target.recipient, @@ -375,15 +353,11 @@ export async function shareNestedShareFolder( throw new KeeperSdkError('Folder path or UID is required.', SHARE_ERROR) } if (recipients.length === 0) { - throw new KeeperSdkError( - 'Recipient is required (email, team name/UID, or @existing).', - SHARE_ERROR - ) + throw new KeeperSdkError('Recipient is required (email, team name/UID, or @existing).', SHARE_ERROR) } const role = input.role?.trim() || NSFShareRoleName.Viewer - const accessRoleType = - action === NsfFolderShareAction.Grant ? resolveNsfRoleName(role) : undefined + const accessRoleType = action === NsfFolderShareAction.Grant ? resolveNsfRoleName(role) : undefined const expirationTimestamp = action === NsfFolderShareAction.Grant @@ -407,18 +381,9 @@ export async function shareNestedShareFolder( ensureNestedShareFolder(storage, folderUid, folderArg) checkFolderSharePermission(storage, folderUid, auth.username, accountUid) - const targets = await resolveFolderShareTargets( - auth, - storage, - folderUid, - recipients, - auth.username - ) + const targets = await resolveFolderShareTargets(auth, storage, folderUid, recipients, auth.username) if (targets.length === 0) { - throw new KeeperSdkError( - `No share targets resolved for folder '${folderArg}'.`, - SHARE_ERROR - ) + throw new KeeperSdkError(`No share targets resolved for folder '${folderArg}'.`, SHARE_ERROR) } for (const target of targets) { @@ -426,14 +391,7 @@ export async function shareNestedShareFolder( results.push(await removeFolderAccess(auth, folderUid, target)) } else { results.push( - await grantFolderAccess( - storage, - auth, - folderUid, - target, - accessRoleType!, - expirationTimestamp - ) + await grantFolderAccess(storage, auth, folderUid, target, accessRoleType!, expirationTimestamp) ) } } @@ -442,18 +400,11 @@ export async function shareNestedShareFolder( return { results } } catch (err) { if (err instanceof KeeperSdkError) throw err - throw new KeeperSdkError( - `Failed to share nested share folder: ${extractErrorMessage(err)}`, - SHARE_ERROR - ) + throw new KeeperSdkError(`Failed to share nested share folder: ${extractErrorMessage(err)}`, SHARE_ERROR) } } -function resolveRecordUids( - storage: InMemoryStorage, - recordArg: string, - recursive: boolean -): string[] { +function resolveRecordUids(storage: InMemoryStorage, recordArg: string, recursive: boolean): string[] { const trimmed = recordArg.trim() if (!trimmed) { throw new KeeperSdkError('Record path or UID is required.', SHARE_ERROR) @@ -492,11 +443,7 @@ function isShareUpdateNoop( return isShareExpirationNoop(existing.expiration, expirationTimestamp) } -async function requireRecordKey( - storage: InMemoryStorage, - auth: Auth, - recordUid: string -): Promise { +async function requireRecordKey(storage: InMemoryStorage, auth: Auth, recordUid: string): Promise { const recordKey = await resolveRecordKeyBytes(storage, auth, recordUid) if (!recordKey) { throw new KeeperSdkError( @@ -528,7 +475,11 @@ async function resolveUserRecordShareForRevoke( storage: InMemoryStorage, recordUid: string, email: string -): Promise<{ hasDirectShare: boolean; inherited: boolean; userKeys: Awaited> }> { +): Promise<{ + hasDirectShare: boolean + inherited: boolean + userKeys: Awaited> +}> { const userKeys = await loadUserShareKeys(auth, email) const accountUidStr = webSafe64FromBytes(userKeys.accountUid) const shareUsers = await loadShareUserMap(auth, storage) @@ -547,8 +498,7 @@ async function resolveUserRecordShareForRevoke( (access) => access.recordUid === recordUid && !access.owner && - (access.accessTypeUid === accountUidStr || - access.accessorName.toLowerCase() === email.toLowerCase()) + (access.accessTypeUid === accountUidStr || access.accessorName.toLowerCase() === email.toLowerCase()) ) if (!liveEntry) { return { hasDirectShare: false, inherited: false, userKeys } @@ -587,9 +537,7 @@ async function revokeRecordShare( } const permission = buildNsfRevokePermissionFromKeys(recordUid, shareState.userKeys) - const response = await auth.executeRest( - recordsShareV3Message({ revokeSharingPermissions: [permission] }) - ) + const response = await auth.executeRest(recordsShareV3Message({ revokeSharingPermissions: [permission] })) const parsed = parseRecordSharingStatus(response.revokedSharingStatus?.[0]) return { recordUid, @@ -634,9 +582,7 @@ async function grantRecordShare( expirationTimestamp, SHARE_ERROR ) - const response = await auth.executeRest( - recordsShareV3Message({ createSharingPermissions: [permission] }) - ) + const response = await auth.executeRest(recordsShareV3Message({ createSharingPermissions: [permission] })) const parsed = parseRecordSharingStatus(response.createdSharingStatus?.[0]) return { recordUid, @@ -729,18 +675,14 @@ export async function shareNestedShareRecord( throw new KeeperSdkError('Recipient email is required.', SHARE_ERROR) } if (action === NsfRecordShareAction.Owner && emails.length > 1) { - throw new KeeperSdkError( - 'Ownership can only be transferred to a single account.', - SHARE_ERROR - ) + throw new KeeperSdkError('Ownership can only be transferred to a single account.', SHARE_ERROR) } if (action === NsfRecordShareAction.Grant && !input.role?.trim()) { throw new KeeperSdkError('Role is required for grant action.', SHARE_ERROR) } const role = input.role?.trim() || NSFShareRoleName.Viewer - const accessRoleType = - action === NsfRecordShareAction.Grant ? resolveNsfRoleName(role) : undefined + const accessRoleType = action === NsfRecordShareAction.Grant ? resolveNsfRoleName(role) : undefined const expirationTimestamp = action === NsfRecordShareAction.Grant @@ -791,14 +733,7 @@ export async function shareNestedShareRecord( results.push(await revokeRecordShare(storage, auth, recordUid, email)) } else { results.push( - await grantRecordShare( - storage, - auth, - recordUid, - email, - accessRoleType!, - expirationTimestamp - ) + await grantRecordShare(storage, auth, recordUid, email, accessRoleType!, expirationTimestamp) ) } } @@ -807,9 +742,6 @@ export async function shareNestedShareRecord( return { dryRun: false, plan, results } } catch (err) { if (err instanceof KeeperSdkError) throw err - throw new KeeperSdkError( - `Failed to share nested share record: ${extractErrorMessage(err)}`, - SHARE_ERROR - ) + throw new KeeperSdkError(`Failed to share nested share record: ${extractErrorMessage(err)}`, SHARE_ERROR) } } diff --git a/KeeperSdk/src/nestedShareFolders/nsfShareKeys.ts b/KeeperSdk/src/nestedShareFolders/nsfShareKeys.ts index 40fa0fa7..f3dca309 100644 --- a/KeeperSdk/src/nestedShareFolders/nsfShareKeys.ts +++ b/KeeperSdk/src/nestedShareFolders/nsfShareKeys.ts @@ -70,10 +70,7 @@ export async function loadUserShareKeysOrInvite( try { await auth.executeRestAction(sendShareInviteMessage({ email })) } catch (err) { - throw new KeeperSdkError( - `Failed to invite ${email}: ${extractErrorMessage(err)}`, - errorCode - ) + throw new KeeperSdkError(`Failed to invite ${email}: ${extractErrorMessage(err)}`, errorCode) } keys = await fetchUserShareKeys(auth, email) } @@ -86,10 +83,7 @@ export async function loadUserShareKeysOrInvite( return keys } -export async function loadNsfUserShareKeysMap( - auth: Auth, - emails: string[] -): Promise> { +export async function loadNsfUserShareKeysMap(auth: Auth, emails: string[]): Promise> { const deduped = dedupeNsfShareEmails(emails) const keysByEmail = new Map() if (deduped.length === 0) return keysByEmail @@ -141,15 +135,14 @@ export async function encryptKeyForRecipient( useEccKey: false, } } - throw new KeeperSdkError( - `No usable public key available for ${userKeys.username}`, - MISSING_PUBLIC_KEY - ) + throw new KeeperSdkError(`No usable public key available for ${userKeys.username}`, MISSING_PUBLIC_KEY) } -export function parseRecordSharingStatus( - status: record.v3.sharing.IStatus | null | undefined -): { recordUid: string; success: boolean; message: string } { +export function parseRecordSharingStatus(status: record.v3.sharing.IStatus | null | undefined): { + recordUid: string + success: boolean + message: string +} { if (!status?.recordUid?.length) { return { recordUid: '', success: false, message: 'No status returned' } } @@ -219,13 +212,7 @@ export async function buildNsfRecordSharePermission( errorCode: string = MISSING_PUBLIC_KEY ): Promise { const userKeys = await loadUserShareKeysOrInvite(auth, email, errorCode) - return buildNsfSharePermissionFromKeys( - recordUid, - recordKey, - accessRoleType, - userKeys, - expirationTimestamp - ) + return buildNsfSharePermissionFromKeys(recordUid, recordKey, accessRoleType, userKeys, expirationTimestamp) } export async function buildNsfRecordRevokePermission( diff --git a/KeeperSdk/src/nestedShareFolders/nsfShortcut.ts b/KeeperSdk/src/nestedShareFolders/nsfShortcut.ts index c285a6d9..62914dce 100644 --- a/KeeperSdk/src/nestedShareFolders/nsfShortcut.ts +++ b/KeeperSdk/src/nestedShareFolders/nsfShortcut.ts @@ -101,10 +101,7 @@ function resolveShortcutRecordUids( } if (recordUid) { - throw new KeeperSdkError( - `Record '${trimmed}' is not linked to multiple folders.`, - SHORTCUT_ERROR - ) + throw new KeeperSdkError(`Record '${trimmed}' is not linked to multiple folders.`, SHORTCUT_ERROR) } throw new KeeperSdkError(`Target '${trimmed}' not found`, ResultCodes.NSF_NOT_FOUND) @@ -125,9 +122,7 @@ function collectShortcutRows( recordUid, title: recordTitle(storage, recordUid), folders: [...(shortcuts.get(recordUid) ?? [])] - .sort((a, b) => - formatFolderLabel(storage, a).localeCompare(formatFolderLabel(storage, b)) - ) + .sort((a, b) => formatFolderLabel(storage, a).localeCompare(formatFolderLabel(storage, b))) .map((folderUid) => formatFolderLabel(storage, folderUid)), })) } @@ -153,11 +148,7 @@ export function formatNsfShortcutTable(rows: NsfShortcutRow[]): string { export function formatNsfShortcutCsv(rows: NsfShortcutRow[]): string { const lines = ['record_uid,title,folders'] for (const row of rows) { - lines.push( - [row.recordUid, row.title, row.folders.join('; ')] - .map(escapeCsvCell) - .join(',') - ) + lines.push([row.recordUid, row.title, row.folders.join('; ')].map(escapeCsvCell).join(',')) } return lines.join('\n') } @@ -184,10 +175,7 @@ export function formatNsfShortcutOutput( return formatNsfShortcutTable(rows) } -export function listNsfShortcuts( - storage: InMemoryStorage, - options: ListNsfShortcutsOptions = {} -): NsfShortcutRow[] { +export function listNsfShortcuts(storage: InMemoryStorage, options: ListNsfShortcutsOptions = {}): NsfShortcutRow[] { const shortcuts = getNsfRecordShortcuts(storage) return collectShortcutRows(storage, shortcuts, options.target) } @@ -227,8 +215,7 @@ function parseFolderRecordUpdateResult( recordUid: string ): KeepNsfShortcutResultItem { const result = response.folderRecordUpdateResult?.find( - (entry) => - !!entry.recordUid?.length && webSafe64FromBytes(entry.recordUid) === recordUid + (entry) => !!entry.recordUid?.length && webSafe64FromBytes(entry.recordUid) === recordUid ) if (!result) { @@ -305,10 +292,7 @@ export async function keepNsfShortcut( const keepFolderUid = resolveKeepFolderUid(storage, input.folder, defaultFolderUid) const folderSet = shortcuts.get(recordUid) if (!folderSet || folderSet.size < 2) { - throw new KeeperSdkError( - `Record '${recordArg}' is not linked to multiple folders.`, - SHORTCUT_ERROR - ) + throw new KeeperSdkError(`Record '${recordArg}' is not linked to multiple folders.`, SHORTCUT_ERROR) } if (!folderSet.has(keepFolderUid)) { throw new KeeperSdkError( @@ -328,7 +312,12 @@ export async function keepNsfShortcut( } if (removeFolderUids.length === 0) { - return { dryRun: input.dryRun ?? false, plan, results: [], nothingToDo: true } + return { + dryRun: input.dryRun ?? false, + plan, + results: [], + nothingToDo: true, + } } if (input.dryRun) { diff --git a/KeeperSdk/src/nestedShareFolders/nsfTeamShare.ts b/KeeperSdk/src/nestedShareFolders/nsfTeamShare.ts index e084c9be..847d0a67 100644 --- a/KeeperSdk/src/nestedShareFolders/nsfTeamShare.ts +++ b/KeeperSdk/src/nestedShareFolders/nsfTeamShare.ts @@ -35,10 +35,7 @@ function hasAsymmetricTeamPublicKeys(keys: NsfTeamPublicKeys): boolean { return Boolean(keys.rsaPublicKey?.length || keys.eccPublicKey?.length) } -async function decryptTeamGetKeysEntry( - auth: Auth, - entry: TeamGetKeyEntry -): Promise> { +async function decryptTeamGetKeysEntry(auth: Auth, entry: TeamGetKeyEntry): Promise> { if (!entry.key) return {} const keyBytes = normal64Bytes(entry.key) @@ -99,7 +96,9 @@ async function fetchNsfTeamPublicKeysFromVaultStorage( if (!teamPrivateKey?.length) return {} try { - return { rsaPublicKey: deriveRsaPublicKeyFromPkcs1PrivateKey(teamPrivateKey) } + return { + rsaPublicKey: deriveRsaPublicKeyFromPkcs1PrivateKey(teamPrivateKey), + } } catch (err) { logger.debug( `Could not derive team RSA public key from vault storage for ${teamUid}: ${extractErrorMessage(err)}` @@ -108,10 +107,7 @@ async function fetchNsfTeamPublicKeysFromVaultStorage( } } -function findMatchingShareTeams( - teams: Records.IShareTeam[], - query: string -): Records.IShareTeam[] { +function findMatchingShareTeams(teams: Records.IShareTeam[], query: string): Records.IShareTeam[] { const lower = query.toLowerCase() return teams.filter((team) => { const uid = team.teamUid?.length ? webSafe64FromBytes(team.teamUid) : '' @@ -144,19 +140,13 @@ export async function fetchNsfTeamPublicKeys( } if (!hasAsymmetricTeamPublicKeys(keys)) { - throw new KeeperSdkError( - `No public key found for team ${trimmed}.`, - ResultCodes.TEAM_NOT_FOUND - ) + throw new KeeperSdkError(`No public key found for team ${trimmed}.`, ResultCodes.TEAM_NOT_FOUND) } return keys } catch (err) { if (err instanceof KeeperSdkError) throw err - throw new KeeperSdkError( - `Failed to load team keys for ${trimmed}: ${extractErrorMessage(err)}`, - SHARE_ERROR - ) + throw new KeeperSdkError(`Failed to load team keys for ${trimmed}: ${extractErrorMessage(err)}`, SHARE_ERROR) } } @@ -166,10 +156,7 @@ export async function encryptNsfFolderKeyForTeam( ): Promise { if (teamPublicKeys.rsaPublicKey?.length) { return Folder.EncryptedDataKey.create({ - encryptedKey: platform.publicEncrypt( - folderKey, - platform.bytesToBase64(teamPublicKeys.rsaPublicKey) - ), + encryptedKey: platform.publicEncrypt(folderKey, platform.bytesToBase64(teamPublicKeys.rsaPublicKey)), encryptedKeyType: Folder.EncryptedKeyType.encrypted_by_public_key, }) } @@ -199,7 +186,11 @@ export async function resolveNsfShareRecipient( if (matches.length === 1) { const teamUid = webSafe64FromBytes(matches[0].teamUid!) - return { recipient: teamUid, isTeam: true, accountUid: matches[0].teamUid as Uint8Array } + return { + recipient: teamUid, + isTeam: true, + accountUid: matches[0].teamUid as Uint8Array, + } } if (matches.length > 1) { throw new KeeperSdkError( @@ -208,8 +199,5 @@ export async function resolveNsfShareRecipient( ) } - throw new KeeperSdkError( - `Recipient '${trimmed}' could not be resolved as an email or team.`, - SHARE_ERROR - ) + throw new KeeperSdkError(`Recipient '${trimmed}' could not be resolved as an email or team.`, SHARE_ERROR) } diff --git a/KeeperSdk/src/nestedShareFolders/nsfTransferRecord.ts b/KeeperSdk/src/nestedShareFolders/nsfTransferRecord.ts index 86377642..cd41f4f2 100644 --- a/KeeperSdk/src/nestedShareFolders/nsfTransferRecord.ts +++ b/KeeperSdk/src/nestedShareFolders/nsfTransferRecord.ts @@ -19,11 +19,7 @@ import { NsfResultStatus, NsfTransferApiStatus } from './nsfTypes' const TRANSFER_ERROR = ResultCodes.NSF_TRANSFER_FAILED -async function requireRecordKey( - storage: InMemoryStorage, - auth: Auth, - recordUid: string -): Promise { +async function requireRecordKey(storage: InMemoryStorage, auth: Auth, recordUid: string): Promise { const recordKey = await resolveRecordKeyBytes(storage, auth, recordUid) if (!recordKey) { throw new KeeperSdkError( @@ -98,9 +94,7 @@ export async function transferNestedShareRecords( } ensureNestedShareRecord(storage, recordUid, identifier) checkRecordChangeOwnershipPermission(storage, recordUid, auth.username, accountUid) - results.push( - await transferNestedShareRecordOwnership(storage, auth, recordUid, newOwnerEmail) - ) + results.push(await transferNestedShareRecordOwnership(storage, auth, recordUid, newOwnerEmail)) } return { @@ -116,9 +110,7 @@ export async function transferNestedShareRecords( } } -export function formatTransferNestedShareRecordResults( - results: TransferNestedShareRecordResultItem[] -): string { +export function formatTransferNestedShareRecordResults(results: TransferNestedShareRecordResultItem[]): string { if (results.length === 0) return '' const lines: string[] = [] for (const item of results) { diff --git a/KeeperSdk/src/nestedShareFolders/removeNsfFolder.ts b/KeeperSdk/src/nestedShareFolders/removeNsfFolder.ts index 6e34567d..6b3d0819 100644 --- a/KeeperSdk/src/nestedShareFolders/removeNsfFolder.ts +++ b/KeeperSdk/src/nestedShareFolders/removeNsfFolder.ts @@ -149,9 +149,7 @@ export function formatRemoveNsfFolderPreview( quiet = false ): string { const action = - operation === NsfRemoveFolderOperation.DeletePermanent - ? PERMANENT_DELETE_ACTION_LABEL - : TRASH_ACTION_LABEL + operation === NsfRemoveFolderOperation.DeletePermanent ? PERMANENT_DELETE_ACTION_LABEL : TRASH_ACTION_LABEL const lines: string[] = [] for (const item of preview) { diff --git a/KeeperSdk/src/nestedShareFolders/removeNsfRecord.ts b/KeeperSdk/src/nestedShareFolders/removeNsfRecord.ts index 2afae04e..74cd0a53 100644 --- a/KeeperSdk/src/nestedShareFolders/removeNsfRecord.ts +++ b/KeeperSdk/src/nestedShareFolders/removeNsfRecord.ts @@ -82,14 +82,14 @@ function buildRemovals( throw new KeeperSdkError('At least one record UID or title is required.', ResultCodes.NSF_NOT_FOUND) } if (recordIdentifiers.length > NSF_MAX_RECORD_BATCH) { - throw new KeeperSdkError(`Maximum ${NSF_MAX_RECORD_BATCH} records per request.`, ResultCodes.NSF_TOO_MANY_RECORDS) - } - if (operation === NsfRemoveOperation.Unlink && !folderIdentifier?.trim()) { throw new KeeperSdkError( - '--folder is required when operation is "unlink".', - ResultCodes.NSF_FOLDER_REQUIRED + `Maximum ${NSF_MAX_RECORD_BATCH} records per request.`, + ResultCodes.NSF_TOO_MANY_RECORDS ) } + if (operation === NsfRemoveOperation.Unlink && !folderIdentifier?.trim()) { + throw new KeeperSdkError('--folder is required when operation is "unlink".', ResultCodes.NSF_FOLDER_REQUIRED) + } const folderUid = folderIdentifier ? resolveNsfFolderIdentifier(storage, folderIdentifier) : undefined if (folderIdentifier && !folderUid) { @@ -206,7 +206,10 @@ export async function removeNestedShareRecords( const preview = (previewResponse.results ?? []).map(mapPreviewItem) if (hasPreviewErrors(preview)) { - throw new KeeperSdkError(formatRemoveNsfPreview(preview) || 'Removal preview failed.', ResultCodes.NSF_REMOVE_FAILED) + throw new KeeperSdkError( + formatRemoveNsfPreview(preview) || 'Removal preview failed.', + ResultCodes.NSF_REMOVE_FAILED + ) } if (dryRun || !previewResponse.confirmationToken?.length) { @@ -214,7 +217,12 @@ export async function removeNestedShareRecords( } if (!input.force) { - return { confirmed: false, dryRun: false, preview, message: 'Confirmation required. Set force=true to proceed.' } + return { + confirmed: false, + dryRun: false, + preview, + message: 'Confirmation required. Set force=true to proceed.', + } } await executeRemove(auth, removals, RemoveAction.REMOVE_ACTION_CONFIRM, previewResponse.confirmationToken) diff --git a/KeeperSdk/src/nestedShareFolders/updateNsfFolder.ts b/KeeperSdk/src/nestedShareFolders/updateNsfFolder.ts index 177620f2..ccbc94a5 100644 --- a/KeeperSdk/src/nestedShareFolders/updateNsfFolder.ts +++ b/KeeperSdk/src/nestedShareFolders/updateNsfFolder.ts @@ -71,10 +71,7 @@ async function buildUpdateFolderData( ) } - const encryptedData = await platform.aesGcmEncrypt( - platform.stringToBytes(JSON.stringify(metadata)), - folderKey - ) + const encryptedData = await platform.aesGcmEncrypt(platform.stringToBytes(JSON.stringify(metadata)), folderKey) return Folder.FolderData.create({ folderUid: normal64Bytes(folderUid), @@ -118,10 +115,7 @@ export async function updateNestedShareFolder( const color = input.color !== undefined ? normalizeColor(input.color) : undefined if (newName === undefined && color === undefined) { - throw new KeeperSdkError( - 'New folder name and/or color parameters are required.', - ResultCodes.NSF_UPDATE_FAILED - ) + throw new KeeperSdkError('New folder name and/or color parameters are required.', ResultCodes.NSF_UPDATE_FAILED) } const folderUid = resolveNsfFolderIdentifier(storage, folderArg) diff --git a/KeeperSdk/src/nestedShareFolders/updateNsfRecord.ts b/KeeperSdk/src/nestedShareFolders/updateNsfRecord.ts index 8829ed38..b4454c63 100644 --- a/KeeperSdk/src/nestedShareFolders/updateNsfRecord.ts +++ b/KeeperSdk/src/nestedShareFolders/updateNsfRecord.ts @@ -34,9 +34,7 @@ function loadStoredRecordData(storage: InMemoryStorage, recordUid: string): Reco return { fields: [] } } -function isPerRecordUpdateInput( - input: UpdateNsfRecordInput | UpdateNsfRecordsInput -): input is UpdateNsfRecordsInput { +function isPerRecordUpdateInput(input: UpdateNsfRecordInput | UpdateNsfRecordsInput): input is UpdateNsfRecordsInput { const first = input.records[0] return first != null && typeof first === 'object' && 'record' in first } @@ -188,7 +186,9 @@ export async function updateNestedShareRecord( auth: Auth, input: UpdateNsfRecordItemInput ): Promise { - const { updated } = await updateNestedShareRecords(storage, auth, { records: [input] }) + const { updated } = await updateNestedShareRecords(storage, auth, { + records: [input], + }) if (!updated[0]) { throw new KeeperSdkError('Failed to update nested share record.', ResultCodes.NSF_UPDATE_FAILED) } diff --git a/KeeperSdk/src/records/RecordOperations.ts b/KeeperSdk/src/records/RecordOperations.ts index acee9afa..9d744712 100644 --- a/KeeperSdk/src/records/RecordOperations.ts +++ b/KeeperSdk/src/records/RecordOperations.ts @@ -111,10 +111,7 @@ export type DeleteRecordResult = { message?: string } -export async function addRecord( - auth: Auth, - input: NewRecordInput -): Promise { +export async function addRecord(auth: Auth, input: NewRecordInput): Promise { if (!input.data.title || !input.data.title.trim()) { throw new KeeperSdkError('Record title is required.', 'missing_record_title') } @@ -127,11 +124,7 @@ export async function addRecord( return addTypedRecord(auth, input.data, input.folderUid) } -async function addPasswordRecord( - auth: Auth, - data: PasswordRecordData, - folderUid?: string -): Promise { +async function addPasswordRecord(auth: Auth, data: PasswordRecordData, folderUid?: string): Promise { const recordUidBytes = generateUidBytes() const recordKey = generateEncryptionKey() const recordUid = webSafe64FromBytes(recordUidBytes) @@ -181,11 +174,7 @@ async function addPasswordRecord( } } -async function addTypedRecord( - auth: Auth, - data: TypedRecordData, - folderUid?: string -): Promise { +async function addTypedRecord(auth: Auth, data: TypedRecordData, folderUid?: string): Promise { const recordUidBytes = generateUidBytes() const recordKey = generateEncryptionKey() const recordUid = webSafe64FromBytes(recordUidBytes) @@ -223,16 +212,12 @@ async function addTypedRecord( const response = await auth.executeRest(msg) const recordStatus = response.records?.[0] - const success = - recordStatus?.status === Records.RecordModifyResult.RS_SUCCESS || - !recordStatus?.status + const success = recordStatus?.status === Records.RecordModifyResult.RS_SUCCESS || !recordStatus?.status return { recordUid, success, - status: recordStatus?.status != null - ? Records.RecordModifyResult[recordStatus.status] - : ResultCode.OK, + status: recordStatus?.status != null ? Records.RecordModifyResult[recordStatus.status] : ResultCode.OK, } } @@ -278,23 +263,16 @@ export async function updateRecord( const response = await auth.executeRest(msg) const recordStatus = response.records?.[0] - const success = - recordStatus?.status === Records.RecordModifyResult.RS_SUCCESS || - !recordStatus?.status + const success = recordStatus?.status === Records.RecordModifyResult.RS_SUCCESS || !recordStatus?.status return { recordUid, success, - status: recordStatus?.status != null - ? Records.RecordModifyResult[recordStatus.status] - : ResultCode.OK, + status: recordStatus?.status != null ? Records.RecordModifyResult[recordStatus.status] : ResultCode.OK, } } -export async function deleteRecord( - auth: Auth, - recordUid: string -): Promise { +export async function deleteRecord(auth: Auth, recordUid: string): Promise { const preDeleteRequest = { objects: [ { @@ -437,18 +415,18 @@ function resolveFolder(uid: string, storage: InMemoryStorage): FolderInfo { const sfFolder = storage.getByUid(FolderKind.SharedFolderFolder, uid) if (sfFolder) { - return { uid, folderType: FolderKind.SharedFolderFolder, scopeUid: sfFolder.sharedFolderUid } + return { + uid, + folderType: FolderKind.SharedFolderFolder, + scopeUid: sfFolder.sharedFolderUid, + } } return { uid, folderType: FolderKind.UserFolder, scopeUid: '' } } async function findRecordSourceFolder(recordUid: string, storage: InMemoryStorage): Promise { - const folderKinds = [ - FolderKind.UserFolder, - FolderKind.SharedFolder, - FolderKind.SharedFolderFolder, - ] as const + const folderKinds = [FolderKind.UserFolder, FolderKind.SharedFolder, FolderKind.SharedFolderFolder] as const for (const kind of folderKinds) { for (const folder of storage.getAll(kind)) { @@ -474,13 +452,7 @@ export async function moveRecord( storage: InMemoryStorage, input: MoveRecordInput ): Promise { - const { - recordUid, - dstFolderUid, - link = false, - canEdit, - canShare, - } = input + const { recordUid, dstFolderUid, link = false, canEdit, canShare } = input const dst = resolveFolder(dstFolderUid, storage) @@ -514,7 +486,11 @@ export async function moveRecord( } if (!dstKey) { - return { recordUid, success: false, message: 'Destination folder key not found' } + return { + recordUid, + success: false, + message: 'Destination folder key not found', + } } const record = storage.getByUid(VaultObjectKind.Record, recordUid) @@ -527,7 +503,10 @@ export async function moveRecord( encryptedKey = await platform.aesCbcEncrypt(recordKey, dstKey, true) } - transitionKeys.push({ uid: recordUid, key: webSafe64FromBytes(encryptedKey) }) + transitionKeys.push({ + uid: recordUid, + key: webSafe64FromBytes(encryptedKey), + }) } const request: MoveRequest = { diff --git a/KeeperSdk/src/roles/RoleManager.ts b/KeeperSdk/src/roles/RoleManager.ts index 673bb2c7..c398af41 100644 --- a/KeeperSdk/src/roles/RoleManager.ts +++ b/KeeperSdk/src/roles/RoleManager.ts @@ -2,12 +2,7 @@ import type { Auth } from '@keeper-security/keeperapi' import { KeeperSdkError, ResultCodes } from '../utils' import { EnterpriseDataManager } from '../teams/enterpriseData' import { formatRolesTable, listRoles, renderRolesAsciiTable } from './listRoles' -import type { - FormatRolesTableOptions, - FormattedRolesTable, - ListRoleRow, - ListRolesOptions, -} from './roleTypes' +import type { FormatRolesTableOptions, FormattedRolesTable, ListRoleRow, ListRolesOptions } from './roleTypes' import { formatRoleView, roleViewTable, @@ -62,10 +57,7 @@ export class RoleManager { return formatRolesTable(rows, options) } - public renderRolesAsciiTable( - table: FormattedRolesTable, - options: { minColWidth?: number } = {} - ): string { + public renderRolesAsciiTable(table: FormattedRolesTable, options: { minColWidth?: number } = {}): string { return renderRolesAsciiTable(table, options) } diff --git a/KeeperSdk/src/roles/addRole.ts b/KeeperSdk/src/roles/addRole.ts index 4804110c..fecd8b50 100644 --- a/KeeperSdk/src/roles/addRole.ts +++ b/KeeperSdk/src/roles/addRole.ts @@ -138,16 +138,34 @@ export async function addRoles(auth: Auth, input: AddRoleInput): Promise role.node_id === parentNodeId) if (sameParent) { - items.push(skippedItem(sameParent.role_id, name, sameParent.node_id, AddRoleSkipReason.AlreadyExistsInParent, - `Role "${name}" already exists in parent node ${parentNodeId}.`)) + items.push( + skippedItem( + sameParent.role_id, + name, + sameParent.node_id, + AddRoleSkipReason.AlreadyExistsInParent, + `Role "${name}" already exists in parent node ${parentNodeId}.` + ) + ) continue } if (conflicts.length > 0 && !force) { - const confirmed = await confirmCrossNode(input.confirm, conflicts[0], { roleName: name, parentNodeId, parentNodeName }) + const confirmed = await confirmCrossNode(input.confirm, conflicts[0], { + roleName: name, + parentNodeId, + parentNodeName, + }) if (!confirmed) { - items.push(skippedItem(conflicts[0].role_id, name, conflicts[0].node_id, AddRoleSkipReason.ExistsElsewhereDeclined, - `Role "${name}" exists in node ${conflicts[0].node_id}; creation declined.`)) + items.push( + skippedItem( + conflicts[0].role_id, + name, + conflicts[0].node_id, + AddRoleSkipReason.ExistsElsewhereDeclined, + `Role "${name}" exists in node ${conflicts[0].node_id}; creation declined.` + ) + ) continue } } @@ -163,9 +181,20 @@ export async function addRoles(auth: Auth, input: AddRoleInput): Promise { const response = await auth.executeRestCommand(enterpriseAllocateIdsCommand({ number_requested: 1 })) if (!response.base_id) { - throw new KeeperSdkError('Failed to allocate enterprise ID for new role.', ResultCodes.ROLE_ID_ALLOCATION_FAILED) + throw new KeeperSdkError( + 'Failed to allocate enterprise ID for new role.', + ResultCodes.ROLE_ID_ALLOCATION_FAILED + ) } return response.base_id } @@ -204,12 +236,14 @@ async function confirmCrossNode( context: { roleName: string; parentNodeId: number; parentNodeName: string } ): Promise { if (!confirm) return false - return (await confirm({ - ...context, - existingRoleId: existing.role_id, - existingRoleName: (existing.displayName || '').trim() || String(existing.role_id), - existingNodeId: existing.node_id ?? 0, - })) === true + return ( + (await confirm({ + ...context, + existingRoleId: existing.role_id, + existingRoleName: (existing.displayName || '').trim() || String(existing.role_id), + existingNodeId: existing.node_id ?? 0, + })) === true + ) } function skippedItem( @@ -219,12 +253,27 @@ function skippedItem( skipReason: AddRoleSkipReason, message: string ): AddRoleItemResult { - return { roleId, roleName, nodeId, status: AddRoleStatus.Skipped, skipReason, message } + return { + roleId, + roleName, + nodeId, + status: AddRoleStatus.Skipped, + skipReason, + message, + } } function finalizeResult(items: AddRoleItemResult[], parentNodeId: number, parentNodeName: string): AddRoleResult { const created = items.filter((item) => item.status === AddRoleStatus.Created).length const skipped = items.filter((item) => item.status === AddRoleStatus.Skipped).length const failed = items.filter((item) => item.status === AddRoleStatus.Failed).length - return { success: failed === 0 && created > 0, parentNodeId, parentNodeName, items, created, skipped, failed } + return { + success: failed === 0 && created > 0, + parentNodeId, + parentNodeName, + items, + created, + skipped, + failed, + } } diff --git a/KeeperSdk/src/roles/deleteRole.ts b/KeeperSdk/src/roles/deleteRole.ts index 9a893a73..bcf1527b 100644 --- a/KeeperSdk/src/roles/deleteRole.ts +++ b/KeeperSdk/src/roles/deleteRole.ts @@ -65,9 +65,20 @@ export async function deleteRoles(auth: Auth, input: DeleteRoleInput): Promise HEADER_BY_COLUMN[col])] @@ -110,10 +109,7 @@ export function formatRolesTable( return { headers, rows: outRows } } -export function renderRolesAsciiTable( - table: FormattedRolesTable, - options: { minColWidth?: number } = {} -): string { +export function renderRolesAsciiTable(table: FormattedRolesTable, options: { minColWidth?: number } = {}): string { const { minColWidth = MIN_ASCII_COL_WIDTH } = options const { headers, rows } = table const columnCount = headers.length @@ -134,10 +130,8 @@ export function renderRolesAsciiTable( } } - const padCell = (cell: string, ci: number): string => - cell + ' '.repeat(columnWidths[ci] - cell.length) - const formatPhysicalRow = (cells: string[]): string => - cells.map((cell, ci) => padCell(cell, ci)).join(' ') + const padCell = (cell: string, ci: number): string => cell + ' '.repeat(columnWidths[ci] - cell.length) + const formatPhysicalRow = (cells: string[]): string => cells.map((cell, ci) => padCell(cell, ci)).join(' ') const ruleRow = formatPhysicalRow(columnWidths.map((w) => '-'.repeat(w))) const lines: string[] = [formatPhysicalRow(headers), ruleRow] @@ -215,7 +209,9 @@ function buildNodePathLookup(nodes: EnterpriseNode[]): Map { return new Map( nodes.map((node) => [ node.node_id, - EnterpriseDataManager.getNodePath(nodes, node.node_id, { separator: NODE_PATH_SEPARATOR }), + EnterpriseDataManager.getNodePath(nodes, node.node_id, { + separator: NODE_PATH_SEPARATOR, + }), ]) ) } @@ -273,12 +269,11 @@ function resolveSortedNames(ids: Set, nameById: Map): string[] return result.sort((a, b) => a.localeCompare(b, undefined, { sensitivity: 'base' })) } -function decorateRow( - role: EnterpriseRole, - columns: readonly RoleColumn[], - context: DecorateContext -): ListRoleRow { - const row: ListRoleRow = { role_id: role.role_id, name: roleDisplayName(role) } +function decorateRow(role: EnterpriseRole, columns: readonly RoleColumn[], context: DecorateContext): ListRoleRow { + const row: ListRoleRow = { + role_id: role.role_id, + name: roleDisplayName(role), + } for (const col of columns) { switch (col) { diff --git a/KeeperSdk/src/roles/roleUtils.ts b/KeeperSdk/src/roles/roleUtils.ts index 5e3c5037..f4a258bf 100644 --- a/KeeperSdk/src/roles/roleUtils.ts +++ b/KeeperSdk/src/roles/roleUtils.ts @@ -20,7 +20,12 @@ export type RoleToggle = 'on' | 'off' export type RoleToggleInput = RoleToggle | `${RoleToggle}` | null | undefined export type EnforcementPair = { key: string; value: string } -type RoleResultRow = { status: string; roleName: string; roleId: number; nodeId: number } +type RoleResultRow = { + status: string + roleName: string + roleId: number + nodeId: number +} export function normalizeIdentifiers(values: ReadonlyArray | null | undefined): string[] { return (values || []) @@ -75,10 +80,7 @@ export function resolveExistingRoles(roles: EnterpriseRole[], identifiers: strin } if (missing.length > 0) { - throw new KeeperSdkError( - `Role(s) "${missing.join(', ')}" could not be resolved.`, - ResultCodes.ROLE_NOT_FOUND - ) + throw new KeeperSdkError(`Role(s) "${missing.join(', ')}" could not be resolved.`, ResultCodes.ROLE_NOT_FOUND) } return Array.from(found.values()) } @@ -139,8 +141,7 @@ function roleHasEnforcement( links: readonly EnterpriseRoleEnforcementLink[] ): boolean { return links.some( - (link) => - link.role_id === roleId && normalizeEnforcementKey(link.enforcement_type) === enforcement + (link) => link.role_id === roleId && normalizeEnforcementKey(link.enforcement_type) === enforcement ) } diff --git a/KeeperSdk/src/roles/updateRole.ts b/KeeperSdk/src/roles/updateRole.ts index d0fc5679..083ab9c5 100644 --- a/KeeperSdk/src/roles/updateRole.ts +++ b/KeeperSdk/src/roles/updateRole.ts @@ -1,9 +1,4 @@ -import { - encryptObjectForStorage, - roleUpdateCommand, - type Auth, - type RoleEditRequest, -} from '@keeper-security/keeperapi' +import { encryptObjectForStorage, roleUpdateCommand, type Auth, type RoleEditRequest } from '@keeper-security/keeperapi' import { extractErrorMessage, KeeperSdkError, ResultCodes } from '../utils' import { EnterpriseDataInclude, EnterpriseDataManager, type EnterpriseRole } from '../teams/enterpriseData' import { @@ -26,10 +21,7 @@ import { type RoleToggleInput, } from './roleUtils' -const UPDATE_ROLE_BASE_INCLUDES: EnterpriseDataInclude[] = [ - EnterpriseDataInclude.Nodes, - EnterpriseDataInclude.Roles, -] +const UPDATE_ROLE_BASE_INCLUDES: EnterpriseDataInclude[] = [EnterpriseDataInclude.Nodes, EnterpriseDataInclude.Roles] export enum UpdateRoleStatus { Updated = 'updated', @@ -124,9 +116,20 @@ export async function updateRoles(auth: Auth, input: UpdateRoleInput): Promise { const response = await auth.executeRestCommand(roleUpdateCommand(payload)) - assertCommandSucceeded(response, `role_update failed for role_id=${payload.role_id}`, ResultCodes.ROLE_UPDATE_FAILED) + assertCommandSucceeded( + response, + `role_update failed for role_id=${payload.role_id}`, + ResultCodes.ROLE_UPDATE_FAILED + ) } function finalizeResult(items: UpdateRoleItemResult[]): UpdateRoleResult { diff --git a/KeeperSdk/src/roles/viewRole.ts b/KeeperSdk/src/roles/viewRole.ts index e0aa336d..6d829257 100644 --- a/KeeperSdk/src/roles/viewRole.ts +++ b/KeeperSdk/src/roles/viewRole.ts @@ -125,10 +125,7 @@ export async function viewRole(auth: Auth, identifier: string): Promise, - identifier: string -): EnterpriseRole { +function resolveRole(roles: EnterpriseRole[], decryptedNames: Map, identifier: string): EnterpriseRole { const trimmed = (identifier ?? '').trim() if (!trimmed) { throw new KeeperSdkError('Role name or ID is required.', ResultCodes.ROLE_REQUIRED) @@ -204,9 +197,7 @@ function resolveRole( } const lowered = trimmed.toLowerCase() - const nameMatches = roles.filter( - (r) => (r.displayName || '').trim().toLowerCase() === lowered - ) + const nameMatches = roles.filter((r) => (r.displayName || '').trim().toLowerCase() === lowered) if (nameMatches.length === 1) return nameMatches[0] if (nameMatches.length > 1) { throw new KeeperSdkError( @@ -217,11 +208,7 @@ function resolveRole( throw new KeeperSdkError(`Role "${trimmed}" does not exist.`, ResultCodes.ROLE_NOT_FOUND) } -function resolveNodePath( - nodes: EnterpriseNode[], - displayNames: EnterpriseDisplayNames, - nodeId: number -): string { +function resolveNodePath(nodes: EnterpriseNode[], displayNames: EnterpriseDisplayNames, nodeId: number): string { for (const node of nodes) { const display = displayNames.nodes.get(node.node_id) if (display) node.displayName = display @@ -244,7 +231,11 @@ function buildRoleTeams( for (const link of roleTeamLinks) { if (link.role_id !== roleId) continue const team = teamByUid.get(link.team_uid) - if (team) result.push({ team_uid: team.team_uid, team_name: (team.name || team.team_uid).trim() }) + if (team) + result.push({ + team_uid: team.team_uid, + team_name: (team.name || team.team_uid).trim(), + }) } result.sort((a, b) => a.team_name.localeCompare(b.team_name, undefined, { sensitivity: 'base' })) return result @@ -263,7 +254,10 @@ function buildRoleUsers( if (link.role_id !== roleId) continue const user = userById.get(link.enterprise_user_id) if (user?.username) { - result.push({ enterprise_user_id: link.enterprise_user_id, username: user.username }) + result.push({ + enterprise_user_id: link.enterprise_user_id, + username: user.username, + }) } } result.sort((a, b) => a.username.localeCompare(b.username, undefined, { sensitivity: 'base' })) @@ -312,10 +306,7 @@ function buildManagedNodes( return result } -function buildEnforcements( - links: EnterpriseRoleEnforcementLink[], - roleId: number -): RoleEnforcementInfo[] { +function buildEnforcements(links: EnterpriseRoleEnforcementLink[], roleId: number): RoleEnforcementInfo[] { const result: RoleEnforcementInfo[] = [] for (const link of links) { if (link.role_id !== roleId || !link.value) continue @@ -358,10 +349,7 @@ function renderMainSection(table: FormattedRoleViewTable): string { idLines: hasIdColumn ? asIdLines(row.id) : [], })) - const valueWidth = expandedRows.reduce( - (max, row) => Math.max(max, ...row.valueLines.map((l) => l.length)), - 0 - ) + const valueWidth = expandedRows.reduce((max, row) => Math.max(max, ...row.valueLines.map((l) => l.length)), 0) const idWidth = hasIdColumn ? expandedRows.reduce((max, row) => Math.max(max, ...row.idLines.map((l) => l.length)), 0) : 0 @@ -419,9 +407,7 @@ function renderManagedNodesSection(table: FormattedManagedNodePrivilegeTable): s title, formatRow(colHeaders), rule, - ...table.privilegeRows.map((row) => - formatRow([row.privilege, ...row.granted.map((g) => (g ? 'X' : ''))]) - ), + ...table.privilegeRows.map((row) => formatRow([row.privilege, ...row.granted.map((g) => (g ? 'X' : ''))])), rule, formatRow(['Cascade Node Permissions', ...table.cascadeRow.map((c) => (c ? 'X' : ''))]), ] @@ -445,4 +431,4 @@ function asIdLines(id: number | number[] | undefined): string[] { function formatAsciiRow(cells: string[], widths: number[]): string { return cells.map((cell, index) => cell + ' '.repeat(Math.max(0, widths[index] - cell.length))).join(' ') -} \ No newline at end of file +} diff --git a/KeeperSdk/src/sharedFolders/SharedFolderManager.ts b/KeeperSdk/src/sharedFolders/SharedFolderManager.ts index bac940f3..a3621a6c 100644 --- a/KeeperSdk/src/sharedFolders/SharedFolderManager.ts +++ b/KeeperSdk/src/sharedFolders/SharedFolderManager.ts @@ -1,16 +1,8 @@ import type { Auth } from '@keeper-security/keeperapi' import { InMemoryStorage } from '../storage/InMemoryStorage' import { KeeperSdkError, ResultCodes } from '../utils' -import { - formatSharedFoldersTable, - listSharedFolders, - renderSharedFoldersAsciiTable, -} from './listSharedFolders' -import type { - FormattedSharedFoldersTable, - ListSharedFolderRow, - ListSharedFoldersOptions, -} from './listSharedFolders' +import { formatSharedFoldersTable, listSharedFolders, renderSharedFoldersAsciiTable } from './listSharedFolders' +import type { FormattedSharedFoldersTable, ListSharedFolderRow, ListSharedFoldersOptions } from './listSharedFolders' import { shareFolder } from './shareFolder' import type { ShareFolderInput, ShareFolderResult } from './shareFolder' diff --git a/KeeperSdk/src/sharedFolders/listSharedFolders.ts b/KeeperSdk/src/sharedFolders/listSharedFolders.ts index ac484bf3..3c0a7765 100644 --- a/KeeperSdk/src/sharedFolders/listSharedFolders.ts +++ b/KeeperSdk/src/sharedFolders/listSharedFolders.ts @@ -157,12 +157,9 @@ export function renderSharedFoldersAsciiTable( columnWidths[columnIndex] = Math.max(columnWidths[columnIndex], cell.length, minColWidth) } } - const padCell = (cell: string, columnIndex: number) => - cell + ' '.repeat(columnWidths[columnIndex] - cell.length) + const padCell = (cell: string, columnIndex: number) => cell + ' '.repeat(columnWidths[columnIndex] - cell.length) const formatRow = (cells: string[]) => cells.map((cell, columnIndex) => padCell(cell, columnIndex)).join(' ') - const ruleRow = Array.from({ length: columnCount }, (_unused, columnIndex) => - '-'.repeat(columnWidths[columnIndex]) - ) + const ruleRow = Array.from({ length: columnCount }, (_unused, columnIndex) => '-'.repeat(columnWidths[columnIndex])) .map((dashes, columnIndex) => padCell(dashes, columnIndex)) .join(' ') const lines: string[] = [formatRow(headers), ruleRow] diff --git a/KeeperSdk/src/sharedFolders/shareFolder.ts b/KeeperSdk/src/sharedFolders/shareFolder.ts index 98d622c9..d365d670 100644 --- a/KeeperSdk/src/sharedFolders/shareFolder.ts +++ b/KeeperSdk/src/sharedFolders/shareFolder.ts @@ -304,9 +304,7 @@ async function shareWithSharedFolder( const newUserManageRecords = isBoolean(input.manageRecords) ? input.manageRecords : sharedFolder.defaultManageRecords - const newUserManageUsers = isBoolean(input.manageUsers) - ? input.manageUsers - : sharedFolder.defaultManageUsers + const newUserManageUsers = isBoolean(input.manageUsers) ? input.manageUsers : sharedFolder.defaultManageUsers for (const email of emails) { if (existingMembers.has(email)) { diff --git a/KeeperSdk/src/sharing/Sharing.ts b/KeeperSdk/src/sharing/Sharing.ts index 9046f369..0b7ba981 100644 --- a/KeeperSdk/src/sharing/Sharing.ts +++ b/KeeperSdk/src/sharing/Sharing.ts @@ -251,9 +251,7 @@ export async function getRecordShareInfo(auth: Auth, recordUid: string): Promise try { response = await auth.executeRest(msg) } catch (err) { - throw new KeeperSdkError( - `Failed to fetch share info for ${recordUid}: ${extractErrorMessage(err)}` - ) + throw new KeeperSdkError(`Failed to fetch share info for ${recordUid}: ${extractErrorMessage(err)}`) } const detail = response.recordDataWithAccessInfo?.[0] diff --git a/KeeperSdk/src/teams/TeamManager.ts b/KeeperSdk/src/teams/TeamManager.ts index 4b8ad230..d846bb05 100644 --- a/KeeperSdk/src/teams/TeamManager.ts +++ b/KeeperSdk/src/teams/TeamManager.ts @@ -80,10 +80,7 @@ export class TeamManager { return addTeams(this.requireAuth(), input) } - public formatAddTeamResult( - result: AddTeamResult, - options: FormatAddTeamResultOptions = {} - ): FormattedAddTeamTable { + public formatAddTeamResult(result: AddTeamResult, options: FormatAddTeamResultOptions = {}): FormattedAddTeamTable { return formatAddTeamResult(result, options) } diff --git a/KeeperSdk/src/teams/addTeam.ts b/KeeperSdk/src/teams/addTeam.ts index 732c7912..af105f95 100644 --- a/KeeperSdk/src/teams/addTeam.ts +++ b/KeeperSdk/src/teams/addTeam.ts @@ -242,10 +242,7 @@ export async function addTeams(auth: Auth, input: AddTeamInput): Promise { +function buildQueuedByLowerName(queued: EnterpriseQueuedTeamRecord[]): Map { const map = new Map() for (const team of queued) { const key = (team.name || '').trim().toLowerCase() @@ -360,13 +355,14 @@ async function sendTeamAdd( parentNodeId: number, dataKey: Uint8Array, treeKey: Uint8Array, - restrictions: { restrictEdit: boolean; restrictShare: boolean; restrictView: boolean } + restrictions: { + restrictEdit: boolean + restrictShare: boolean + restrictView: boolean + } ): Promise { const teamKeyBytes = generateEncryptionKey() - const [rsaKeyPair, eccKeyPair] = await Promise.all([ - platform.generateRSAKeyPair(), - platform.generateECKeyPair(), - ]) + const [rsaKeyPair, eccKeyPair] = await Promise.all([platform.generateRSAKeyPair(), platform.generateECKeyPair()]) const encryptedPrivateKey = await encryptForStorage(rsaKeyPair.privateKey, teamKeyBytes) const encryptedEccPrivateKey = await encryptKey(eccKeyPair.privateKey, teamKeyBytes) const encryptedTeamKeyByDataKey = await encryptForStorage(teamKeyBytes, dataKey) @@ -406,11 +402,7 @@ async function sendTeamAdd( } } -function finalizeResult( - items: AddTeamItemResult[], - parentNodeId: number, - parentNodeName: string -): AddTeamResult { +function finalizeResult(items: AddTeamItemResult[], parentNodeId: number, parentNodeName: string): AddTeamResult { const created = items.filter((item) => item.status === AddTeamStatus.Created).length const skipped = items.filter((item) => item.status === AddTeamStatus.Skipped).length const failed = items.filter((item) => item.status === AddTeamStatus.Failed).length @@ -449,9 +441,7 @@ export function formatAddTeamResult( options: FormatAddTeamResultOptions = {} ): FormattedAddTeamTable { const showSkipped = options.showSkipped !== false - const visible = result.items.filter( - (item) => showSkipped || item.status !== AddTeamStatus.Skipped - ) + const visible = result.items.filter((item) => showSkipped || item.status !== AddTeamStatus.Skipped) const rows = visible.map((item, index) => [ String(index + 1), diff --git a/KeeperSdk/src/teams/deleteTeam.ts b/KeeperSdk/src/teams/deleteTeam.ts index 704969e3..06b509fc 100644 --- a/KeeperSdk/src/teams/deleteTeam.ts +++ b/KeeperSdk/src/teams/deleteTeam.ts @@ -1,9 +1,6 @@ import type { Auth, KeeperResponse, RestCommand } from '@keeper-security/keeperapi' import { extractErrorMessage, KeeperSdkError, ResultCodes } from '../utils' -import { - EnterpriseDataInclude, - EnterpriseDataManager, -} from './enterpriseData' +import { EnterpriseDataInclude, EnterpriseDataManager } from './enterpriseData' import { resolveExistingTeams, TEAM_TABLE_HEADERS } from './teamUtils' const TEAM_DELETE_COMMAND = 'team_delete' @@ -85,9 +82,7 @@ async function sendTeamDelete(auth: Auth, teamUid: string): Promise { const result = (response.result || '').toLowerCase() if (result && result !== 'success') { throw new KeeperSdkError( - response.message || - response.result_code || - `team_delete failed for team_uid=${teamUid}`, + response.message || response.result_code || `team_delete failed for team_uid=${teamUid}`, response.result_code || ResultCodes.TEAM_DELETE_FAILED ) } diff --git a/KeeperSdk/src/teams/enterpriseData.ts b/KeeperSdk/src/teams/enterpriseData.ts index d9336218..f9402361 100644 --- a/KeeperSdk/src/teams/enterpriseData.ts +++ b/KeeperSdk/src/teams/enterpriseData.ts @@ -13,7 +13,6 @@ import { extractErrorMessage, isNumber, logger } from '../utils' const DEFAULT_NODE_PATH_SEPARATOR = '\\' const MAX_CONTINUATIONS = 50 - export enum EnterpriseDataInclude { Nodes = 'nodes', Users = 'users', @@ -207,9 +206,7 @@ export class EnterpriseDataManager implements EnterpriseDataManagerApi { public async decryptNodeNames(nodes: EnterpriseNode[]): Promise { if (!nodes || nodes.length === 0) return 0 - const needsDecrypt = nodes.some( - (node) => !!node.encrypted_data && !(node.displayName || '').trim() - ) + const needsDecrypt = nodes.some((node) => !!node.encrypted_data && !(node.displayName || '').trim()) if (!needsDecrypt) return 0 const displayNames = await this.getDisplayNames() @@ -252,11 +249,7 @@ export class EnterpriseDataManager implements EnterpriseDataManagerApi { this.treeKeyPromise = null } - public static getNodePath( - nodes: EnterpriseNode[], - nodeId: number, - options: NodePathOptions = {} - ): string { + public static getNodePath(nodes: EnterpriseNode[], nodeId: number, options: NodePathOptions = {}): string { const { omitRoot = true, separator = DEFAULT_NODE_PATH_SEPARATOR } = options const byId = new Map() for (const node of nodes) byId.set(node.node_id, node) @@ -284,12 +277,8 @@ export class EnterpriseDataManager implements EnterpriseDataManagerApi { return [...includes].sort().join(',') } - private async fetchEnterpriseData( - includes: EnterpriseDataInclude[] - ): Promise { - const interesting = new Set( - includes.map((key) => INCLUDE_TO_ENTITY[key]) - ) + private async fetchEnterpriseData(includes: EnterpriseDataInclude[]): Promise { + const interesting = new Set(includes.map((key) => INCLUDE_TO_ENTITY[key])) const aggregate: GetEnterpriseDataResponse = {} let continuationToken: Uint8Array | undefined @@ -318,7 +307,10 @@ export class EnterpriseDataManager implements EnterpriseDataManagerApi { } private async fetchDisplayNames(): Promise { - const empty: EnterpriseDisplayNames = { nodes: new Map(), roles: new Map() } + const empty: EnterpriseDisplayNames = { + nodes: new Map(), + roles: new Map(), + } const treeKey = await this.getTreeKey() if (!treeKey) return empty @@ -399,16 +391,16 @@ export class EnterpriseDataManager implements EnterpriseDataManagerApi { return null } } catch (err) { - logger.debug( - `Tree-key decryption failed (keyTypeId=${keyType}): ${extractErrorMessage(err)}` - ) + logger.debug(`Tree-key decryption failed (keyTypeId=${keyType}): ${extractErrorMessage(err)}`) return null } } private static async decryptDisplayName(encrypted: string, treeKey: Uint8Array): Promise { try { - const decrypted = await decryptObjectFromStorage<{ displayname?: string }>(encrypted, treeKey) + const decrypted = await decryptObjectFromStorage<{ + displayname?: string + }>(encrypted, treeKey) return (decrypted?.displayname || '').trim() } catch { return '' @@ -427,24 +419,22 @@ export class EnterpriseDataManager implements EnterpriseDataManagerApi { return bytes && bytes.length > 0 ? webSafe64FromBytes(bytes) : '' } - private static decodeChunk( - chunkData: Uint8Array[] | null | undefined, - decoder: (bytes: Uint8Array) => T - ): T[] { + private static decodeChunk(chunkData: Uint8Array[] | null | undefined, decoder: (bytes: Uint8Array) => T): T[] { if (!chunkData || chunkData.length === 0) return [] const results: T[] = [] for (const bytes of chunkData) { try { results.push(decoder(bytes)) - } catch { - } + } catch {} } return results } private static decodeNodeChunk(bytes: Uint8Array): EnterpriseNode { const message = Enterprise.Node.decode(bytes) - const node: EnterpriseNode = { node_id: EnterpriseDataManager.toNumber(message.nodeId) } + const node: EnterpriseNode = { + node_id: EnterpriseDataManager.toNumber(message.nodeId), + } if (message.parentId != null) node.parent_id = EnterpriseDataManager.toNumber(message.parentId) if (message.encryptedData) node.encrypted_data = message.encryptedData return node @@ -471,7 +461,9 @@ export class EnterpriseDataManager implements EnterpriseDataManagerApi { private static decodeRoleChunk(bytes: Uint8Array): EnterpriseRole { const message = Enterprise.Role.decode(bytes) - const out: EnterpriseRole = { role_id: EnterpriseDataManager.toNumber(message.roleId) } + const out: EnterpriseRole = { + role_id: EnterpriseDataManager.toNumber(message.roleId), + } if (message.nodeId != null) out.node_id = EnterpriseDataManager.toNumber(message.nodeId) if (message.encryptedData) out.encrypted_data = message.encryptedData if (message.visibleBelow != null) out.visible_below = message.visibleBelow @@ -568,10 +560,7 @@ export class EnterpriseDataManager implements EnterpriseDataManagerApi { } } - private static applyChunk( - chunk: Enterprise.IEnterpriseData, - target: GetEnterpriseDataResponse - ): void { + private static applyChunk(chunk: Enterprise.IEnterpriseData, target: GetEnterpriseDataResponse): void { const entity = chunk.entity ?? Enterprise.EnterpriseDataEntity.UNKNOWN const data = chunk.data || [] @@ -658,4 +647,4 @@ export class EnterpriseDataManager implements EnterpriseDataManagerApi { break } } -} \ No newline at end of file +} diff --git a/KeeperSdk/src/teams/listTeams.ts b/KeeperSdk/src/teams/listTeams.ts index 391238aa..57688938 100644 --- a/KeeperSdk/src/teams/listTeams.ts +++ b/KeeperSdk/src/teams/listTeams.ts @@ -93,7 +93,10 @@ export async function listTeams(auth: Auth, options: ListTeamsOptions = {}): Pro const wantsDisplayNames = columns.includes(TeamColumn.Node) || columns.includes(TeamColumn.Roles) const enterpriseData = new EnterpriseDataManager(auth) - const emptyDisplayNames: EnterpriseDisplayNames = { nodes: new Map(), roles: new Map() } + const emptyDisplayNames: EnterpriseDisplayNames = { + nodes: new Map(), + roles: new Map(), + } const [response, displayNames] = await Promise.all([ enterpriseData.getData(includes), wantsDisplayNames ? enterpriseData.getDisplayNames() : Promise.resolve(emptyDisplayNames), @@ -127,10 +130,7 @@ export async function listTeams(auth: Auth, options: ListTeamsOptions = {}): Pro return rows } -export function formatTeamsTable( - rows: ListTeamRow[], - options: FormatTeamsTableOptions = {} -): FormattedTeamsTable { +export function formatTeamsTable(rows: ListTeamRow[], options: FormatTeamsTableOptions = {}): FormattedTeamsTable { const columns = resolveColumns(options.columns) const headers: string[] = ['#', 'Team UID', 'Name', ...columns.map((column) => HEADER_BY_COLUMN[column])] @@ -143,10 +143,7 @@ export function formatTeamsTable( return { headers, rows: outRows } } -export function renderTeamsAsciiTable( - table: FormattedTeamsTable, - options: { minColWidth?: number } = {} -): string { +export function renderTeamsAsciiTable(table: FormattedTeamsTable, options: { minColWidth?: number } = {}): string { const { minColWidth = MIN_ASCII_COL_WIDTH } = options const { headers, rows } = table const columnCount = headers.length @@ -257,7 +254,9 @@ function buildNodePathLookup(nodes: EnterpriseNode[]): Map { return new Map( nodes.map((node) => [ node.node_id, - EnterpriseDataManager.getNodePath(nodes, node.node_id, { separator: NODE_PATH_SEPARATOR }), + EnterpriseDataManager.getNodePath(nodes, node.node_id, { + separator: NODE_PATH_SEPARATOR, + }), ]) ) } @@ -287,7 +286,7 @@ function buildRoleTeamMap(response: GetEnterpriseDataResponse): Map { const map = new Map() for (const user of users) { - if (isNumber(user.enterprise_user_id ) && user.username) { + if (isNumber(user.enterprise_user_id) && user.username) { map.set(user.enterprise_user_id, user.username) } } diff --git a/KeeperSdk/src/teams/teamUtils.ts b/KeeperSdk/src/teams/teamUtils.ts index 35cb89d9..208d64aa 100644 --- a/KeeperSdk/src/teams/teamUtils.ts +++ b/KeeperSdk/src/teams/teamUtils.ts @@ -95,10 +95,7 @@ function buildNodeNotFoundMessage(nodes: EnterpriseNode[], requested: string): s return lines.join('\n') } -export function resolveParentNode( - nodes: EnterpriseNode[], - identifier: string | number | null -): EnterpriseNode { +export function resolveParentNode(nodes: EnterpriseNode[], identifier: string | number | null): EnterpriseNode { if (identifier === null || identifier === undefined || identifier === '') { const root = nodes.find((node) => !node.parent_id || node.parent_id === 0) if (!root) { @@ -163,10 +160,7 @@ export function resolveParentNode( ) } - throw new KeeperSdkError( - buildNodeNotFoundMessage(nodes, trimmed), - ResultCodes.PARENT_NODE_NOT_FOUND - ) + throw new KeeperSdkError(buildNodeNotFoundMessage(nodes, trimmed), ResultCodes.PARENT_NODE_NOT_FOUND) } export function applyDecryptedNodeNames(nodes: EnterpriseNode[], decrypted: Map): void { @@ -177,10 +171,7 @@ export function applyDecryptedNodeNames(nodes: EnterpriseNode[], decrypted: Map< } } -export function applyEnterpriseNameToRoot( - nodes: EnterpriseNode[], - enterpriseName: string | undefined -): void { +export function applyEnterpriseNameToRoot(nodes: EnterpriseNode[], enterpriseName: string | undefined): void { const fallback = (enterpriseName || '').trim() if (!fallback) return for (const node of nodes) { diff --git a/KeeperSdk/src/teams/updateTeam.ts b/KeeperSdk/src/teams/updateTeam.ts index 50056b28..d4621162 100644 --- a/KeeperSdk/src/teams/updateTeam.ts +++ b/KeeperSdk/src/teams/updateTeam.ts @@ -1,9 +1,6 @@ import type { Auth, KeeperResponse, RestCommand } from '@keeper-security/keeperapi' import { extractErrorMessage, KeeperSdkError, ResultCodes } from '../utils' -import { - EnterpriseDataInclude, - EnterpriseDataManager, -} from './enterpriseData' +import { EnterpriseDataInclude, EnterpriseDataManager } from './enterpriseData' import { TeamRestriction, type TeamRestrictionInput } from './addTeam' import { applyDecryptedNodeNames, @@ -16,10 +13,7 @@ import { } from './teamUtils' const TEAM_UPDATE_COMMAND = 'team_update' -const UPDATE_TEAM_INCLUDES: EnterpriseDataInclude[] = [ - EnterpriseDataInclude.Nodes, - EnterpriseDataInclude.Teams, -] +const UPDATE_TEAM_INCLUDES: EnterpriseDataInclude[] = [EnterpriseDataInclude.Nodes, EnterpriseDataInclude.Teams] export enum UpdateTeamStatus { Updated = 'updated', @@ -103,10 +97,7 @@ export async function updateTeams(auth: Auth, input: UpdateTeamInput): Promise Math.max(max, ...row.valueLines.map((line) => line.length)), - 0 - ) + const valueWidth = expandedRows.reduce((max, row) => Math.max(max, ...row.valueLines.map((line) => line.length)), 0) const idWidth = table.hasIdColumn ? expandedRows.reduce((max, row) => Math.max(max, ...row.idLines.map((line) => line.length)), 0) : 0 - const padRight = (text: string, width: number): string => - text + ' '.repeat(Math.max(0, width - text.length)) - const padLeft = (text: string, width: number): string => - ' '.repeat(Math.max(0, width - text.length)) + text + const padRight = (text: string, width: number): string => text + ' '.repeat(Math.max(0, width - text.length)) + const padLeft = (text: string, width: number): string => ' '.repeat(Math.max(0, width - text.length)) + text const lines: string[] = [] for (const row of expandedRows) { @@ -178,18 +173,17 @@ function resolveTeam(teams: EnterpriseTeamRecord[], identifier: string): Enterpr throw new KeeperSdkError(`Team "${trimmed}" does not exist.`, ResultCodes.TEAM_NOT_FOUND) } -function resolveNodePath( - nodes: EnterpriseNode[], - displayNames: EnterpriseDisplayNames, - nodeId: number -): string { +function resolveNodePath(nodes: EnterpriseNode[], displayNames: EnterpriseDisplayNames, nodeId: number): string { if (displayNames.nodes.size > 0) { for (const node of nodes) { const display = displayNames.nodes.get(node.node_id) if (display) node.displayName = display } } - return EnterpriseDataManager.getNodePath(nodes, nodeId, { omitRoot: false, separator: NODE_PATH_SEPARATOR }) + return EnterpriseDataManager.getNodePath(nodes, nodeId, { + omitRoot: false, + separator: NODE_PATH_SEPARATOR, + }) } function buildTeamUsers( @@ -226,7 +220,10 @@ function buildTeamRoles( const result: TeamRoleInfo[] = [] for (const id of roleIds) { - result.push({ role_id: id, role_name: decryptedRoleNames.get(id) || String(id) }) + result.push({ + role_id: id, + role_name: decryptedRoleNames.get(id) || String(id), + }) } result.sort((a, b) => a.role_name.localeCompare(b.role_name, undefined, { sensitivity: 'base' })) return result diff --git a/KeeperSdk/src/users/UserManager.ts b/KeeperSdk/src/users/UserManager.ts index 6db91cc2..042e088f 100644 --- a/KeeperSdk/src/users/UserManager.ts +++ b/KeeperSdk/src/users/UserManager.ts @@ -146,4 +146,4 @@ export class UserManager { } return auth } -} \ No newline at end of file +} diff --git a/KeeperSdk/src/users/actionUser.ts b/KeeperSdk/src/users/actionUser.ts index bacc22ae..00de3f8f 100644 --- a/KeeperSdk/src/users/actionUser.ts +++ b/KeeperSdk/src/users/actionUser.ts @@ -6,11 +6,7 @@ import { type RestCommand, } from '@keeper-security/keeperapi' import { extractErrorMessage, isNumber, KeeperSdkError, logger, ResultCodes } from '../utils' -import { - EnterpriseDataInclude, - EnterpriseDataManager, - type EnterpriseUser, -} from '../teams/enterpriseData' +import { EnterpriseDataInclude, EnterpriseDataManager, type EnterpriseUser } from '../teams/enterpriseData' import { EnterpriseUserStatus, normalizeEmailInputs, @@ -40,9 +36,7 @@ type ExpirePasswordPayload = { email: string } -type ActionUserTarget = - | { kind: 'user'; user: EnterpriseUser } - | { kind: 'not_found'; identifier: string } +type ActionUserTarget = { kind: 'user'; user: EnterpriseUser } | { kind: 'not_found'; identifier: string } export async function actionUsers(auth: Auth, input: UserActionInput): Promise { const identifiers = normalizeEmailInputs(input.emails) @@ -102,7 +96,9 @@ export async function actionUsers(auth: Auth, input: UserActionInput): Promise { const result = (response.result || '').toLowerCase() if (result && result !== 'success') { throw new KeeperSdkError( - response.message || - response.result_code || - `${EXPIRE_PASSWORD_COMMAND} failed for "${maskEmail(email)}"`, + response.message || response.result_code || `${EXPIRE_PASSWORD_COMMAND} failed for "${maskEmail(email)}"`, response.result_code || ResultCodes.USER_ACTION_FAILED ) } @@ -252,9 +246,7 @@ function toEnterpriseUserId(value: unknown): number | null { return null } const numericId = - typeof value === 'object' && 'toNumber' in value - ? (value as { toNumber(): number }).toNumber() - : Number(value) + typeof value === 'object' && 'toNumber' in value ? (value as { toNumber(): number }).toNumber() : Number(value) return isNumber(numericId) && numericId > 0 ? numericId : null } @@ -307,13 +299,21 @@ function resolveCallerEnterpriseUserId(auth: Auth, allUsers: EnterpriseUser[]): } function finalizeResult(items: UserActionItemResult[]): UserActionResult { - let succeeded = 0, skipped = 0, failed = 0 + let succeeded = 0, + skipped = 0, + failed = 0 for (const item of items) { if (item.status === UserActionStatus.Success) succeeded++ else if (item.status === UserActionStatus.Skipped) skipped++ else failed++ } - return { success: failed === 0 && succeeded > 0, items, succeeded, skipped, failed } + return { + success: failed === 0 && succeeded > 0, + items, + succeeded, + skipped, + failed, + } } export function formatUserActionResult(result: UserActionResult): FormattedUserActionTable { @@ -336,8 +336,7 @@ export function renderUserActionAsciiTable(table: FormattedUserActionTable): str const widths = headers.map((header, index) => Math.max(header.length, ...rows.map((row) => (row[index] || '').length)) ) - const padCell = (cell: string, columnIndex: number): string => - cell.padEnd(widths[columnIndex]) + const padCell = (cell: string, columnIndex: number): string => cell.padEnd(widths[columnIndex]) const formatRow = (cells: string[]): string => cells.map((cell, columnIndex) => padCell(cell, columnIndex)).join(' ') diff --git a/KeeperSdk/src/users/addUser.ts b/KeeperSdk/src/users/addUser.ts index f0816063..967dfe8d 100644 --- a/KeeperSdk/src/users/addUser.ts +++ b/KeeperSdk/src/users/addUser.ts @@ -1,15 +1,6 @@ -import { - encryptObjectForStorage, - type Auth, - type KeeperResponse, - type RestCommand, -} from '@keeper-security/keeperapi' +import { encryptObjectForStorage, type Auth, type KeeperResponse, type RestCommand } from '@keeper-security/keeperapi' import { extractErrorMessage, isNumber, isValidEmail, KeeperSdkError, ResultCodes } from '../utils' -import { - EnterpriseDataInclude, - EnterpriseDataManager, - type EnterpriseUser, -} from '../teams/enterpriseData' +import { EnterpriseDataInclude, EnterpriseDataManager, type EnterpriseUser } from '../teams/enterpriseData' import { applyDecryptedNodeNames, applyEnterpriseNameToRoot, @@ -36,10 +27,7 @@ const USER_ADD_COMMAND = 'enterprise_user_add' const ALLOCATE_IDS_COMMAND = 'enterprise_allocate_ids' const REINVITE_COMMAND = 'resend_enterprise_invite' -const ADD_USER_INCLUDES: EnterpriseDataInclude[] = [ - EnterpriseDataInclude.Nodes, - EnterpriseDataInclude.Users, -] +const ADD_USER_INCLUDES: EnterpriseDataInclude[] = [EnterpriseDataInclude.Nodes, EnterpriseDataInclude.Users] const USER_TABLE_HEADERS = ['#', 'Status', 'Email', 'User ID', 'Node ID', 'Detail'] @@ -66,10 +54,7 @@ type AllocateIdsResponse = KeeperResponse & { export async function addUsers(auth: Auth, input: AddUserInput): Promise { const rawEmails = [ - ...new Map( - normalizeEmailInputs(input.emails) - .map((e) => [e.toLowerCase(), e] as const) - ).values(), + ...new Map(normalizeEmailInputs(input.emails).map((e) => [e.toLowerCase(), e] as const)).values(), ] if (rawEmails.length === 0) { @@ -95,16 +80,15 @@ export async function addUsers(auth: Auth, input: AddUserInput): Promise 0 || reinvited > 0), parentNodeId, parentNodeName, items, added, reinvited, skipped, failed } + return { + success: failed === 0 && (added > 0 || reinvited > 0), + parentNodeId, + parentNodeName, + items, + added, + reinvited, + skipped, + failed, + } } export function formatAddUserResult( @@ -271,8 +263,7 @@ export function renderAddUserAsciiTable(table: FormattedAddUserTable): string { const widths = headers.map((header, index) => Math.max(header.length, ...rows.map((row) => (row[index] || '').length)) ) - const padCell = (cell: string, columnIndex: number): string => - cell.padEnd(widths[columnIndex]) + const padCell = (cell: string, columnIndex: number): string => cell.padEnd(widths[columnIndex]) const formatRow = (cells: string[]): string => cells.map((cell, columnIndex) => padCell(cell, columnIndex)).join(' ') diff --git a/KeeperSdk/src/users/aliasUser.ts b/KeeperSdk/src/users/aliasUser.ts index 90af0aa0..4e2bfc6f 100644 --- a/KeeperSdk/src/users/aliasUser.ts +++ b/KeeperSdk/src/users/aliasUser.ts @@ -11,20 +11,12 @@ import { type EnterpriseUser, type EnterpriseUserAliasLink, } from '../teams/enterpriseData' -import { - resolveExistingUsers, - AliasOperation, - type AliasUserInput, - type AliasUserResult, -} from './userTypes' +import { resolveExistingUsers, AliasOperation, type AliasUserInput, type AliasUserResult } from './userTypes' export { AliasOperation } export type { AliasUserInput, AliasUserResult } -const ALIAS_USER_INCLUDES: EnterpriseDataInclude[] = [ - EnterpriseDataInclude.Users, - EnterpriseDataInclude.UserAliases, -] +const ALIAS_USER_INCLUDES: EnterpriseDataInclude[] = [EnterpriseDataInclude.Users, EnterpriseDataInclude.UserAliases] export async function aliasUser(auth: Auth, input: AliasUserInput): Promise { const alias = input.alias.trim().toLowerCase() @@ -58,11 +50,20 @@ async function addAlias( existingAliases: EnterpriseUserAliasLink[], alias: string ): Promise { - const base = { username: user.username, enterpriseUserId: user.enterprise_user_id, alias, operation: AliasOperation.Add } + const base = { + username: user.username, + enterpriseUserId: user.enterprise_user_id, + alias, + operation: AliasOperation.Add, + } if (user.username === alias) { logger.info(`Alias "${alias}" is already the primary email for this user.`) - return { ...base, success: true, detail: 'Alias is already the primary email.' } + return { + ...base, + success: true, + detail: 'Alias is already the primary email.', + } } const alreadyExists = existingAliases.some((a) => a.username === alias) @@ -86,7 +87,12 @@ async function removeAlias( existingAliases: EnterpriseUserAliasLink[], alias: string ): Promise { - const base = { username: user.username, enterpriseUserId: user.enterprise_user_id, alias, operation: AliasOperation.Remove } + const base = { + username: user.username, + enterpriseUserId: user.enterprise_user_id, + alias, + operation: AliasOperation.Remove, + } const exists = alias === user.username || existingAliases.some((a) => a.username === alias) @@ -103,9 +109,7 @@ async function removeAlias( } async function sendAddAlias(auth: Auth, enterpriseUserId: number, alias: string): Promise { - const response = await auth.executeRest( - enterpriseUserAddAliasMessage({ enterpriseUserId, alias, primary: true }) - ) + const response = await auth.executeRest(enterpriseUserAddAliasMessage({ enterpriseUserId, alias, primary: true })) for (const status of response.status || []) { if (status.status && status.status !== 'success') { throw new KeeperSdkError(`Add alias failed: ${status.status}`, ResultCodes.USER_ALIAS_FAILED) diff --git a/KeeperSdk/src/users/deleteUser.ts b/KeeperSdk/src/users/deleteUser.ts index 327dd94e..89e3cd0b 100644 --- a/KeeperSdk/src/users/deleteUser.ts +++ b/KeeperSdk/src/users/deleteUser.ts @@ -1,13 +1,6 @@ -import { - type Auth, - type KeeperResponse, - type RestCommand, -} from '@keeper-security/keeperapi' +import { type Auth, type KeeperResponse, type RestCommand } from '@keeper-security/keeperapi' import { extractErrorMessage, KeeperSdkError, ResultCodes } from '../utils' -import { - EnterpriseDataInclude, - EnterpriseDataManager, -} from '../teams/enterpriseData' +import { EnterpriseDataInclude, EnterpriseDataManager } from '../teams/enterpriseData' import { normalizeEmailInputs, resolveExistingUsers, @@ -72,16 +65,15 @@ async function sendUserDelete(auth: Auth, enterpriseUserId: number): Promise Math.max(header.length, ...rows.map((row) => (row[index] || '').length)) ) - const padCell = (cell: string, columnIndex: number): string => - cell.padEnd(widths[columnIndex]) + const padCell = (cell: string, columnIndex: number): string => cell.padEnd(widths[columnIndex]) const formatRow = (cells: string[]): string => cells.map((cell, columnIndex) => padCell(cell, columnIndex)).join(' ') diff --git a/KeeperSdk/src/users/listUsers.ts b/KeeperSdk/src/users/listUsers.ts index 6ec295cf..f4117172 100644 --- a/KeeperSdk/src/users/listUsers.ts +++ b/KeeperSdk/src/users/listUsers.ts @@ -75,7 +75,10 @@ export async function listUsers(auth: Auth, options: ListUsersOptions = {}): Pro const wantsDisplayNames = columns.includes(UserColumn.Node) const enterpriseData = new EnterpriseDataManager(auth) - const emptyDisplayNames: EnterpriseDisplayNames = { nodes: new Map(), roles: new Map() } + const emptyDisplayNames: EnterpriseDisplayNames = { + nodes: new Map(), + roles: new Map(), + } const [response, displayNames] = await Promise.all([ enterpriseData.getData(includes), wantsDisplayNames ? enterpriseData.getDisplayNames() : Promise.resolve(emptyDisplayNames), @@ -88,11 +91,7 @@ export async function listUsers(auth: Auth, options: ListUsersOptions = {}): Pro nodePaths: buildNodePathLookup(nodes), userTeams: buildUserTeamMap(response.team_users || []), userQueuedTeams: buildUserQueuedTeamMap(response.queued_team_users || []), - userRoles: buildUserRolesMap( - response.role_users || [], - response.role_teams || [], - response.team_users || [] - ), + userRoles: buildUserRolesMap(response.role_users || [], response.role_teams || [], response.team_users || []), teamNameByUid: buildTeamNameMap(response.teams || []), queuedTeamNameByUid: buildTeamNameMap(response.queued_teams || []), roleNameById: buildRoleNameMap(response.roles || [], displayNames.roles), @@ -115,10 +114,7 @@ export async function listUsers(auth: Auth, options: ListUsersOptions = {}): Pro return rows } -export function formatUsersTable( - rows: ListUserRow[], - options: FormatUsersTableOptions = {} -): FormattedUsersTable { +export function formatUsersTable(rows: ListUserRow[], options: FormatUsersTableOptions = {}): FormattedUsersTable { const columns = resolveColumns(options.columns) const headers: string[] = ['#', 'User ID', 'Email', ...columns.map((col) => HEADER_BY_COLUMN[col])] @@ -131,10 +127,7 @@ export function formatUsersTable( return { headers, rows: outRows } } -export function renderUsersAsciiTable( - table: FormattedUsersTable, - options: { minColWidth?: number } = {} -): string { +export function renderUsersAsciiTable(table: FormattedUsersTable, options: { minColWidth?: number } = {}): string { const { minColWidth = MIN_ASCII_COL_WIDTH } = options const { headers, rows } = table const columnCount = headers.length @@ -156,8 +149,7 @@ export function renderUsersAsciiTable( } const padCell = (cell: string, ci: number): string => cell.padEnd(columnWidths[ci]) - const formatPhysicalRow = (cells: string[]): string => - cells.map((cell, ci) => padCell(cell, ci)).join(' ') + const formatPhysicalRow = (cells: string[]): string => cells.map((cell, ci) => padCell(cell, ci)).join(' ') const ruleRow = formatPhysicalRow(columnWidths.map((w) => '-'.repeat(w))) const lines: string[] = [formatPhysicalRow(headers), ruleRow] @@ -348,7 +340,10 @@ function buildUserAliasMap(links: EnterpriseUserAliasLink[]): Map() for (const [userId, aliases] of map) { - result.set(userId, [...aliases].sort((a, b) => a.localeCompare(b, undefined, { sensitivity: 'base' }))) + result.set( + userId, + [...aliases].sort((a, b) => a.localeCompare(b, undefined, { sensitivity: 'base' })) + ) } return result } @@ -425,9 +420,7 @@ function decorateRow( } case UserColumn.Alias: { const aliases = ctx.userAliases.get(user.enterprise_user_id) - row.alias = aliases - ? aliases.filter((a) => a.toLowerCase() !== user.username.toLowerCase()) - : [] + row.alias = aliases ? aliases.filter((a) => a.toLowerCase() !== user.username.toLowerCase()) : [] break } case UserColumn.TwoFaEnabled: @@ -443,17 +436,29 @@ function formatListCell(values: string[] | undefined): string { function formatCell(row: ListUserRow, col: UserColumn): string { switch (col) { - case UserColumn.Name: return row.name ?? '' - case UserColumn.Status: return row.status ?? '' - case UserColumn.TransferStatus: return row.transfer_status ?? '' - case UserColumn.Node: return row.node ?? '' - case UserColumn.TeamCount: return row.team_count == null ? '' : String(row.team_count) - case UserColumn.Teams: return formatListCell(row.teams) - case UserColumn.QueuedTeamCount: return row.queued_team_count == null ? '' : String(row.queued_team_count) - case UserColumn.QueuedTeams: return formatListCell(row.queued_teams) - case UserColumn.RoleCount: return row.role_count == null ? '' : String(row.role_count) - case UserColumn.Roles: return formatListCell(row.roles) - case UserColumn.Alias: return formatListCell(row.alias) - case UserColumn.TwoFaEnabled: return row.tfa_enabled == null ? '' : String(row.tfa_enabled) + case UserColumn.Name: + return row.name ?? '' + case UserColumn.Status: + return row.status ?? '' + case UserColumn.TransferStatus: + return row.transfer_status ?? '' + case UserColumn.Node: + return row.node ?? '' + case UserColumn.TeamCount: + return row.team_count == null ? '' : String(row.team_count) + case UserColumn.Teams: + return formatListCell(row.teams) + case UserColumn.QueuedTeamCount: + return row.queued_team_count == null ? '' : String(row.queued_team_count) + case UserColumn.QueuedTeams: + return formatListCell(row.queued_teams) + case UserColumn.RoleCount: + return row.role_count == null ? '' : String(row.role_count) + case UserColumn.Roles: + return formatListCell(row.roles) + case UserColumn.Alias: + return formatListCell(row.alias) + case UserColumn.TwoFaEnabled: + return row.tfa_enabled == null ? '' : String(row.tfa_enabled) } } diff --git a/KeeperSdk/src/users/teamUser.ts b/KeeperSdk/src/users/teamUser.ts index 93d7838f..4c179f7b 100644 --- a/KeeperSdk/src/users/teamUser.ts +++ b/KeeperSdk/src/users/teamUser.ts @@ -178,10 +178,7 @@ async function fetchUserPublicKeys(auth: Auth, emails: string[]): Promise { +async function encryptTeamKeyForUser(teamKey: Uint8Array, publicKeys: UserPublicKeys): Promise { if (publicKeys.rsaPublicKey) { return { key: platform.publicEncrypt(teamKey, platform.bytesToBase64(publicKeys.rsaPublicKey)), @@ -215,11 +212,7 @@ async function getDecryptedTeamKey( } } -async function loadTeamUserContext( - auth: Auth, - rawUsers: string[], - rawTeams: string[] -): Promise { +async function loadTeamUserContext(auth: Auth, rawUsers: string[], rawTeams: string[]): Promise { const emails = normalizeEmailInputs(rawUsers) if (emails.length === 0) { throw new KeeperSdkError('No users provided.', ResultCodes.NO_USERS_TO_UPDATE) @@ -323,7 +316,11 @@ async function prepareAddBatches( const base = buildItemBase(user, team) if (membership.has(membershipKey(user.enterprise_user_id, team.team_uid))) { - items.push({ ...base, status: TeamUserStatus.Skipped, skipReason: TeamUserSkipReason.AlreadyMember }) + items.push({ + ...base, + status: TeamUserStatus.Skipped, + skipReason: TeamUserSkipReason.AlreadyMember, + }) continue } @@ -353,9 +350,16 @@ async function prepareAddBatches( } try { - prepared.push({ user, encryptedKey: await encryptTeamKeyForUser(teamKey, publicKeys) }) + prepared.push({ + user, + encryptedKey: await encryptTeamKeyForUser(teamKey, publicKeys), + }) } catch (err) { - items.push({ ...base, status: TeamUserStatus.Failed, message: extractErrorMessage(err) }) + items.push({ + ...base, + status: TeamUserStatus.Failed, + message: extractErrorMessage(err), + }) } } @@ -384,7 +388,11 @@ function buildAddTeamRequests( function markAllBatchUsersFailed(batchTeams: PreparedBatchTeam[], message: string): TeamUserItemResult[] { return batchTeams.flatMap(({ team, prepared }) => - prepared.map(({ user }) => ({ ...buildItemBase(user, team), status: TeamUserStatus.Failed, message })) + prepared.map(({ user }) => ({ + ...buildItemBase(user, team), + status: TeamUserStatus.Failed, + message, + })) ) } @@ -410,12 +418,7 @@ function mergeTeamResponse( status: success ? TeamUserStatus.Added : TeamUserStatus.Failed, message: success ? undefined - : pickResponseError( - userResp.message, - userResp.resultCode, - userResp.additionalInfo, - teamFailureMessage - ), + : pickResponseError(userResp.message, userResp.resultCode, userResp.additionalInfo, teamFailureMessage), }) userMap.delete(enterpriseUserId) } @@ -445,7 +448,9 @@ async function sendTeamsEnterpriseUsersAdd( let response: Enterprise.ITeamsEnterpriseUsersAddResponse try { response = await auth.executeRest( - teamsEnterpriseUsersAdd({ teams: buildAddTeamRequests(batchTeams, userType) }) + teamsEnterpriseUsersAdd({ + teams: buildAddTeamRequests(batchTeams, userType), + }) ) } catch (err) { return markAllBatchUsersFailed(batchTeams, extractErrorMessage(err)) @@ -509,7 +514,11 @@ function prepareRemoveEntries( for (const user of users) { const base = buildItemBase(user, team) if (!membership.has(membershipKey(user.enterprise_user_id, team.team_uid))) { - items.push({ ...base, status: TeamUserStatus.Skipped, skipReason: TeamUserSkipReason.NotMember }) + items.push({ + ...base, + status: TeamUserStatus.Skipped, + skipReason: TeamUserSkipReason.NotMember, + }) continue } toRemove.push({ user, team }) @@ -574,7 +583,12 @@ async function sendTeamsEnterpriseUsersRemove( status: success ? TeamUserStatus.Removed : TeamUserStatus.Failed, message: success ? undefined - : pickResponseError(userResp.message, userResp.resultCode, userResp.additionalInfo, 'Team remove failed'), + : pickResponseError( + userResp.message, + userResp.resultCode, + userResp.additionalInfo, + 'Team remove failed' + ), }) entryMap.delete(membershipKey(enterpriseUserId, teamUid)) } @@ -597,12 +611,19 @@ async function processInvitedQueue(auth: Auth, invitedQueue: InvitedQueueEntry[] try { await executeTeamUserCommand( auth, - teamQueueUserCommand({ enterprise_user_id: user.enterprise_user_id, team_uid: team.team_uid }), + teamQueueUserCommand({ + enterprise_user_id: user.enterprise_user_id, + team_uid: team.team_uid, + }), ResultCodes.TEAM_USER_ADD_FAILED ) items.push({ ...base, status: TeamUserStatus.Added }) } catch (err) { - items.push({ ...base, status: TeamUserStatus.Failed, message: extractErrorMessage(err) }) + items.push({ + ...base, + status: TeamUserStatus.Failed, + message: extractErrorMessage(err), + }) } } return items @@ -637,10 +658,7 @@ export async function addUsersToTeams(auth: Auth, input: AddUsersToTeamsInput): return finalizeResult(items) } -export async function removeUsersFromTeams( - auth: Auth, - input: RemoveUsersFromTeamsInput -): Promise { +export async function removeUsersFromTeams(auth: Auth, input: RemoveUsersFromTeamsInput): Promise { const ctx = await loadTeamUserContext(auth, input.users, input.teams || []) const { items, toRemove } = prepareRemoveEntries(ctx.teams, ctx.users, ctx.membership) @@ -660,7 +678,13 @@ function finalizeResult(items: TeamUserItemResult[]): TeamUserResult { else if (item.status === TeamUserStatus.Skipped) skipped++ else failed++ } - return { success: failed === 0 && succeeded > 0, items, succeeded, skipped, failed } + return { + success: failed === 0 && succeeded > 0, + items, + succeeded, + skipped, + failed, + } } export function formatTeamUserResult(result: TeamUserResult): FormattedTeamUserTable { diff --git a/KeeperSdk/src/users/updateUser.ts b/KeeperSdk/src/users/updateUser.ts index feb1932a..fe25f499 100644 --- a/KeeperSdk/src/users/updateUser.ts +++ b/KeeperSdk/src/users/updateUser.ts @@ -90,16 +90,11 @@ export async function updateUsers(auth: Auth, input: UpdateUserInput): Promise Math.max(header.length, ...rows.map((row) => (row[index] || '').length)) ) - const padCell = (cell: string, columnIndex: number): string => - cell.padEnd(widths[columnIndex]) + const padCell = (cell: string, columnIndex: number): string => cell.padEnd(widths[columnIndex]) const formatRow = (cells: string[]): string => cells.map((cell, columnIndex) => padCell(cell, columnIndex)).join(' ') diff --git a/KeeperSdk/src/users/userTypes.ts b/KeeperSdk/src/users/userTypes.ts index 760486f9..4ebd1a4e 100644 --- a/KeeperSdk/src/users/userTypes.ts +++ b/KeeperSdk/src/users/userTypes.ts @@ -392,4 +392,4 @@ export function formatTransferStatus(user: EnterpriseUser): string { return new Date(exp) < new Date() ? 'Blocked' : 'Pending Transfer' } return '' -} \ No newline at end of file +} diff --git a/KeeperSdk/src/users/viewUser.ts b/KeeperSdk/src/users/viewUser.ts index d8d4c910..7630cab0 100644 --- a/KeeperSdk/src/users/viewUser.ts +++ b/KeeperSdk/src/users/viewUser.ts @@ -96,7 +96,11 @@ export function formatUserView(view: UserView, options: FormatUserViewOptions = { label: 'User ID', value: String(view.enterprise_user_id) }, { label: 'Email', value: view.username }, { label: 'Full Name', value: view.full_name }, - { label: 'Node Name', value: view.node_name, id: verbose ? String(view.node_id) : undefined }, + { + label: 'Node Name', + value: view.node_name, + id: verbose ? String(view.node_id) : undefined, + }, { label: 'Status', value: view.status }, { label: 'Transfer Status', value: view.transfer_status }, { label: '2FA Enabled', value: String(view.tfa_enabled) }, @@ -142,18 +146,13 @@ export function userViewTable(table: FormattedUserViewTable): string { idLines: table.hasIdColumn ? asLines(row.id ?? []) : [], })) - const valueWidth = expandedRows.reduce( - (max, row) => Math.max(max, ...row.valueLines.map((l) => l.length)), - 0 - ) + const valueWidth = expandedRows.reduce((max, row) => Math.max(max, ...row.valueLines.map((l) => l.length)), 0) const idWidth = table.hasIdColumn ? expandedRows.reduce((max, row) => Math.max(max, ...row.idLines.map((l) => l.length)), 0) : 0 - const padLeft = (text: string, width: number): string => - ' '.repeat(Math.max(0, width - text.length)) + text - const padRight = (text: string, width: number): string => - text + ' '.repeat(Math.max(0, width - text.length)) + const padLeft = (text: string, width: number): string => ' '.repeat(Math.max(0, width - text.length)) + text + const padRight = (text: string, width: number): string => text + ' '.repeat(Math.max(0, width - text.length)) const lines: string[] = [] for (const row of expandedRows) { @@ -252,7 +251,11 @@ function buildUserRoles( role_id: link.role_id, role_name: decryptedRoleNames.get(link.role_id) || String(link.role_id), })) - .sort((a, b) => a.role_name.localeCompare(b.role_name, undefined, { sensitivity: 'base' })) + .sort((a, b) => + a.role_name.localeCompare(b.role_name, undefined, { + sensitivity: 'base', + }) + ) } async function fetchShareAdmins(auth: Auth, username: string): Promise { diff --git a/KeeperSdk/src/utils/constants.ts b/KeeperSdk/src/utils/constants.ts index f9062376..524b6f00 100644 --- a/KeeperSdk/src/utils/constants.ts +++ b/KeeperSdk/src/utils/constants.ts @@ -247,4 +247,4 @@ export const KEEPER_PUBLIC_HOSTS: Record = { CA: 'keepersecurity.ca', JP: 'keepersecurity.jp', GOV: 'govcloud.keepersecurity.us', -} \ No newline at end of file +} diff --git a/KeeperSdk/src/vault/KeeperVault.ts b/KeeperSdk/src/vault/KeeperVault.ts index 23bfa386..7f8f81a4 100644 --- a/KeeperSdk/src/vault/KeeperVault.ts +++ b/KeeperSdk/src/vault/KeeperVault.ts @@ -87,11 +87,7 @@ import { import { UserManager } from '../users/UserManager' import { NestedShareFolderManager } from '../nestedShareFolders/NestedShareFolderManager' import { isNestedShareFolder } from '../nestedShareFolders/nsfHelpers' -import { - formatListNsfTable, - renderListNsfAsciiTable, - formatListNsfOutput, -} from '../nestedShareFolders/listNsf' +import { formatListNsfTable, renderListNsfAsciiTable, formatListNsfOutput } from '../nestedShareFolders/listNsf' import { formatNsfDetail } from '../nestedShareFolders/getNsf' import { formatRemoveNsfPreview } from '../nestedShareFolders/removeNsfRecord' import { @@ -847,8 +843,7 @@ export class KeeperVault { public async mkdirNestedShareFolder(input: Omit): Promise { const current = this.folderSession.currentFolderUid - const baseFolderUid = - current && isNestedShareFolder(this.storage, current) ? current : null + const baseFolderUid = current && isNestedShareFolder(this.storage, current) ? current : null const result = await this.nestedShareFolderManager.mkdirNestedShareFolder({ ...input, baseFolderUid, @@ -863,9 +858,7 @@ export class KeeperVault { return result } - public async getNestedShareRecordDetails( - input: GetNsfRecordDetailsInput - ): Promise { + public async getNestedShareRecordDetails(input: GetNsfRecordDetailsInput): Promise { return this.nestedShareFolderManager.getNestedShareRecordDetails(input) } @@ -901,17 +894,13 @@ export class KeeperVault { return result } - public async shareNestedShareFolder( - input: ShareNestedShareFolderInput - ): Promise { + public async shareNestedShareFolder(input: ShareNestedShareFolderInput): Promise { const result = await this.nestedShareFolderManager.shareNestedShareFolder(input) if (result.results.some((item) => item.success)) await this.syncIfNeeded() return result } - public async shareNestedShareRecord( - input: ShareNestedShareRecordInput - ): Promise { + public async shareNestedShareRecord(input: ShareNestedShareRecordInput): Promise { const result = await this.nestedShareFolderManager.shareNestedShareRecord(input) if (!result.dryRun && result.results.some((item) => item.success)) await this.syncIfNeeded() return result @@ -940,8 +929,7 @@ export class KeeperVault { public async keepNsfShortcut(input: KeepNsfShortcutInput): Promise { const current = this.folderSession.currentFolderUid - const defaultFolderUid = - current && isNestedShareFolder(this.storage, current) ? current : undefined + const defaultFolderUid = current && isNestedShareFolder(this.storage, current) ? current : undefined const result = await this.nestedShareFolderManager.keepNsfShortcut(input, defaultFolderUid) if (!result.dryRun && result.results.some((item) => item.success)) await this.syncIfNeeded() return result @@ -959,9 +947,7 @@ export class KeeperVault { return result } - public formatTransferNestedShareRecordResults( - results: TransferNestedShareRecordResult['results'] - ): string { + public formatTransferNestedShareRecordResults(results: TransferNestedShareRecordResult['results']): string { return formatTransferNestedShareRecordResults(results) }