From ffd4da46ca1dfda261d8aa3e6464632c459ba8b4 Mon Sep 17 00:00:00 2001 From: Jay Date: Fri, 25 Aug 2023 12:31:46 +0200 Subject: [PATCH] Codecov, compression, start of usb implementation --- README.md | 7 + jest.config.js | 2 +- package-lock.json | 496 +++++++++++++++++++- package.json | 5 +- src/index.js | 20 +- src/index.test.js | 61 ++- "src/\360\237\220\237/cryptography.js" | 146 ++++-- "src/\360\237\220\237/disklist.js" | 230 +++++++++ "src/\360\237\220\237/synchronousOsInfo.js" | 2 - "src/\360\237\246\210.js" | 3 + 10 files changed, 910 insertions(+), 62 deletions(-) create mode 100644 "src/\360\237\220\237/disklist.js" diff --git a/README.md b/README.md index a28eb5a..a541b78 100644 --- a/README.md +++ b/README.md @@ -26,6 +26,13 @@ So files encrypted with one version might not be decryptable with new versions. ### Resonably secure encryption +Changelog 8/25/23 12; : +- General code coverage improvements + +- Starting to implement encryption using a removable USB drive as an identifier. + +- Added support for compression + Changelog 7/19/23 03~ : - General code quality improvements (Ongoing) diff --git a/jest.config.js b/jest.config.js index 71ecc51..bf76b38 100644 --- a/jest.config.js +++ b/jest.config.js @@ -1,6 +1,6 @@ export default { collectCoverage: true, - coverageReporters: ['json'], + coverageReporters: ['json', 'lcov'], moduleDirectories: [ "node_modules" ], diff --git a/package-lock.json b/package-lock.json index cd9f7a6..2adc0cf 100644 --- a/package-lock.json +++ b/package-lock.json @@ -11,13 +11,16 @@ "dependencies": { "clipboardy": "^3.0.0", "commander": "^11.0.0", + "drivelist": "^11.1.0", "esbuild": "0.18.13", "ip": "^1.1.8", "md6-hash": "^1.0.0", "node-machine-id": "^1.1.12", "qrcode-terminal": "^0.12.0", "readline-sync": "^1.4.10", - "totp.js": "^0.0.1" + "totp.js": "^0.0.1", + "usb": "^2.9.0", + "usb-detection": "^4.14.2" }, "bin": { "sharkkey": "src/index.js" @@ -1682,6 +1685,11 @@ "integrity": "sha512-cputDpIbFgLUaGQn6Vqg3/YsJwxUwHLO13v3i5ouxT4lat0khip9AEWxtERujXV9wxIB1EyF97BSJFt6vpdI8g==", "dev": true }, + "node_modules/@types/w3c-web-usb": { + "version": "1.0.6", + "resolved": "https://registry.npmjs.org/@types/w3c-web-usb/-/w3c-web-usb-1.0.6.tgz", + "integrity": "sha512-cSjhgrr8g4KbPnnijAr/KJDNKa/bBa+ixYkywFRvrhvi9n1WEl7yYbtRyzE6jqNQiSxxJxoAW3STaOQwJHndaw==" + }, "node_modules/@types/yargs": { "version": "17.0.24", "resolved": "https://registry.npmjs.org/@types/yargs/-/yargs-17.0.24.tgz", @@ -1930,6 +1938,43 @@ "integrity": "sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==", "dev": true }, + "node_modules/base64-js": { + "version": "1.5.1", + "resolved": "https://registry.npmjs.org/base64-js/-/base64-js-1.5.1.tgz", + "integrity": "sha512-AKpaYlHn8t4SVbOHCy+b5+KKgvR4vrsD8vbvrbiQJps7fKDTkjkDry6ji0rUJjC0kzbNePLwzxq8iypo41qeWA==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ] + }, + "node_modules/bindings": { + "version": "1.5.0", + "resolved": "https://registry.npmjs.org/bindings/-/bindings-1.5.0.tgz", + "integrity": "sha512-p2q/t/mhvuOj/UeLlV6566GD/guowlr0hHxClI0W9m7MWYkL1F0hLo+0Aexs9HSPCtR1SXQ0TD3MMKrXZajbiQ==", + "dependencies": { + "file-uri-to-path": "1.0.0" + } + }, + "node_modules/bl": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/bl/-/bl-4.1.0.tgz", + "integrity": "sha512-1W07cM9gS6DcLperZfFSj+bWLtaPGSOHWhPiGzXmvVJbRLdG82sH/Kn8EtW1VqWVA54AKf2h5k5BbnIbwF3h6w==", + "dependencies": { + "buffer": "^5.5.0", + "inherits": "^2.0.4", + "readable-stream": "^3.4.0" + } + }, "node_modules/brace-expansion": { "version": "1.1.11", "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz", @@ -1993,6 +2038,29 @@ "node-int64": "^0.4.0" } }, + "node_modules/buffer": { + "version": "5.7.1", + "resolved": "https://registry.npmjs.org/buffer/-/buffer-5.7.1.tgz", + "integrity": "sha512-EHcyIPBQ4BSGlvjB16k5KgAJ27CIsHY/2JBmCRReo48y9rQ3MaUzWX3KVlBa4U7MyX02HdVj0K7C3WaB3ju7FQ==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ], + "dependencies": { + "base64-js": "^1.3.1", + "ieee754": "^1.1.13" + } + }, "node_modules/buffer-from": { "version": "1.1.2", "resolved": "https://registry.npmjs.org/buffer-from/-/buffer-from-1.1.2.tgz", @@ -2072,6 +2140,11 @@ "url": "https://github.com/sponsors/wooorm" } }, + "node_modules/chownr": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/chownr/-/chownr-1.1.4.tgz", + "integrity": "sha512-jJ0bqzaylmJtVnNgzTeSOs8DPavpbYgEr/b0YL8/2GO3xJEhInFmhKMUnEJQjZumK7KXGFhUy89PrsJWlakBVg==" + }, "node_modules/ci-info": { "version": "3.8.0", "resolved": "https://registry.npmjs.org/ci-info/-/ci-info-3.8.0.tgz", @@ -2194,7 +2267,6 @@ "version": "4.3.4", "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.4.tgz", "integrity": "sha512-PRWFHuSU3eDtQJPvnNY7Jcket1j0t5OuOsFzPPzsekD52Zl8qUfFIPEiswXqIvHWGVHOgX+7G/vCNNhehwxfkQ==", - "dev": true, "dependencies": { "ms": "2.1.2" }, @@ -2220,12 +2292,34 @@ "url": "https://github.com/sponsors/wooorm" } }, + "node_modules/decompress-response": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/decompress-response/-/decompress-response-6.0.0.tgz", + "integrity": "sha512-aW35yZM6Bb/4oJlZncMH2LCoZtJXTRxES17vE3hoRiowU2kWHaJKFkSBDnDR+cm9J+9QhXmREyIfv0pji9ejCQ==", + "dependencies": { + "mimic-response": "^3.1.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, "node_modules/dedent": { "version": "0.7.0", "resolved": "https://registry.npmjs.org/dedent/-/dedent-0.7.0.tgz", "integrity": "sha512-Q6fKUPqnAHAyhiUgFU7BUzLiv0kd8saH9al7tnu5Q/okj6dnupxyTgFIBjVzJATdfIAm9NAsvXNzjaKa+bxVyA==", "dev": true }, + "node_modules/deep-extend": { + "version": "0.6.0", + "resolved": "https://registry.npmjs.org/deep-extend/-/deep-extend-0.6.0.tgz", + "integrity": "sha512-LOHxIOaPYdHlJRtCQfDIVZtfw/ufM8+rVj649RIHzcm/vGwQRXFt6OPqIFWsm2XEMrNIEtWR64sY1LEKD2vAOA==", + "engines": { + "node": ">=4.0.0" + } + }, "node_modules/deep-is": { "version": "0.1.4", "resolved": "https://registry.npmjs.org/deep-is/-/deep-is-0.1.4.tgz", @@ -2250,6 +2344,14 @@ "node": ">=6" } }, + "node_modules/detect-libc": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/detect-libc/-/detect-libc-2.0.2.tgz", + "integrity": "sha512-UX6sGumvvqSaXgdKGUsgZWqcUyIXZ/vZTrlRT/iobiKhGL0zL4d3osHj3uqllWJK+i+sixDS/3COVEOFbupFyw==", + "engines": { + "node": ">=8" + } + }, "node_modules/detect-newline": { "version": "3.1.0", "resolved": "https://registry.npmjs.org/detect-newline/-/detect-newline-3.1.0.tgz", @@ -2289,6 +2391,26 @@ "node": ">=6.0.0" } }, + "node_modules/drivelist": { + "version": "11.1.0", + "resolved": "https://registry.npmjs.org/drivelist/-/drivelist-11.1.0.tgz", + "integrity": "sha512-DT328SbKqB78y+HUeuazwj4+Enh5ormv9OgTIMB0/OP2VxKLFDOrKhejJxjP9ytmJok8W/nzR8gSWdpiaJi1XA==", + "hasInstallScript": true, + "dependencies": { + "bindings": "^1.5.0", + "debug": "^4.3.4", + "node-addon-api": "^5.0.0", + "prebuild-install": "^7.1.1" + }, + "engines": { + "node": ">=16 < 19" + } + }, + "node_modules/drivelist/node_modules/node-addon-api": { + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/node-addon-api/-/node-addon-api-5.1.0.tgz", + "integrity": "sha512-eh0GgfEkpnoWDq+VY8OyvYhFEzBk6jIYbRKdIlyTiAXIVJ8PyBaKb0rp7oDtoddbdoHWhq8wwr+XZ81F1rpNdA==" + }, "node_modules/electron-to-chromium": { "version": "1.4.461", "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.4.461.tgz", @@ -2313,6 +2435,14 @@ "integrity": "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==", "dev": true }, + "node_modules/end-of-stream": { + "version": "1.4.4", + "resolved": "https://registry.npmjs.org/end-of-stream/-/end-of-stream-1.4.4.tgz", + "integrity": "sha512-+uw1inIHVPQoaVuHzRyXd21icM+cnt4CzD5rW+NC1wjOUSTOs+Te7FOv7AhN7vS9x/oIyhLP5PR1H+phQAHu5Q==", + "dependencies": { + "once": "^1.4.0" + } + }, "node_modules/error-ex": { "version": "1.3.2", "resolved": "https://registry.npmjs.org/error-ex/-/error-ex-1.3.2.tgz", @@ -2533,6 +2663,11 @@ "node": ">=0.10.0" } }, + "node_modules/eventemitter2": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/eventemitter2/-/eventemitter2-5.0.1.tgz", + "integrity": "sha512-5EM1GHXycJBS6mauYAbVKT1cVs7POKWb2NXD4Vyt8dDqeZa7LaDK1/sjtL+Zb0lzTpSNil4596Dyu97hz37QLg==" + }, "node_modules/execa": { "version": "5.1.1", "resolved": "https://registry.npmjs.org/execa/-/execa-5.1.1.tgz", @@ -2564,6 +2699,14 @@ "node": ">= 0.8.0" } }, + "node_modules/expand-template": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/expand-template/-/expand-template-2.0.3.tgz", + "integrity": "sha512-XYfuKMvj4O35f/pOXLObndIRvyQ+/+6AhODh+OKWj9S9498pHHn/IMszH+gt0fBCRWMNfk1ZSp5x3AifmnI2vg==", + "engines": { + "node": ">=6" + } + }, "node_modules/expect": { "version": "29.6.1", "resolved": "https://registry.npmjs.org/expect/-/expect-29.6.1.tgz", @@ -2635,6 +2778,11 @@ "node": "^10.12.0 || >=12.0.0" } }, + "node_modules/file-uri-to-path": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/file-uri-to-path/-/file-uri-to-path-1.0.0.tgz", + "integrity": "sha512-0Zt+s3L7Vf1biwWZ29aARiVYLx7iMGnEUl9x33fbB/j3jR81u/O2LbqK+Bm1CDSNDKVtJ/YjwY7TUd5SkeLQLw==" + }, "node_modules/fill-range": { "version": "7.0.1", "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-7.0.1.tgz", @@ -2682,6 +2830,11 @@ "integrity": "sha512-5nqDSxl8nn5BSNxyR3n4I6eDmbolI6WT+QqR547RwxQapgjQBmtktdP+HTBb/a/zLsbzERTONyUB5pefh5TtjQ==", "dev": true }, + "node_modules/fs-constants": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/fs-constants/-/fs-constants-1.0.0.tgz", + "integrity": "sha512-y6OAwoSIf7FyjMIv94u+b5rdheZEjzR63GTyZJm5qh4Bi+2YgwLCcI/fPFZkL5PSixOt6ZNKm+w+Hfp/Bciwow==" + }, "node_modules/fs.realpath": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/fs.realpath/-/fs.realpath-1.0.0.tgz", @@ -2746,6 +2899,11 @@ "url": "https://github.com/sponsors/sindresorhus" } }, + "node_modules/github-from-package": { + "version": "0.0.0", + "resolved": "https://registry.npmjs.org/github-from-package/-/github-from-package-0.0.0.tgz", + "integrity": "sha512-SyHy3T1v2NUXn29OsWdxmK6RwHD+vkj3v8en8AOBZ1wBQ/hCAQ5bAQTD02kW4W9tUp/3Qh6J8r9EvntiyCmOOw==" + }, "node_modules/glob": { "version": "7.2.3", "resolved": "https://registry.npmjs.org/glob/-/glob-7.2.3.tgz", @@ -2852,6 +3010,25 @@ "node": ">=10.17.0" } }, + "node_modules/ieee754": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/ieee754/-/ieee754-1.2.1.tgz", + "integrity": "sha512-dcyqhDvX1C46lXZcVqCpK+FtMRQVdIMN6/Df5js2zouUsqG7I6sFxitIC+7KYK29KdXOLHdu9zL4sFnoVQnqaA==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ] + }, "node_modules/ignore": { "version": "5.2.4", "resolved": "https://registry.npmjs.org/ignore/-/ignore-5.2.4.tgz", @@ -2918,8 +3095,12 @@ "node_modules/inherits": { "version": "2.0.4", "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.4.tgz", - "integrity": "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==", - "dev": true + "integrity": "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==" + }, + "node_modules/ini": { + "version": "1.3.8", + "resolved": "https://registry.npmjs.org/ini/-/ini-1.3.8.tgz", + "integrity": "sha512-JV/yugV2uzW5iMRSiZAyDtQd+nxtUnjeLt0acNdw98kKLrvuRVyB80tsREOE7yvGVgalhZ6RNXCmEHkUKBKxew==" }, "node_modules/ip": { "version": "1.1.8", @@ -4496,6 +4677,17 @@ "node": ">=6" } }, + "node_modules/mimic-response": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/mimic-response/-/mimic-response-3.1.0.tgz", + "integrity": "sha512-z0yWI+4FDrrweS8Zmt4Ej5HdJmky15+L2e6Wgn3+iK5fWzb6T3fhNFq2+MeTRb064c6Wr4N/wv0DzQTjNzHNGQ==", + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, "node_modules/minimatch": { "version": "3.1.2", "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz", @@ -4508,6 +4700,19 @@ "node": "*" } }, + "node_modules/minimist": { + "version": "1.2.8", + "resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.8.tgz", + "integrity": "sha512-2yyAR8qBkN3YuheJanUpWC5U3bb5osDywNB8RzDVlDwDHbocAJveqqj1u8+SVD7jkWT4yvsHCpWqqWqAxb0zCA==", + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/mkdirp-classic": { + "version": "0.5.3", + "resolved": "https://registry.npmjs.org/mkdirp-classic/-/mkdirp-classic-0.5.3.tgz", + "integrity": "sha512-gKLcREMhtuZRwRAfqP3RFW+TK4JqApVBtOIftVgjuABpAtpxhPGaDcfvbhNvD0B8iD1oUr/txX35NjcaY6Ns/A==" + }, "node_modules/mri": { "version": "1.2.0", "resolved": "https://registry.npmjs.org/mri/-/mri-1.2.0.tgz", @@ -4520,8 +4725,17 @@ "node_modules/ms": { "version": "2.1.2", "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", - "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==", - "dev": true + "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==" + }, + "node_modules/nan": { + "version": "2.17.0", + "resolved": "https://registry.npmjs.org/nan/-/nan-2.17.0.tgz", + "integrity": "sha512-2ZTgtl0nJsO0KQCjEpxcIr5D+Yv90plTitZt9JBfQvVJDS5seMl3FOvsh3+9CoYWXf/1l5OaZzzF6nDm4cagaQ==" + }, + "node_modules/napi-build-utils": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/napi-build-utils/-/napi-build-utils-1.0.2.tgz", + "integrity": "sha512-ONmRUqK7zj7DWX0D9ADe03wbwOBZxNAfF20PlGfCWQcD3+/MakShIHrMqx9YwPTfxDdF1zLeL+RGZiR9kGMLdg==" }, "node_modules/natural-compare": { "version": "1.4.0", @@ -4529,6 +4743,62 @@ "integrity": "sha512-OWND8ei3VtNC9h7V60qff3SVobHr996CTwgxubgyQYEpg290h9J0buyECNNJexkFm5sOajh5G116RYA1c8ZMSw==", "dev": true }, + "node_modules/node-abi": { + "version": "3.45.0", + "resolved": "https://registry.npmjs.org/node-abi/-/node-abi-3.45.0.tgz", + "integrity": "sha512-iwXuFrMAcFVi/ZoZiqq8BzAdsLw9kxDfTC0HMyjXfSL/6CSDAGD5UmR7azrAgWV1zKYq7dUUMj4owusBWKLsiQ==", + "dependencies": { + "semver": "^7.3.5" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/node-abi/node_modules/lru-cache": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-6.0.0.tgz", + "integrity": "sha512-Jo6dJ04CmSjuznwJSS3pUeWmd/H0ffTlkXXgwZi+eq1UCmqQwCh+eLsYOYCwY991i2Fah4h1BEMCx4qThGbsiA==", + "dependencies": { + "yallist": "^4.0.0" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/node-abi/node_modules/semver": { + "version": "7.5.4", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.5.4.tgz", + "integrity": "sha512-1bCSESV6Pv+i21Hvpxp3Dx+pSD8lIPt8uVjRrxAUt/nbswYc+tK6Y2btiULjd4+fnq15PX+nqQDC7Oft7WkwcA==", + "dependencies": { + "lru-cache": "^6.0.0" + }, + "bin": { + "semver": "bin/semver.js" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/node-abi/node_modules/yallist": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/yallist/-/yallist-4.0.0.tgz", + "integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==" + }, + "node_modules/node-addon-api": { + "version": "6.1.0", + "resolved": "https://registry.npmjs.org/node-addon-api/-/node-addon-api-6.1.0.tgz", + "integrity": "sha512-+eawOlIgy680F0kBzPUNFhMZGtJ1YmqM6l4+Crf4IkImjYrO/mqPwRMh352g23uIaQKFItcQ64I7KMaJxHgAVA==" + }, + "node_modules/node-gyp-build": { + "version": "4.6.0", + "resolved": "https://registry.npmjs.org/node-gyp-build/-/node-gyp-build-4.6.0.tgz", + "integrity": "sha512-NTZVKn9IylLwUzaKjkas1e4u2DLNcV4rdYagA4PWdPwW87Bi7z+BznyKSRwS/761tV/lzCGXplWsiaMjLqP2zQ==", + "bin": { + "node-gyp-build": "bin.js", + "node-gyp-build-optional": "optional.js", + "node-gyp-build-test": "build-test.js" + } + }, "node_modules/node-int64": { "version": "0.4.0", "resolved": "https://registry.npmjs.org/node-int64/-/node-int64-0.4.0.tgz", @@ -4570,7 +4840,6 @@ "version": "1.4.0", "resolved": "https://registry.npmjs.org/once/-/once-1.4.0.tgz", "integrity": "sha512-lNaJgI+2Q5URQBkccEKHTQOPaXdUxnZZElQTZY0MFUAuaEqe1E+Nyvgdz/aIyNi6Z9MzO5dv1H8n58/GELp3+w==", - "dev": true, "dependencies": { "wrappy": "1" } @@ -4821,6 +5090,31 @@ "node": ">=4" } }, + "node_modules/prebuild-install": { + "version": "7.1.1", + "resolved": "https://registry.npmjs.org/prebuild-install/-/prebuild-install-7.1.1.tgz", + "integrity": "sha512-jAXscXWMcCK8GgCoHOfIr0ODh5ai8mj63L2nWrjuAgXE6tDyYGnx4/8o/rCgU+B4JSyZBKbeZqzhtwtC3ovxjw==", + "dependencies": { + "detect-libc": "^2.0.0", + "expand-template": "^2.0.3", + "github-from-package": "0.0.0", + "minimist": "^1.2.3", + "mkdirp-classic": "^0.5.3", + "napi-build-utils": "^1.0.1", + "node-abi": "^3.3.0", + "pump": "^3.0.0", + "rc": "^1.2.7", + "simple-get": "^4.0.0", + "tar-fs": "^2.0.0", + "tunnel-agent": "^0.6.0" + }, + "bin": { + "prebuild-install": "bin.js" + }, + "engines": { + "node": ">=10" + } + }, "node_modules/prelude-ls": { "version": "1.2.1", "resolved": "https://registry.npmjs.org/prelude-ls/-/prelude-ls-1.2.1.tgz", @@ -4869,6 +5163,15 @@ "node": ">= 6" } }, + "node_modules/pump": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/pump/-/pump-3.0.0.tgz", + "integrity": "sha512-LwZy+p3SFs1Pytd/jYct4wpv49HiYCqd9Rlc5ZVdk0V+8Yzv6jR5Blk3TRmPL1ft69TxP0IMZGJ+WPFU2BFhww==", + "dependencies": { + "end-of-stream": "^1.1.0", + "once": "^1.3.1" + } + }, "node_modules/punycode": { "version": "2.3.0", "resolved": "https://registry.npmjs.org/punycode/-/punycode-2.3.0.tgz", @@ -4922,12 +5225,47 @@ } ] }, + "node_modules/rc": { + "version": "1.2.8", + "resolved": "https://registry.npmjs.org/rc/-/rc-1.2.8.tgz", + "integrity": "sha512-y3bGgqKj3QBdxLbLkomlohkvsA8gdAiUQlSBJnBhfn+BPxg4bc62d8TcBW15wavDfgexCgccckhcZvywyQYPOw==", + "dependencies": { + "deep-extend": "^0.6.0", + "ini": "~1.3.0", + "minimist": "^1.2.0", + "strip-json-comments": "~2.0.1" + }, + "bin": { + "rc": "cli.js" + } + }, + "node_modules/rc/node_modules/strip-json-comments": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/strip-json-comments/-/strip-json-comments-2.0.1.tgz", + "integrity": "sha512-4gB8na07fecVVkOI6Rs4e7T6NOTki5EmL7TUduTs6bu3EdnSycntVJ4re8kgZA+wx9IueI2Y11bfbgwtzuE0KQ==", + "engines": { + "node": ">=0.10.0" + } + }, "node_modules/react-is": { "version": "18.2.0", "resolved": "https://registry.npmjs.org/react-is/-/react-is-18.2.0.tgz", "integrity": "sha512-xWGDIW6x921xtzPkhiULtthJHoJvBbF3q26fzloPCK0hsvxtPVelvftw3zjbHWSkR2km9Z+4uxbDDK/6Zw9B8w==", "dev": true }, + "node_modules/readable-stream": { + "version": "3.6.2", + "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-3.6.2.tgz", + "integrity": "sha512-9u/sniCrY3D5WdsERHzHE4G2YCXqoG5FTHUiCC4SIbr6XcLZBY05ya9EKjYek9O5xOAwjGq+1JdGBAS7Q9ScoA==", + "dependencies": { + "inherits": "^2.0.3", + "string_decoder": "^1.1.1", + "util-deprecate": "^1.0.1" + }, + "engines": { + "node": ">= 6" + } + }, "node_modules/readline-sync": { "version": "1.4.10", "resolved": "https://registry.npmjs.org/readline-sync/-/readline-sync-1.4.10.tgz", @@ -5903,6 +6241,25 @@ "node": ">=6" } }, + "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" + } + ] + }, "node_modules/semver": { "version": "6.3.1", "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.1.tgz", @@ -5936,6 +6293,49 @@ "resolved": "https://registry.npmjs.org/signal-exit/-/signal-exit-3.0.7.tgz", "integrity": "sha512-wnD2ZE+l+SPC/uoS0vXeE9L1+0wuaMqKlfz9AMUo38JsyLSBWSFcHR1Rri62LZc12vLr1gb3jl7iwQhgwpAbGQ==" }, + "node_modules/simple-concat": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/simple-concat/-/simple-concat-1.0.1.tgz", + "integrity": "sha512-cSFtAPtRhljv69IK0hTVZQ+OfE9nePi/rtJmw5UjHeVyVroEqJXP1sFztKUy1qU+xvz3u/sfYJLa947b7nAN2Q==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ] + }, + "node_modules/simple-get": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/simple-get/-/simple-get-4.0.1.tgz", + "integrity": "sha512-brv7p5WgH0jmQJr1ZDDfKDOSeWWg+OVypG99A/5vYGPqJ6pxiaHLy8nxtFjBA7oMa01ebA9gfh1uMCFqOuXxvA==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ], + "dependencies": { + "decompress-response": "^6.0.0", + "once": "^1.3.1", + "simple-concat": "^1.0.0" + } + }, "node_modules/sisteransi": { "version": "1.0.5", "resolved": "https://registry.npmjs.org/sisteransi/-/sisteransi-1.0.5.tgz", @@ -5997,6 +6397,14 @@ "node": ">=8" } }, + "node_modules/string_decoder": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.3.0.tgz", + "integrity": "sha512-hkRX8U1WjJFd8LsDJ2yQ/wWWxaopEsABU1XfkM8A+j0+85JAGppt16cr1Whg6KIbb4okU6Mql6BOj+uup/wKeA==", + "dependencies": { + "safe-buffer": "~5.2.0" + } + }, "node_modules/string-length": { "version": "4.0.2", "resolved": "https://registry.npmjs.org/string-length/-/string-length-4.0.2.tgz", @@ -6089,6 +6497,32 @@ "url": "https://github.com/sponsors/ljharb" } }, + "node_modules/tar-fs": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/tar-fs/-/tar-fs-2.1.1.tgz", + "integrity": "sha512-V0r2Y9scmbDRLCNex/+hYzvp/zyYjvFbHPNgVTKfQvVrb6guiE/fxP+XblDNR011utopbkex2nM4dHNV6GDsng==", + "dependencies": { + "chownr": "^1.1.1", + "mkdirp-classic": "^0.5.2", + "pump": "^3.0.0", + "tar-stream": "^2.1.4" + } + }, + "node_modules/tar-stream": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/tar-stream/-/tar-stream-2.2.0.tgz", + "integrity": "sha512-ujeqbceABgwMZxEJnk2HDY2DlnUZ+9oEcb1KzTVfYHio0UE6dG71n60d8D2I4qNvleWrrXpmjpt7vZeF1LnMZQ==", + "dependencies": { + "bl": "^4.0.3", + "end-of-stream": "^1.4.1", + "fs-constants": "^1.0.0", + "inherits": "^2.0.3", + "readable-stream": "^3.1.1" + }, + "engines": { + "node": ">=6" + } + }, "node_modules/test-exclude": { "version": "6.0.0", "resolved": "https://registry.npmjs.org/test-exclude/-/test-exclude-6.0.0.tgz", @@ -6163,6 +6597,17 @@ "url": "https://github.com/sponsors/wooorm" } }, + "node_modules/tunnel-agent": { + "version": "0.6.0", + "resolved": "https://registry.npmjs.org/tunnel-agent/-/tunnel-agent-0.6.0.tgz", + "integrity": "sha512-McnNiV1l8RYeY8tBgEpuodCC1mLUdbSN+CYBL7kJsJNInOP8UjDDEwdk6Mw60vdLLrr5NHKZhMAOSrR2NZuQ+w==", + "dependencies": { + "safe-buffer": "^5.0.1" + }, + "engines": { + "node": "*" + } + }, "node_modules/type-check": { "version": "0.4.0", "resolved": "https://registry.npmjs.org/type-check/-/type-check-0.4.0.tgz", @@ -6391,6 +6836,40 @@ "punycode": "^2.1.0" } }, + "node_modules/usb": { + "version": "2.9.0", + "resolved": "https://registry.npmjs.org/usb/-/usb-2.9.0.tgz", + "integrity": "sha512-G0I/fPgfHUzWH8xo2KkDxTTFruUWfppgSFJ+bQxz/kVY2x15EQ/XDB7dqD1G432G4gBG4jYQuF3U7j/orSs5nw==", + "hasInstallScript": true, + "dependencies": { + "@types/w3c-web-usb": "^1.0.6", + "node-addon-api": "^6.0.0", + "node-gyp-build": "^4.5.0" + }, + "engines": { + "node": ">=10.20.0 <11.x || >=12.17.0 <13.0 || >=14.0.0" + } + }, + "node_modules/usb-detection": { + "version": "4.14.2", + "resolved": "https://registry.npmjs.org/usb-detection/-/usb-detection-4.14.2.tgz", + "integrity": "sha512-bDWuytXW3tJq/Nkr6pucIMW4QtOTgu1KHwk2g0Dk/xXRvXW+/IEMDFJdQxDwiWfz41ADvs9amZuKirD9VM0gWA==", + "hasInstallScript": true, + "dependencies": { + "bindings": "^1.5.0", + "eventemitter2": "^5.0.1", + "nan": "^2.15.0", + "prebuild-install": "^7.0.1" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/util-deprecate": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/util-deprecate/-/util-deprecate-1.0.2.tgz", + "integrity": "sha512-EPD5q1uXyFxJpCrLnCc1nHnq3gOa6DZBocAIiI2TaSCA7VCJ1UJDMagCzIkXNsUYfD1daK//LTEQ8xiIbrHtcw==" + }, "node_modules/uvu": { "version": "0.5.6", "resolved": "https://registry.npmjs.org/uvu/-/uvu-0.5.6.tgz", @@ -6525,8 +7004,7 @@ "node_modules/wrappy": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz", - "integrity": "sha512-l4Sp/DRseor9wL6EvV2+TuQn63dMkPjZ/sp9XkghTEbV9KlPS1xUsZ3u7/IQO4wxtcFB4bgpQPRcR3QCvezPcQ==", - "dev": true + "integrity": "sha512-l4Sp/DRseor9wL6EvV2+TuQn63dMkPjZ/sp9XkghTEbV9KlPS1xUsZ3u7/IQO4wxtcFB4bgpQPRcR3QCvezPcQ==" }, "node_modules/write-file-atomic": { "version": "4.0.2", diff --git a/package.json b/package.json index db34f85..5b32062 100644 --- a/package.json +++ b/package.json @@ -24,13 +24,16 @@ "dependencies": { "clipboardy": "^3.0.0", "commander": "^11.0.0", + "drivelist": "^11.1.0", "esbuild": "0.18.13", "ip": "^1.1.8", "md6-hash": "^1.0.0", "node-machine-id": "^1.1.12", "qrcode-terminal": "^0.12.0", "readline-sync": "^1.4.10", - "totp.js": "^0.0.1" + "totp.js": "^0.0.1", + "usb": "^2.9.0", + "usb-detection": "^4.14.2" }, "devDependencies": { "eslint": "^8.45.0", diff --git a/src/index.js b/src/index.js index 52c2b75..5c55694 100644 --- a/src/index.js +++ b/src/index.js @@ -49,6 +49,10 @@ program // Set basic info "Include the name of the file being encrypted as part of the encryption process") .option('--totp', "Require TOTP authentacation before decrypting") + .option('--compression', + "Compress output") + .option('--usb', + "Require specefic USB drive to be connected before decrypting") .action((file, pass, options) => { let aaa = handleOpts(options); let features = aaa[0]; @@ -99,10 +103,13 @@ program // Set basic info createIDFile: options.createID, isString: options.string, doCopy: options.copy, - userkey: pass || "cHaNgE-mE" + userkey: pass || "cHaNgE-mE", + compression: options.compression || false } ); + + // Define variables here so we can use them in the switch statement let outputStr, outputMessage; @@ -150,6 +157,8 @@ program // Set basic info "Delete original file after encryption") .option('-s, --string', "Encrypt a string instead of a file") + .option('--compression', + 'Decompress output') .option('-c, --copy', "Copy the decrypted file or string to the clipboard after decryption") .action((file, pass, idfile, options) => { @@ -170,7 +179,7 @@ program // Set basic info ✨✨✨✨✨✨✨✨✨✨✨✨✨✨✨✨✨✨✨✨✨✨✨✨✨✨✨`; // Check if we're gonna be using an ID file to decrypt - if (Object.prototype.hasOwnProperty.call(options, 'useID') || options.useID) { + if (options.useID) { // Use ID to decrypt fiie // 🦈--> Implement logic throw new Error("Not implemented"); @@ -182,7 +191,8 @@ program // Set basic info file, options.deleteOriginal, options.string, - options.copy + options.copy, + options.compression ); } catch (err) { console.log("[🦈🔑] We were unable to decrypt the data with the info you provided."); @@ -263,9 +273,9 @@ program.parse(process.argv); function handleOpts(opts) { let features = []; - let values = { deleteOriginal: false, createID: false, string: false, copy: false, useID: false, verbose: false }; + let values = { deleteOriginal: false, createID: false, string: false, copy: false, useID: false, verbose: false, compression: false }; for (const opt in opts) { - if (["deleteOriginal", "createID", "string", "copy", "useID", "verbose"].includes(opt)) { + if (["deleteOriginal", "createID", "string", "copy", "useID", "verbose", "compression"].includes(opt)) { values[opt] = true; continue; } diff --git a/src/index.test.js b/src/index.test.js index de3fa97..7730bd0 100644 --- a/src/index.test.js +++ b/src/index.test.js @@ -15,6 +15,7 @@ describe("files", () => { test("encrypt file", () => { fs.writeFileSync("jestFile.txt", "hello world", "utf8"); + fs.writeFileSync("jestFile2.txt", "hello world", "utf8"); expect(shark.cryptography.encrypt(hashKey, "./jestFile.txt", true, { features: [], createIDFile: false, @@ -24,6 +25,34 @@ describe("files", () => { })) .toBe(true); }); + test("encrypt file with compression", () => { + fs.writeFileSync("jestFile2.txt", "hello world", "utf8"); + expect(shark.cryptography.encrypt(hashKey, "./jestFile2.txt", true, { + features: [], + createIDFile: false, + isString: false, + doCopy: false, + userkey: "cHaNgE-mE", + compression: true + })) + .toBe(true); + }); + test("encrypt file with features", () => { + fs.writeFileSync("jestFile3.txt", "features test", "utf8"); + let localHashKey = shark.cryptography.calculateKey( + "cHaNgE-mE", ['hwid', 'distro', 'lip', 'username', 'timezone', 'locale', 'hostname', 'platform', 'serial', 'filename'], + false, + "./jestFile3.txt"); + expect(shark.cryptography.encrypt(localHashKey, "./jestFile3.txt", true, { + features: ['hwid', 'distro', 'lip', 'username', 'timezone', 'locale', 'hostname', 'platform', 'serial', 'filename'], + createIDFile: false, + isString: false, + doCopy: false, + userkey: "cHaNgE-mE", + compression: false + })) + .toBe(true); + }); test("encrypt file with id", () => { fs.writeFileSync("jestFileId.txt", "hello world", "utf8"); let hk = shark.cryptography.calculateKey( @@ -54,9 +83,29 @@ describe("files", () => { .toHaveProperty('id', { '0': '992469a97b348ca4', '1': '502c4b8f4ae94915' }); }); test("decrypt file", () => { - expect(shark.cryptography.decrypt("jestPass", "./jestFile.txt.🦈🔑", true, false, false)) + expect(shark.cryptography.decrypt("jestPass", "./jestFile.txt.🦈🔑", true, false, false, false)) .toBe(true); if (fs.existsSync("jestFile.txt")) fs.unlinkSync("jestFile.txt"); + if (fs.existsSync("jestFile2.txt")) fs.unlinkSync("jestFile2.txt"); + if (fs.existsSync("jestFileId.txt.🦈🔑")) fs.unlinkSync("jestFileId.txt.🦈🔑"); + if (fs.existsSync("jestFileId.txt.🦈🔑🪪")) fs.unlinkSync("jestFileId.txt.🦈🔑🪪"); + if (fs.existsSync("jestFileTOTP.txt.🦈🔑")) fs.unlinkSync("jestFileTOTP.txt.🦈🔑"); + }); + test("decrypt file with compression", () => { + expect(shark.cryptography.decrypt("jestPass", "./jestFile2.txt.🦈🔑", true, false, false, true)) + .toBe(true); + if (fs.existsSync("jestFile.txt")) fs.unlinkSync("jestFile.txt"); + if (fs.existsSync("jestFile2.txt")) fs.unlinkSync("jestFile2.txt"); + if (fs.existsSync("jestFileId.txt.🦈🔑")) fs.unlinkSync("jestFileId.txt.🦈🔑"); + if (fs.existsSync("jestFileId.txt.🦈🔑🪪")) fs.unlinkSync("jestFileId.txt.🦈🔑🪪"); + if (fs.existsSync("jestFileTOTP.txt.🦈🔑")) fs.unlinkSync("jestFileTOTP.txt.🦈🔑"); + }); + test("decrypt file with features", () => { + expect(shark.cryptography.decrypt("cHaNgE-mE", "./jestFile3.txt.🦈🔑", true, false, false, false)) + .toBe(true); + if (fs.existsSync("jestFile.txt")) fs.unlinkSync("jestFile.txt"); + if (fs.existsSync("jestFile2.txt")) fs.unlinkSync("jestFile2.txt"); + if (fs.existsSync("jestFile3.txt")) fs.unlinkSync("jestFile3.txt"); if (fs.existsSync("jestFileId.txt.🦈🔑")) fs.unlinkSync("jestFileId.txt.🦈🔑"); if (fs.existsSync("jestFileId.txt.🦈🔑🪪")) fs.unlinkSync("jestFileId.txt.🦈🔑🪪"); if (fs.existsSync("jestFileTOTP.txt.🦈🔑")) fs.unlinkSync("jestFileTOTP.txt.🦈🔑"); @@ -137,4 +186,14 @@ describe("fish hash", () => { expect(h.fish512("hello world", "utf8")) .toBe("0b876d42c8e72587b32b443feaeac514305046146b0cc9152194c80ce53994ae0c5f8484cb3c8ea6350db144a857a3d45876371980a24f109717424cd56ba934889dc38f657a8fe499f924a51146fa8ae1a0d6d68dfed639084f261ce5fffc5a5298798fed6f230f5846d2a9d424d0a154a642d673514f8f73e62a03778af865"); }); +}); +describe("disklist", () => { + test("async", async() => { + expect(typeof await shark.disklist.listDrives() === 'object') + .toBeTruthy(); + }); + test("sync", () => { + expect(typeof shark.disklist.listDrivesSync() === 'object') + .toBeTruthy(); + }); }); \ No newline at end of file diff --git "a/src/\360\237\220\237/cryptography.js" "b/src/\360\237\220\237/cryptography.js" index 2816728..697c885 100644 --- "a/src/\360\237\220\237/cryptography.js" +++ "b/src/\360\237\220\237/cryptography.js" @@ -16,10 +16,11 @@ import base32 from 'thirty-two'; import clipboard from 'clipboardy'; import qrcode from 'qrcode-terminal'; import nodeMachineId from 'node-machine-id'; +import drivelist from './disklist.js'; +import Compression from './compression.js'; const { machineIdSync } = nodeMachineId; // Declare idObjectFile so we can use it globally let idObjectFile; - /** * Contains cryptographic functions for 🦈.js */ @@ -259,7 +260,17 @@ class Cryptography { if (features.includes("filename")) { id += `${file}`; } - + /* + For this to work we need to refactor disklist.js to provide the exact same output no matter what machine its connected to (win/unix/darwin) + As of right now, the output is different depending on what OS it is, even tho it is the same physical drive. + + if (features.includes("usb")) { + let drive = Cryptography.usb.getSerialHex() || false; + if (typeof drive !== 'object') throw new Error("No useable USB drive connected."); + console.log(`Using drive ${drive.displayName} - ${drive.description} for encryption. This means you need this USB drive to be connected when you decrypt.`); + id += `${drive.serial}`; + } + */ // Remove the spaces from the ID string id = id.replace(/ /g, ""); return id; @@ -352,13 +363,13 @@ class Cryptography { * @returns {string} Altered MD6 hash. */ static md6(md6key) { - // Reverse md5 + // Reverse md6 md6key = md6key.split("").reverse().join(""); // Shift it by its own first int md6key = Cryptography.shift(md6key); - // Reverse md5 + // Reverse md6 md6key = md6key.split("").reverse().join(""); // split by every other - into two arrays (xx, yy) @@ -696,7 +707,7 @@ class Cryptography { * @param {string[]} [features=[]] Array of strings, taken from args, containing info about what info we use to create the ID string for encryption * @returns {string} Base64 encoded hex obfuscated object that contains file / string info, and the raw encrypted data */ - static encryptData(data, key, isString, features = []) { + static encryptData(data, key, isString, features) { let dataToEncrypt; switch (isString) { @@ -724,17 +735,9 @@ class Cryptography { tag = cipher.getAuthTag(); rawEncrypted = enc + "$$" + tag.toString('hex') + "$$" + iv.toString('hex'); encrypted = Cryptography.object.writeFileObject(rawEncrypted, key, features, isString ? "string" : data); + return Buffer.from(encrypted, "utf8").toString("base64"); // encrypts to base64 } catch (err) { - console.log("Error in encryptData! - isString:", isString); - console.log("Relavent variables:"); - console.log("Inputs: Data:", data); - console.log("Inputs: Key:", key); - console.log("Inputs: isString:", isString); - console.log("Internal: dataToEncrypt:", dataToEncrypt); - console.log("Internal: rawEncrypted:", rawEncrypted); - console.log("Internal: encrypted:", encrypted); - console.log("Return: encrypted (Base64):", Buffer.from(encrypted, "utf8").toString("base64")); console.error(err); process.exit(0); } @@ -800,15 +803,20 @@ class Cryptography { * @param {string} [userkey="cHaNgE-mE"] Password for ID files, if created. * @returns {object} Object that contains information about the operation (file location +++) */ - static encrypt(key, data, deleteOriginal = false, options = {}) { - const { - features = [], - createIDFile = false, - isString = false, - doCopy = false, - userkey = "cHaNgE-mE" - } = options; + static encrypt(key, data, deleteOriginal = false, options) { + + let features = options.features || []; + let createIDFile = options.createIDFile || false; + let isString = options.isString || false; + let doCopy = options.doCopy || false; + let userkey = options.userkey || 'cHaNgE-mE'; + let compression = options.compression || false; + let encrypted = Cryptography.encryptData(data, key, isString, features); + + if (compression) { + encrypted = Compression.compressString(encrypted); + } // 🦈--> Add return statements with objects try { switch (isString) { @@ -856,17 +864,27 @@ class Cryptography { * @param {boolean} isString If the data is a string and not a file(path) - set to true if --string is used * @returns {string} Decrypted data */ - static decryptData(key, data, isString) { + static decryptData(key, data, isString, compression = false) { // declare dataToDecrypt for use later let dataToDecrypt; + let file; try { // set dataToDecrypt to the correct data, and decode it from Base64 switch (isString) { case true: + file = 'string'; + if (compression) { + data = Compression.decompressString(data); + } dataToDecrypt = Buffer.from(data, "base64").toString("utf8"); break; case false: - dataToDecrypt = Buffer.from(fs.readFileSync(data, "utf8"), "base64").toString("utf8"); + file = data.replace('.🦈🔑', ''); + if (compression) { + dataToDecrypt = Buffer.from(Compression.decompressString(fs.readFileSync(data, "utf8")), "base64").toString("utf8"); + } else { + dataToDecrypt = Buffer.from(fs.readFileSync(data, "utf8"), "base64").toString("utf8"); + } break; default: console.log("decryptData() - Parameter - isString:", isString); @@ -877,7 +895,7 @@ class Cryptography { let jsonData = Cryptography.object.readFileObject(dataToDecrypt); // Calculate the hashed key - let hashKey = Cryptography.calculateKey(key, jsonData.features, false); + let hashKey = Cryptography.calculateKey(key, jsonData.features, false, file); // Check if the file is secured with TOTP // 🦈--> Gotta think of a better way of implementing this, as of right now - anyone with the source code, JS knowlege, and time can bypass it. @@ -919,9 +937,9 @@ class Cryptography { * @param {boolean} [isString=false] * @param {boolean} [doCopy=false] */ - static decrypt(key, file, deleteOriginal = false, isString = false, doCopy = false) { + static decrypt(key, file, deleteOriginal = false, isString = false, doCopy = false, compression = false) { // Decrypt the file / string - let originalText = Cryptography.decryptData(key, file, isString); // We declare it here first so we can use it in the low later. + let originalText = Cryptography.decryptData(key, file, isString, compression); // We declare it here first so we can use it in the low later. switch (isString) { case true: @@ -973,22 +991,64 @@ class Cryptography { * @returns {object} ID Object */ static checkid(file, key, doCopy = false) { - if (fs.existsSync(file)) { - let id; - let fileData = fs.readFileSync(file, 'utf8'); - try { // Try to decrypt - id = Cryptography.object.decryptObject(key, fileData); - } catch (err) { // 99% chance of it being cased by using the incorrect password, but log to console just in case. - console.log(err); - throw new Error("An error occured while trying to decrypt the file info! - Have you entered the right password?"); - } - if (doCopy) { - // Stringify the id object and copy it to the clipboard - clipboard.writeSync(JSON.stringify(id, null, 2)); + if (fs.existsSync(file)) { + let id; + let fileData = fs.readFileSync(file, 'utf8'); + try { // Try to decrypt + id = Cryptography.object.decryptObject(key, fileData); + } catch (err) { // 99% chance of it being cased by using the incorrect password, but log to console just in case. + console.log(err); + throw new Error("An error occured while trying to decrypt the file info! - Have you entered the right password?"); + } + if (doCopy) { + // Stringify the id object and copy it to the clipboard + clipboard.writeSync(JSON.stringify(id, null, 2)); + } + return id; // Return the id object + } else // 🦈--> This is not serious enough to stop the program, so write an exception handler on the other end. + { throw new Error("File does not exist."); } + } + /** + * Class to work with USB Hard drives for verification + */ + static usb = class { + /** + * @param {boolean} [useUnsafeIdentifiers=false] Wether or not to use unsafe drive identifiers that might change, such as display name, mountpoints, and label + * If set to false, we will use these values: Size, Protected, System, Removable + * @returns Hex string a pseudo serial number of the USB Drive + * TODO: Add var with name so we get the correct USB Drive, and not just some random one. + * TODO: Add function to return USB Drive name, and other identifiers to show to the user + * so they can select the right USB drive they would like to use for encryption. + */ + static getSerialHex(useUnsafeIdentifiers = false) { + try { + const drives = drivelist.listDrivesSync({ returnOnlyRemovable: false }); + let drive = drives.find(_drive => _drive.removable && !_drive.system); + let driveHashString; + switch (useUnsafeIdentifiers) { + case true: + driveHashString = drive.displayName + drive.label + + JSON.stringify(drive.mountpoints) + drive.description + drive.size + + drive.removable + drive.system + drive.protected; + break; + case false: + driveHashString = drive.size + drive.removable + + drive.system + drive.protected; + break; + } + driveHashString = Buffer.from(encodeURIComponent(driveHashString.replace(/ /g, ""))).toString("hex"); + return { + displayName: drive.displayName, + description: drive.description, + serial: Cryptography.hash.fish512(driveHashString, "hex") + }; + } catch (err) { + throw new Error(err); } - return id; // Return the id object - } else // 🦈--> This is not serious enough to stop the program, so write an exception handler on the other end. - { throw new Error("File does not exist."); } - } + } + static checkSerial() { + + } + }; } export default Cryptography; \ No newline at end of file diff --git "a/src/\360\237\220\237/disklist.js" "b/src/\360\237\220\237/disklist.js" new file mode 100644 index 0000000..2607a41 --- /dev/null +++ "b/src/\360\237\220\237/disklist.js" @@ -0,0 +1,230 @@ +import { execSync } from 'node:child_process'; +import os from 'node:os'; +// Set up in global scope +let driveLettersArray = []; +let driveArray = []; +/** + * disklist.listDrives({ returnOnlyRemovable: false }).then(drives => { + console.dir(drives); +}).catch(err => { + console.error(err); +}); + */ +export default class disklist { + /** + * Get drives sync + * @param {Object} options - Options object + * @param {boolean} options.returnOnlyRemovable - Return only removable devices (eg: USB drives) - Default:false + * @param {Object} options.filter - Filter object - Default:{} + * @param {string} options.filter.key - Filter key name, eg: "InterfaceType" or "Partitions" (CaSe SeNsItIvE) + * @param {(string|number)} options.filter.value - Filter value (filter.key === filter.value) eg: "USB", 2 + * @param {number} options.filter.limit - Limit the number of items in the returned array. + * @returns {(Object|Array)} Returns either am array of objects of the drive, or a single drive object + */ + static listDrivesSync(options = { returnOnlyRemovable: false, filter: {} }) { + helpers.populateArrays(); + // Return only removable devices if param is set to it + if (options.returnOnlyRemovable) { + driveArray = driveArray.filter((drive) => drive.MediaType === "Removable Media"); + } + // True of options.filter (Object) is defined, AND it's not empty + if (options.filter && Object.keys(options.filter).length !== 0) { + // Checks to make sure the required varibles are defined and are the correct types + const { key, value, limit } = options.filter; + const hasValidKeyType = typeof key === "string"; + const hasValidLimitType = limit && typeof limit === "number"; + const hasValidValueType = typeof value === "string" || typeof value === "number"; + + // If key & value types are valid + if (hasValidKeyType && hasValidValueType) { + // Check if the desired filter key is a string or a number + if (typeof driveArray[0][key] === "string" || typeof driveArray[0][key] === "number") { + // Apply the filter + driveArray = driveArray.filter((drive) => drive[key] === value); + } else { + throw new Error("Invalid key type in driveArray."); + } + } else { + if (hasValidLimitType) { + if (key || value) { + throw new Error("Filter key and or value or the incorrect types"); + } else { + // filter key & value is not defined, but filter limit type is valid + // Slice the driveArray to match the max item limit + driveArray = driveArray.slice(0, options.filter.limit); + } + } else { + throw new Error("The options.filter object is missing either the 'key' or 'value' key."); + } + } + } + + /** Final checks and returns */ + + // If driveArray is empty, throw error + if (driveArray.length == 0) { + throw new Error("No drives found"); + } + // If only one drive in array, return the object instead of an array with only one item + if (driveArray.length == 1) { + return driveArray[0]; + } + // If not caught by above checks, return the driveArray + return driveArray; + } + + /** + * Get drives + * @param {Object} options - Options object + * @param {boolean} options.returnOnlyRemovable - Return only removable devices (eg: USB drives) - Default:false + * @param {Object} options.filter - Filter object - Default:{} + * @param {string} options.filter.key - Filter key name, eg: "InterfaceType" or "Partitions" (CaSe SeNsItIvE) + * @param {(string|number)} options.filter.value - Filter value (filter.key === filter.value) eg: "USB", 2 + * @param {number} options.filter.limit - Limit the number of items in the returned array. + * @returns {(Object|Array)} Returns either am array of objects of the drive, or a single drive object + */ + static async listDrives(options = { returnOnlyRemovable: false, filter: {} }) { + return new Promise((resolve, reject) => { + helpers.populateArrays(); + // Return only removable devices if param is set to it + if (options.returnOnlyRemovable) { + driveArray = driveArray.filter((drive) => drive.MediaType === "Removable Media"); + } + // True of options.filter (Object) is defined, AND it's not empty + if (options.filter && Object.keys(options.filter).length !== 0) { + // Checks to make sure the required varibles are defined and are the correct types + const { key, value, limit } = options.filter; + const hasValidKeyType = typeof key === "string"; + const hasValidLimitType = limit && typeof limit === "number"; + const hasValidValueType = typeof value === "string" || typeof value === "number"; + + // If key & value types are valid + if (hasValidKeyType && hasValidValueType) { + // Check if the desired filter key is a string or a number + if (typeof driveArray[0][key] === "string" || typeof driveArray[0][key] === "number") { + // Apply the filter + driveArray = driveArray.filter((drive) => drive[key] === value); + } else { + reject("Invalid key type in driveArray."); + } + } else { + if (hasValidLimitType) { + if (key || value) { + reject("Filter key and or value or the incorrect types"); + } else { + // filter key & value is not defined, but filter limit type is valid + // Slice the driveArray to match the max item limit + driveArray = driveArray.slice(0, options.filter.limit); + } + } else { + reject("The options.filter object is missing either the 'key' or 'value' key."); + } + } + } + + /** Final checks and returns */ + + // If driveArray is empty, throw error + if (driveArray.length == 0) { + throw new Error("No drives found"); + } + // If only one drive in array, return the object instead of an array with only one item + if (driveArray.length == 1) { + resolve(driveArray[0]); + } + // If not caught by above checks, return the driveArray + resolve(driveArray); + }); + } +} +class helpers { + static getDriveLetter(index) { + driveLettersArray.forEach(dl => { // If no drive name, set the name to Unnamed Drive + if (dl.Label === null) dl.Label = "Unnamed Disk"; + }); + return driveLettersArray[index]; + } + static getDriveDescription(deviceName) { + try { + const udevadmOutput = execSync(`udevadm info --query=property --name=${deviceName}`).toString(); + const modelMatch = udevadmOutput.match(/ID_MODEL=(.*)/); + if (modelMatch) { + return modelMatch[1]; + } + } catch (error) { + console.error('Error getting drive description:', error); + } + + return 'Unnamed Disk'; + } + static populateArrays() { + // Declare function scoped vars + let drives = []; + switch (os.platform()) { + case "win32": + // Get the drive letters / root paths + device name + driveLettersArray = JSON.parse(execSync('Get-CimInstance Win32_Volume | Where-Object { $_.DriveType -eq 2 -or $_.DriveType -eq 3 } | ForEach-Object { if ($_.DriveLetter) { [PSCustomObject]@{ DriveLetter = $_.DriveLetter; IsReadOnly = [bool]($_.Attributes -band 1); BootVolume = $_.BootVolume; Label = $_.Label } } } | ConvertTo-json', { 'shell': 'powershell.exe' })); + // Get drives, along with some info about them. + drives = JSON.parse(execSync('gwmi win32_diskdrive | select Model, CapabilityDescriptions, Index, PNPDeviceID, MediaType, SerialNumber, Size, Name, InterfaceType, BytesPerSector, Partitions, Status, SectorsPerTrack, TotalCylinders, TotalHeads, TotalSectors, TotalTracks, TracksPerCylinder, CompressionMethod, FirmwareRevision, Manufacturer | ConvertTo-json', { 'shell': 'powershell.exe' })); + // Enumerate the array of drives, and add the keys from getDriveLetter() to the drive objectuyhgvbkhjhj + drives.forEach(drive => { + let dl = helpers.getDriveLetter(drive.Index); + driveArray.push({ + device: drive.Name, + displayName: dl.DriveLetter, + description: drive.Model, + size: drive.Size, + mountpoints: [{ + path: drive.DriveLetter + '/' + }], + raw: drive.Name, + protected: dl.IsReadOnly, + system: dl.BootVolume, + label: dl.Label, + removable: drive.MediaType === 'Removable Media' + }); + }); + break; + case "darwin": + throw new Error("MacOS Support planned later"); + case "linux": + drives = JSON.parse(execSync('lsblk -J -b -s -o NAME,SIZE,RO,TYPE,MOUNTPOINT,LABEL,RM').toString()); + + for (const item of drives.blockdevices) { + if (item.type === 'disk') { + const driveLetter = `/dev/${item.name}`; + const displayName = driveLetter; + const description = helpers.getDriveDescription(item.name); + const isReadOnly = item.ro === '1'; + const isSystem = false; // For Linux, we can't directly identify the boot drive like in Windows. + const removable = item.rm; + let mountpoints = []; + if (item.mountpoint) { + mountpoints.push({ path: item.mountpoint }); + } + + const raw = driveLetter; + const label = item.label ? item.label.trim() : 'Unnamed Disk'; + + const driveObject = { + device: raw, + displayName, + description, + size: item.size, + mountpoints, + raw, + protected: isReadOnly, + system: isSystem, + label, + removable: removable, + }; + + driveArray.push(driveObject); + } + } + break; + default: + throw new Error("Your OS is not supported by disklist"); + } + } +} \ No newline at end of file diff --git "a/src/\360\237\220\237/synchronousOsInfo.js" "b/src/\360\237\220\237/synchronousOsInfo.js" index f16a195..d0abab8 100644 --- "a/src/\360\237\220\237/synchronousOsInfo.js" +++ "b/src/\360\237\220\237/synchronousOsInfo.js" @@ -4,8 +4,6 @@ import process from 'process'; /* Code in this file was blatantly stolen from https://github.com/sebhildebrandt/systeminformation as i needed a quick and dirty synchronous way to get OS information. - -Go sponser them! https://ko-fi.com/sebhildebrandt https://www.buymeacoffee.com/systeminfo diff --git "a/src/\360\237\246\210.js" "b/src/\360\237\246\210.js" index 84ddc5f..43f9a5f 100644 --- "a/src/\360\237\246\210.js" +++ "b/src/\360\237\246\210.js" @@ -1,6 +1,7 @@ import process from 'process'; import cryptography from "./🐟/cryptography.js"; import compression from './🐟/compression.js'; +import disklist from './🐟/disklist.js'; /** * 🦈.js Base class, Includes basic functions, * and imports to other classes stored in ./🐟/ @@ -70,5 +71,7 @@ class Shark { static cryptography = cryptography; // Imports the compression class static compression = compression; + // Imports the disklist class + static disklist = disklist; } export default Shark; \ No newline at end of file