├── .gitignore ├── README.md ├── build.js ├── package-lock.json ├── package.json ├── postinstall-message.js ├── secure-database.db ├── src ├── index.ts └── services │ ├── credentials.ts │ ├── database.ts │ ├── encryption.ts │ └── utils.ts └── tsconfig.json /.gitignore: -------------------------------------------------------------------------------- 1 | # Logs 2 | logs 3 | *.log 4 | npm-debug.log* 5 | yarn-debug.log* 6 | yarn-error.log* 7 | lerna-debug.log* 8 | .pnpm-debug.log* 9 | 10 | # Diagnostic reports (https://nodejs.org/api/report.html) 11 | report.[0-9]*.[0-9]*.[0-9]*.[0-9]*.json 12 | 13 | # Runtime data 14 | pids 15 | *.pid 16 | *.seed 17 | *.pid.lock 18 | 19 | # Directory for instrumented libs generated by jscoverage/JSCover 20 | lib-cov 21 | 22 | # Coverage directory used by tools like istanbul 23 | coverage 24 | *.lcov 25 | 26 | # nyc test coverage 27 | .nyc_output 28 | 29 | # Grunt intermediate storage (https://gruntjs.com/creating-plugins#storing-task-files) 30 | .grunt 31 | 32 | # Bower dependency directory (https://bower.io/) 33 | bower_components 34 | 35 | # node-waf configuration 36 | .lock-wscript 37 | 38 | # Compiled binary addons (https://nodejs.org/api/addons.html) 39 | build/Release 40 | 41 | # Dependency directories 42 | node_modules/ 43 | jspm_packages/ 44 | 45 | # Snowpack dependency directory (https://snowpack.dev/) 46 | web_modules/ 47 | 48 | # TypeScript cache 49 | *.tsbuildinfo 50 | 51 | # Optional npm cache directory 52 | .npm 53 | 54 | # Optional eslint cache 55 | .eslintcache 56 | 57 | # Optional stylelint cache 58 | .stylelintcache 59 | 60 | # Microbundle cache 61 | .rpt2_cache/ 62 | .rts2_cache_cjs/ 63 | .rts2_cache_es/ 64 | .rts2_cache_umd/ 65 | 66 | # Optional REPL history 67 | .node_repl_history 68 | 69 | # Output of 'npm pack' 70 | *.tgz 71 | 72 | # Yarn Integrity file 73 | .yarn-integrity 74 | 75 | # dotenv environment variable files 76 | .env 77 | .env.development.local 78 | .env.test.local 79 | .env.production.local 80 | .env.local 81 | 82 | # parcel-bundler cache (https://parceljs.org/) 83 | .cache 84 | .parcel-cache 85 | 86 | # Next.js build output 87 | .next 88 | out 89 | 90 | # Nuxt.js build / generate output 91 | .nuxt 92 | dist 93 | 94 | # Gatsby files 95 | .cache/ 96 | # Comment in the public line in if your project uses Gatsby and not Next.js 97 | # https://nextjs.org/blog/next-9-1#public-directory-support 98 | # public 99 | 100 | # vuepress build output 101 | .vuepress/dist 102 | 103 | # vuepress v2.x temp and cache directory 104 | .temp 105 | .cache 106 | 107 | # Docusaurus cache and generated files 108 | .docusaurus 109 | 110 | # Serverless directories 111 | .serverless/ 112 | 113 | # FuseBox cache 114 | .fusebox/ 115 | 116 | # DynamoDB Local files 117 | .dynamodb/ 118 | 119 | # TernJS port file 120 | .tern-port 121 | 122 | # Stores VSCode versions used for testing VSCode extensions 123 | .vscode-test 124 | 125 | # yarn v2 126 | .yarn/cache 127 | .yarn/unplugged 128 | .yarn/build-state.yml 129 | .yarn/install-state.gz 130 | .pnp.* 131 | 132 | encryption-key.txt 133 | .db 134 | secure-database.db -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | ``` 2 | ▄▀▒░█░▀█▀░▄▀▀░█ ░▒█░█░▀█▀░▄▀▀░█▄█▒██▀▒█▀▄ 3 | ░▀▄█░█ ▒█▒▒▄██░▀▄▀▄▀░█ ▒█▒░▀▄▄▒█▒█░█▄▄░█▀▄ 4 | ``` 5 | # GitSwitcher - Program that helps you switch between your git-hub, git-lab & bitbucket accounts. 6 | 7 | **** 8 | # GitSwitcher CLI Command Guide 9 | 10 | ## 0. **Installation** 11 | npm install -g gitswitcher 12 | 13 | ## 1. **Create a Table for Storing Accounts** 14 | - **Command:** `create ` 15 | - **Description:** Creates a new table for storing account credentials (e.g., for GitHub or GitLab). 16 | - **Example:** 17 | ```bash 18 | gitswitcher create github 19 | ``` 20 | This command creates a table named `github`. 21 | 22 | ## 2. **Delete a Table** 23 | - **Command:** `delete-table ` 24 | - **Description:** Deletes a table from the database. 25 | - **Example:** 26 | ```bash 27 | gitswitcher delete-table github 28 | ``` 29 | This command deletes the table named `github`. 30 | 31 | ## 3. **Add an Account to a Table** 32 | - **Command:** `add [token]` 33 | - **Description:** Adds a new account to the specified table. An optional `token` parameter can be provided to store a token or password. 34 | - **Example (without token):** 35 | ```bash 36 | gitswitcher add github "YourName" "your@email.com" 37 | ``` 38 | - **Example (with token):** 39 | ```bash 40 | gitswitcher add gitlab "YourName" "your@email.com" "your_personal_access_token_or_password" 41 | ``` 42 | 43 | ## 4. **Delete an Account from a Table** 44 | - **Command:** `delete-account ` 45 | - **Description:** Deletes an account from the specified table using either its ID or name. 46 | - **Example:** 47 | ```bash 48 | gitswitcher delete-account github 1 49 | ``` 50 | This command deletes the account with ID `1` from the `github` table. 51 | 52 | ## 5. **Show All Accounts in a Table** 53 | - **Command:** `show ` 54 | - **Description:** Displays a list of all accounts in the specified table. 55 | - **Example:** 56 | ```bash 57 | gitswitcher show github 58 | ``` 59 | This command displays all accounts stored in the `github` table. 60 | 61 | **Output Example:** 62 | ```bash 63 | Accounts in folder 'github': 64 | 1: DenisYasyuchenya 65 | 2: AnotherUser 66 | 3: ExampleUser 67 | ``` 68 | 69 | ## 6. **Show All Tables (Folders) in the Database** 70 | - **Command:** `show-folders` 71 | - **Description:** Lists all tables in the database, excluding system tables. 72 | - **Example:** 73 | ```bash 74 | gitswitcher show-folders 75 | ``` 76 | This command displays all tables (e.g., `github`, `gitlab`). 77 | 78 | **Output Example:** 79 | ```bash 80 | Your folders: 81 | github 82 | gitlab 83 | ``` 84 | 85 | ## 7. **Switch to an Account** 86 | - **Command:** `use ` 87 | - **Description:** Switches the current Git configuration to the specified account by its ID. 88 | - **Example:** 89 | ```bash 90 | gitswitcher use github 1 91 | ``` 92 | This command switches the current Git configuration to the account with ID `1` in the `github` table. 93 | -------------------------------------------------------------------------------- /build.js: -------------------------------------------------------------------------------- 1 | const crypto = require('crypto'); 2 | const fs = require('fs'); 3 | const Database = require('better-sqlite3'); 4 | 5 | const encryptionKey = crypto.randomBytes(32).toString('hex'); 6 | 7 | fs.writeFileSync('encryption-key.txt', encryptionKey); 8 | 9 | const db = new Database('secure-database.db'); 10 | db.exec(`PRAGMA key = '${encryptionKey}';`); 11 | 12 | db.exec(` 13 | CREATE TABLE IF NOT EXISTS accounts ( 14 | id INTEGER PRIMARY KEY AUTOINCREMENT, 15 | name TEXT NOT NULL, 16 | email TEXT NOT NULL 17 | ); 18 | `); 19 | 20 | console.log('Database initialized with encryption.'); 21 | -------------------------------------------------------------------------------- /package-lock.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "gitswitcher", 3 | "version": "2.0.0", 4 | "lockfileVersion": 3, 5 | "requires": true, 6 | "packages": { 7 | "": { 8 | "name": "gitswitcher", 9 | "version": "2.0.0", 10 | "hasInstallScript": true, 11 | "license": "ISC", 12 | "dependencies": { 13 | "@types/better-sqlite3": "^7.6.11", 14 | "@types/node": "^22.4.1", 15 | "@types/readline-sync": "^1.4.8", 16 | "@types/validator": "^13.12.0", 17 | "better-sqlite3": "^11.1.2", 18 | "readline-sync": "^1.4.10", 19 | "typescript": "^5.5.4", 20 | "validator": "^13.12.0" 21 | }, 22 | "bin": { 23 | "gitswitcher": "dist/index.js" 24 | }, 25 | "devDependencies": { 26 | "ts-node": "^10.9.2" 27 | } 28 | }, 29 | "node_modules/@cspotcode/source-map-support": { 30 | "version": "0.8.1", 31 | "resolved": "https://registry.npmjs.org/@cspotcode/source-map-support/-/source-map-support-0.8.1.tgz", 32 | "integrity": "sha512-IchNf6dN4tHoMFIn/7OE8LWZ19Y6q/67Bmf6vnGREv8RSbBVb9LPJxEcnwrcwX6ixSvaiGoomAUvu4YSxXrVgw==", 33 | "dev": true, 34 | "license": "MIT", 35 | "dependencies": { 36 | "@jridgewell/trace-mapping": "0.3.9" 37 | }, 38 | "engines": { 39 | "node": ">=12" 40 | } 41 | }, 42 | "node_modules/@jridgewell/resolve-uri": { 43 | "version": "3.1.2", 44 | "resolved": "https://registry.npmjs.org/@jridgewell/resolve-uri/-/resolve-uri-3.1.2.tgz", 45 | "integrity": "sha512-bRISgCIjP20/tbWSPWMEi54QVPRZExkuD9lJL+UIxUKtwVJA8wW1Trb1jMs1RFXo1CBTNZ/5hpC9QvmKWdopKw==", 46 | "dev": true, 47 | "license": "MIT", 48 | "engines": { 49 | "node": ">=6.0.0" 50 | } 51 | }, 52 | "node_modules/@jridgewell/sourcemap-codec": { 53 | "version": "1.5.0", 54 | "resolved": "https://registry.npmjs.org/@jridgewell/sourcemap-codec/-/sourcemap-codec-1.5.0.tgz", 55 | "integrity": "sha512-gv3ZRaISU3fjPAgNsriBRqGWQL6quFx04YMPW/zD8XMLsU32mhCCbfbO6KZFLjvYpCZ8zyDEgqsgf+PwPaM7GQ==", 56 | "dev": true, 57 | "license": "MIT" 58 | }, 59 | "node_modules/@jridgewell/trace-mapping": { 60 | "version": "0.3.9", 61 | "resolved": "https://registry.npmjs.org/@jridgewell/trace-mapping/-/trace-mapping-0.3.9.tgz", 62 | "integrity": "sha512-3Belt6tdc8bPgAtbcmdtNJlirVoTmEb5e2gC94PnkwEW9jI6CAHUeoG85tjWP5WquqfavoMtMwiG4P926ZKKuQ==", 63 | "dev": true, 64 | "license": "MIT", 65 | "dependencies": { 66 | "@jridgewell/resolve-uri": "^3.0.3", 67 | "@jridgewell/sourcemap-codec": "^1.4.10" 68 | } 69 | }, 70 | "node_modules/@tsconfig/node10": { 71 | "version": "1.0.11", 72 | "resolved": "https://registry.npmjs.org/@tsconfig/node10/-/node10-1.0.11.tgz", 73 | "integrity": "sha512-DcRjDCujK/kCk/cUe8Xz8ZSpm8mS3mNNpta+jGCA6USEDfktlNvm1+IuZ9eTcDbNk41BHwpHHeW+N1lKCz4zOw==", 74 | "dev": true, 75 | "license": "MIT" 76 | }, 77 | "node_modules/@tsconfig/node12": { 78 | "version": "1.0.11", 79 | "resolved": "https://registry.npmjs.org/@tsconfig/node12/-/node12-1.0.11.tgz", 80 | "integrity": "sha512-cqefuRsh12pWyGsIoBKJA9luFu3mRxCA+ORZvA4ktLSzIuCUtWVxGIuXigEwO5/ywWFMZ2QEGKWvkZG1zDMTag==", 81 | "dev": true, 82 | "license": "MIT" 83 | }, 84 | "node_modules/@tsconfig/node14": { 85 | "version": "1.0.3", 86 | "resolved": "https://registry.npmjs.org/@tsconfig/node14/-/node14-1.0.3.tgz", 87 | "integrity": "sha512-ysT8mhdixWK6Hw3i1V2AeRqZ5WfXg1G43mqoYlM2nc6388Fq5jcXyr5mRsqViLx/GJYdoL0bfXD8nmF+Zn/Iow==", 88 | "dev": true, 89 | "license": "MIT" 90 | }, 91 | "node_modules/@tsconfig/node16": { 92 | "version": "1.0.4", 93 | "resolved": "https://registry.npmjs.org/@tsconfig/node16/-/node16-1.0.4.tgz", 94 | "integrity": "sha512-vxhUy4J8lyeyinH7Azl1pdd43GJhZH/tP2weN8TntQblOY+A0XbT8DJk1/oCPuOOyg/Ja757rG0CgHcWC8OfMA==", 95 | "dev": true, 96 | "license": "MIT" 97 | }, 98 | "node_modules/@types/better-sqlite3": { 99 | "version": "7.6.11", 100 | "resolved": "https://registry.npmjs.org/@types/better-sqlite3/-/better-sqlite3-7.6.11.tgz", 101 | "integrity": "sha512-i8KcD3PgGtGBLl3+mMYA8PdKkButvPyARxA7IQAd6qeslht13qxb1zzO8dRCtE7U3IoJS782zDBAeoKiM695kg==", 102 | "license": "MIT", 103 | "dependencies": { 104 | "@types/node": "*" 105 | } 106 | }, 107 | "node_modules/@types/node": { 108 | "version": "22.4.1", 109 | "resolved": "https://registry.npmjs.org/@types/node/-/node-22.4.1.tgz", 110 | "integrity": "sha512-1tbpb9325+gPnKK0dMm+/LMriX0vKxf6RnB0SZUqfyVkQ4fMgUSySqhxE/y8Jvs4NyF1yHzTfG9KlnkIODxPKg==", 111 | "license": "MIT", 112 | "dependencies": { 113 | "undici-types": "~6.19.2" 114 | } 115 | }, 116 | "node_modules/@types/readline-sync": { 117 | "version": "1.4.8", 118 | "resolved": "https://registry.npmjs.org/@types/readline-sync/-/readline-sync-1.4.8.tgz", 119 | "integrity": "sha512-BL7xOf0yKLA6baAX6MMOnYkoflUyj/c7y3pqMRfU0va7XlwHAOTOIo4x55P/qLfMsuaYdJJKubToLqRVmRtRZA==", 120 | "license": "MIT" 121 | }, 122 | "node_modules/@types/validator": { 123 | "version": "13.12.0", 124 | "resolved": "https://registry.npmjs.org/@types/validator/-/validator-13.12.0.tgz", 125 | "integrity": "sha512-nH45Lk7oPIJ1RVOF6JgFI6Dy0QpHEzq4QecZhvguxYPDwT8c93prCMqAtiIttm39voZ+DDR+qkNnMpJmMBRqag==", 126 | "license": "MIT" 127 | }, 128 | "node_modules/acorn": { 129 | "version": "8.12.1", 130 | "resolved": "https://registry.npmjs.org/acorn/-/acorn-8.12.1.tgz", 131 | "integrity": "sha512-tcpGyI9zbizT9JbV6oYE477V6mTlXvvi0T0G3SNIYE2apm/G5huBa1+K89VGeovbg+jycCrfhl3ADxErOuO6Jg==", 132 | "dev": true, 133 | "license": "MIT", 134 | "bin": { 135 | "acorn": "bin/acorn" 136 | }, 137 | "engines": { 138 | "node": ">=0.4.0" 139 | } 140 | }, 141 | "node_modules/acorn-walk": { 142 | "version": "8.3.3", 143 | "resolved": "https://registry.npmjs.org/acorn-walk/-/acorn-walk-8.3.3.tgz", 144 | "integrity": "sha512-MxXdReSRhGO7VlFe1bRG/oI7/mdLV9B9JJT0N8vZOhF7gFRR5l3M8W9G8JxmKV+JC5mGqJ0QvqfSOLsCPa4nUw==", 145 | "dev": true, 146 | "license": "MIT", 147 | "dependencies": { 148 | "acorn": "^8.11.0" 149 | }, 150 | "engines": { 151 | "node": ">=0.4.0" 152 | } 153 | }, 154 | "node_modules/arg": { 155 | "version": "4.1.3", 156 | "resolved": "https://registry.npmjs.org/arg/-/arg-4.1.3.tgz", 157 | "integrity": "sha512-58S9QDqG0Xx27YwPSt9fJxivjYl432YCwfDMfZ+71RAqUrZef7LrKQZ3LHLOwCS4FLNBplP533Zx895SeOCHvA==", 158 | "dev": true, 159 | "license": "MIT" 160 | }, 161 | "node_modules/base64-js": { 162 | "version": "1.5.1", 163 | "resolved": "https://registry.npmjs.org/base64-js/-/base64-js-1.5.1.tgz", 164 | "integrity": "sha512-AKpaYlHn8t4SVbOHCy+b5+KKgvR4vrsD8vbvrbiQJps7fKDTkjkDry6ji0rUJjC0kzbNePLwzxq8iypo41qeWA==", 165 | "funding": [ 166 | { 167 | "type": "github", 168 | "url": "https://github.com/sponsors/feross" 169 | }, 170 | { 171 | "type": "patreon", 172 | "url": "https://www.patreon.com/feross" 173 | }, 174 | { 175 | "type": "consulting", 176 | "url": "https://feross.org/support" 177 | } 178 | ], 179 | "license": "MIT" 180 | }, 181 | "node_modules/better-sqlite3": { 182 | "version": "11.1.2", 183 | "resolved": "https://registry.npmjs.org/better-sqlite3/-/better-sqlite3-11.1.2.tgz", 184 | "integrity": "sha512-gujtFwavWU4MSPT+h9B+4pkvZdyOUkH54zgLdIrMmmmd4ZqiBIrRNBzNzYVFO417xo882uP5HBu4GjOfaSrIQw==", 185 | "hasInstallScript": true, 186 | "license": "MIT", 187 | "dependencies": { 188 | "bindings": "^1.5.0", 189 | "prebuild-install": "^7.1.1" 190 | } 191 | }, 192 | "node_modules/bindings": { 193 | "version": "1.5.0", 194 | "resolved": "https://registry.npmjs.org/bindings/-/bindings-1.5.0.tgz", 195 | "integrity": "sha512-p2q/t/mhvuOj/UeLlV6566GD/guowlr0hHxClI0W9m7MWYkL1F0hLo+0Aexs9HSPCtR1SXQ0TD3MMKrXZajbiQ==", 196 | "license": "MIT", 197 | "dependencies": { 198 | "file-uri-to-path": "1.0.0" 199 | } 200 | }, 201 | "node_modules/bl": { 202 | "version": "4.1.0", 203 | "resolved": "https://registry.npmjs.org/bl/-/bl-4.1.0.tgz", 204 | "integrity": "sha512-1W07cM9gS6DcLperZfFSj+bWLtaPGSOHWhPiGzXmvVJbRLdG82sH/Kn8EtW1VqWVA54AKf2h5k5BbnIbwF3h6w==", 205 | "license": "MIT", 206 | "dependencies": { 207 | "buffer": "^5.5.0", 208 | "inherits": "^2.0.4", 209 | "readable-stream": "^3.4.0" 210 | } 211 | }, 212 | "node_modules/buffer": { 213 | "version": "5.7.1", 214 | "resolved": "https://registry.npmjs.org/buffer/-/buffer-5.7.1.tgz", 215 | "integrity": "sha512-EHcyIPBQ4BSGlvjB16k5KgAJ27CIsHY/2JBmCRReo48y9rQ3MaUzWX3KVlBa4U7MyX02HdVj0K7C3WaB3ju7FQ==", 216 | "funding": [ 217 | { 218 | "type": "github", 219 | "url": "https://github.com/sponsors/feross" 220 | }, 221 | { 222 | "type": "patreon", 223 | "url": "https://www.patreon.com/feross" 224 | }, 225 | { 226 | "type": "consulting", 227 | "url": "https://feross.org/support" 228 | } 229 | ], 230 | "license": "MIT", 231 | "dependencies": { 232 | "base64-js": "^1.3.1", 233 | "ieee754": "^1.1.13" 234 | } 235 | }, 236 | "node_modules/chownr": { 237 | "version": "1.1.4", 238 | "resolved": "https://registry.npmjs.org/chownr/-/chownr-1.1.4.tgz", 239 | "integrity": "sha512-jJ0bqzaylmJtVnNgzTeSOs8DPavpbYgEr/b0YL8/2GO3xJEhInFmhKMUnEJQjZumK7KXGFhUy89PrsJWlakBVg==", 240 | "license": "ISC" 241 | }, 242 | "node_modules/create-require": { 243 | "version": "1.1.1", 244 | "resolved": "https://registry.npmjs.org/create-require/-/create-require-1.1.1.tgz", 245 | "integrity": "sha512-dcKFX3jn0MpIaXjisoRvexIJVEKzaq7z2rZKxf+MSr9TkdmHmsU4m2lcLojrj/FHl8mk5VxMmYA+ftRkP/3oKQ==", 246 | "dev": true, 247 | "license": "MIT" 248 | }, 249 | "node_modules/decompress-response": { 250 | "version": "6.0.0", 251 | "resolved": "https://registry.npmjs.org/decompress-response/-/decompress-response-6.0.0.tgz", 252 | "integrity": "sha512-aW35yZM6Bb/4oJlZncMH2LCoZtJXTRxES17vE3hoRiowU2kWHaJKFkSBDnDR+cm9J+9QhXmREyIfv0pji9ejCQ==", 253 | "license": "MIT", 254 | "dependencies": { 255 | "mimic-response": "^3.1.0" 256 | }, 257 | "engines": { 258 | "node": ">=10" 259 | }, 260 | "funding": { 261 | "url": "https://github.com/sponsors/sindresorhus" 262 | } 263 | }, 264 | "node_modules/deep-extend": { 265 | "version": "0.6.0", 266 | "resolved": "https://registry.npmjs.org/deep-extend/-/deep-extend-0.6.0.tgz", 267 | "integrity": "sha512-LOHxIOaPYdHlJRtCQfDIVZtfw/ufM8+rVj649RIHzcm/vGwQRXFt6OPqIFWsm2XEMrNIEtWR64sY1LEKD2vAOA==", 268 | "license": "MIT", 269 | "engines": { 270 | "node": ">=4.0.0" 271 | } 272 | }, 273 | "node_modules/detect-libc": { 274 | "version": "2.0.3", 275 | "resolved": "https://registry.npmjs.org/detect-libc/-/detect-libc-2.0.3.tgz", 276 | "integrity": "sha512-bwy0MGW55bG41VqxxypOsdSdGqLwXPI/focwgTYCFMbdUiBAxLg9CFzG08sz2aqzknwiX7Hkl0bQENjg8iLByw==", 277 | "license": "Apache-2.0", 278 | "engines": { 279 | "node": ">=8" 280 | } 281 | }, 282 | "node_modules/diff": { 283 | "version": "4.0.2", 284 | "resolved": "https://registry.npmjs.org/diff/-/diff-4.0.2.tgz", 285 | "integrity": "sha512-58lmxKSA4BNyLz+HHMUzlOEpg09FV+ev6ZMe3vJihgdxzgcwZ8VoEEPmALCZG9LmqfVoNMMKpttIYTVG6uDY7A==", 286 | "dev": true, 287 | "license": "BSD-3-Clause", 288 | "engines": { 289 | "node": ">=0.3.1" 290 | } 291 | }, 292 | "node_modules/end-of-stream": { 293 | "version": "1.4.4", 294 | "resolved": "https://registry.npmjs.org/end-of-stream/-/end-of-stream-1.4.4.tgz", 295 | "integrity": "sha512-+uw1inIHVPQoaVuHzRyXd21icM+cnt4CzD5rW+NC1wjOUSTOs+Te7FOv7AhN7vS9x/oIyhLP5PR1H+phQAHu5Q==", 296 | "license": "MIT", 297 | "dependencies": { 298 | "once": "^1.4.0" 299 | } 300 | }, 301 | "node_modules/expand-template": { 302 | "version": "2.0.3", 303 | "resolved": "https://registry.npmjs.org/expand-template/-/expand-template-2.0.3.tgz", 304 | "integrity": "sha512-XYfuKMvj4O35f/pOXLObndIRvyQ+/+6AhODh+OKWj9S9498pHHn/IMszH+gt0fBCRWMNfk1ZSp5x3AifmnI2vg==", 305 | "license": "(MIT OR WTFPL)", 306 | "engines": { 307 | "node": ">=6" 308 | } 309 | }, 310 | "node_modules/file-uri-to-path": { 311 | "version": "1.0.0", 312 | "resolved": "https://registry.npmjs.org/file-uri-to-path/-/file-uri-to-path-1.0.0.tgz", 313 | "integrity": "sha512-0Zt+s3L7Vf1biwWZ29aARiVYLx7iMGnEUl9x33fbB/j3jR81u/O2LbqK+Bm1CDSNDKVtJ/YjwY7TUd5SkeLQLw==", 314 | "license": "MIT" 315 | }, 316 | "node_modules/fs-constants": { 317 | "version": "1.0.0", 318 | "resolved": "https://registry.npmjs.org/fs-constants/-/fs-constants-1.0.0.tgz", 319 | "integrity": "sha512-y6OAwoSIf7FyjMIv94u+b5rdheZEjzR63GTyZJm5qh4Bi+2YgwLCcI/fPFZkL5PSixOt6ZNKm+w+Hfp/Bciwow==", 320 | "license": "MIT" 321 | }, 322 | "node_modules/github-from-package": { 323 | "version": "0.0.0", 324 | "resolved": "https://registry.npmjs.org/github-from-package/-/github-from-package-0.0.0.tgz", 325 | "integrity": "sha512-SyHy3T1v2NUXn29OsWdxmK6RwHD+vkj3v8en8AOBZ1wBQ/hCAQ5bAQTD02kW4W9tUp/3Qh6J8r9EvntiyCmOOw==", 326 | "license": "MIT" 327 | }, 328 | "node_modules/ieee754": { 329 | "version": "1.2.1", 330 | "resolved": "https://registry.npmjs.org/ieee754/-/ieee754-1.2.1.tgz", 331 | "integrity": "sha512-dcyqhDvX1C46lXZcVqCpK+FtMRQVdIMN6/Df5js2zouUsqG7I6sFxitIC+7KYK29KdXOLHdu9zL4sFnoVQnqaA==", 332 | "funding": [ 333 | { 334 | "type": "github", 335 | "url": "https://github.com/sponsors/feross" 336 | }, 337 | { 338 | "type": "patreon", 339 | "url": "https://www.patreon.com/feross" 340 | }, 341 | { 342 | "type": "consulting", 343 | "url": "https://feross.org/support" 344 | } 345 | ], 346 | "license": "BSD-3-Clause" 347 | }, 348 | "node_modules/inherits": { 349 | "version": "2.0.4", 350 | "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.4.tgz", 351 | "integrity": "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==", 352 | "license": "ISC" 353 | }, 354 | "node_modules/ini": { 355 | "version": "1.3.8", 356 | "resolved": "https://registry.npmjs.org/ini/-/ini-1.3.8.tgz", 357 | "integrity": "sha512-JV/yugV2uzW5iMRSiZAyDtQd+nxtUnjeLt0acNdw98kKLrvuRVyB80tsREOE7yvGVgalhZ6RNXCmEHkUKBKxew==", 358 | "license": "ISC" 359 | }, 360 | "node_modules/make-error": { 361 | "version": "1.3.6", 362 | "resolved": "https://registry.npmjs.org/make-error/-/make-error-1.3.6.tgz", 363 | "integrity": "sha512-s8UhlNe7vPKomQhC1qFelMokr/Sc3AgNbso3n74mVPA5LTZwkB9NlXf4XPamLxJE8h0gh73rM94xvwRT2CVInw==", 364 | "dev": true, 365 | "license": "ISC" 366 | }, 367 | "node_modules/mimic-response": { 368 | "version": "3.1.0", 369 | "resolved": "https://registry.npmjs.org/mimic-response/-/mimic-response-3.1.0.tgz", 370 | "integrity": "sha512-z0yWI+4FDrrweS8Zmt4Ej5HdJmky15+L2e6Wgn3+iK5fWzb6T3fhNFq2+MeTRb064c6Wr4N/wv0DzQTjNzHNGQ==", 371 | "license": "MIT", 372 | "engines": { 373 | "node": ">=10" 374 | }, 375 | "funding": { 376 | "url": "https://github.com/sponsors/sindresorhus" 377 | } 378 | }, 379 | "node_modules/minimist": { 380 | "version": "1.2.8", 381 | "resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.8.tgz", 382 | "integrity": "sha512-2yyAR8qBkN3YuheJanUpWC5U3bb5osDywNB8RzDVlDwDHbocAJveqqj1u8+SVD7jkWT4yvsHCpWqqWqAxb0zCA==", 383 | "license": "MIT", 384 | "funding": { 385 | "url": "https://github.com/sponsors/ljharb" 386 | } 387 | }, 388 | "node_modules/mkdirp-classic": { 389 | "version": "0.5.3", 390 | "resolved": "https://registry.npmjs.org/mkdirp-classic/-/mkdirp-classic-0.5.3.tgz", 391 | "integrity": "sha512-gKLcREMhtuZRwRAfqP3RFW+TK4JqApVBtOIftVgjuABpAtpxhPGaDcfvbhNvD0B8iD1oUr/txX35NjcaY6Ns/A==", 392 | "license": "MIT" 393 | }, 394 | "node_modules/napi-build-utils": { 395 | "version": "1.0.2", 396 | "resolved": "https://registry.npmjs.org/napi-build-utils/-/napi-build-utils-1.0.2.tgz", 397 | "integrity": "sha512-ONmRUqK7zj7DWX0D9ADe03wbwOBZxNAfF20PlGfCWQcD3+/MakShIHrMqx9YwPTfxDdF1zLeL+RGZiR9kGMLdg==", 398 | "license": "MIT" 399 | }, 400 | "node_modules/node-abi": { 401 | "version": "3.65.0", 402 | "resolved": "https://registry.npmjs.org/node-abi/-/node-abi-3.65.0.tgz", 403 | "integrity": "sha512-ThjYBfoDNr08AWx6hGaRbfPwxKV9kVzAzOzlLKbk2CuqXE2xnCh+cbAGnwM3t8Lq4v9rUB7VfondlkBckcJrVA==", 404 | "license": "MIT", 405 | "dependencies": { 406 | "semver": "^7.3.5" 407 | }, 408 | "engines": { 409 | "node": ">=10" 410 | } 411 | }, 412 | "node_modules/once": { 413 | "version": "1.4.0", 414 | "resolved": "https://registry.npmjs.org/once/-/once-1.4.0.tgz", 415 | "integrity": "sha512-lNaJgI+2Q5URQBkccEKHTQOPaXdUxnZZElQTZY0MFUAuaEqe1E+Nyvgdz/aIyNi6Z9MzO5dv1H8n58/GELp3+w==", 416 | "license": "ISC", 417 | "dependencies": { 418 | "wrappy": "1" 419 | } 420 | }, 421 | "node_modules/prebuild-install": { 422 | "version": "7.1.2", 423 | "resolved": "https://registry.npmjs.org/prebuild-install/-/prebuild-install-7.1.2.tgz", 424 | "integrity": "sha512-UnNke3IQb6sgarcZIDU3gbMeTp/9SSU1DAIkil7PrqG1vZlBtY5msYccSKSHDqa3hNg436IXK+SNImReuA1wEQ==", 425 | "license": "MIT", 426 | "dependencies": { 427 | "detect-libc": "^2.0.0", 428 | "expand-template": "^2.0.3", 429 | "github-from-package": "0.0.0", 430 | "minimist": "^1.2.3", 431 | "mkdirp-classic": "^0.5.3", 432 | "napi-build-utils": "^1.0.1", 433 | "node-abi": "^3.3.0", 434 | "pump": "^3.0.0", 435 | "rc": "^1.2.7", 436 | "simple-get": "^4.0.0", 437 | "tar-fs": "^2.0.0", 438 | "tunnel-agent": "^0.6.0" 439 | }, 440 | "bin": { 441 | "prebuild-install": "bin.js" 442 | }, 443 | "engines": { 444 | "node": ">=10" 445 | } 446 | }, 447 | "node_modules/pump": { 448 | "version": "3.0.0", 449 | "resolved": "https://registry.npmjs.org/pump/-/pump-3.0.0.tgz", 450 | "integrity": "sha512-LwZy+p3SFs1Pytd/jYct4wpv49HiYCqd9Rlc5ZVdk0V+8Yzv6jR5Blk3TRmPL1ft69TxP0IMZGJ+WPFU2BFhww==", 451 | "license": "MIT", 452 | "dependencies": { 453 | "end-of-stream": "^1.1.0", 454 | "once": "^1.3.1" 455 | } 456 | }, 457 | "node_modules/rc": { 458 | "version": "1.2.8", 459 | "resolved": "https://registry.npmjs.org/rc/-/rc-1.2.8.tgz", 460 | "integrity": "sha512-y3bGgqKj3QBdxLbLkomlohkvsA8gdAiUQlSBJnBhfn+BPxg4bc62d8TcBW15wavDfgexCgccckhcZvywyQYPOw==", 461 | "license": "(BSD-2-Clause OR MIT OR Apache-2.0)", 462 | "dependencies": { 463 | "deep-extend": "^0.6.0", 464 | "ini": "~1.3.0", 465 | "minimist": "^1.2.0", 466 | "strip-json-comments": "~2.0.1" 467 | }, 468 | "bin": { 469 | "rc": "cli.js" 470 | } 471 | }, 472 | "node_modules/readable-stream": { 473 | "version": "3.6.2", 474 | "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-3.6.2.tgz", 475 | "integrity": "sha512-9u/sniCrY3D5WdsERHzHE4G2YCXqoG5FTHUiCC4SIbr6XcLZBY05ya9EKjYek9O5xOAwjGq+1JdGBAS7Q9ScoA==", 476 | "license": "MIT", 477 | "dependencies": { 478 | "inherits": "^2.0.3", 479 | "string_decoder": "^1.1.1", 480 | "util-deprecate": "^1.0.1" 481 | }, 482 | "engines": { 483 | "node": ">= 6" 484 | } 485 | }, 486 | "node_modules/readline-sync": { 487 | "version": "1.4.10", 488 | "resolved": "https://registry.npmjs.org/readline-sync/-/readline-sync-1.4.10.tgz", 489 | "integrity": "sha512-gNva8/6UAe8QYepIQH/jQ2qn91Qj0B9sYjMBBs3QOB8F2CXcKgLxQaJRP76sWVRQt+QU+8fAkCbCvjjMFu7Ycw==", 490 | "license": "MIT", 491 | "engines": { 492 | "node": ">= 0.8.0" 493 | } 494 | }, 495 | "node_modules/safe-buffer": { 496 | "version": "5.2.1", 497 | "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.2.1.tgz", 498 | "integrity": "sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ==", 499 | "funding": [ 500 | { 501 | "type": "github", 502 | "url": "https://github.com/sponsors/feross" 503 | }, 504 | { 505 | "type": "patreon", 506 | "url": "https://www.patreon.com/feross" 507 | }, 508 | { 509 | "type": "consulting", 510 | "url": "https://feross.org/support" 511 | } 512 | ], 513 | "license": "MIT" 514 | }, 515 | "node_modules/semver": { 516 | "version": "7.6.3", 517 | "resolved": "https://registry.npmjs.org/semver/-/semver-7.6.3.tgz", 518 | "integrity": "sha512-oVekP1cKtI+CTDvHWYFUcMtsK/00wmAEfyqKfNdARm8u1wNVhSgaX7A8d4UuIlUI5e84iEwOhs7ZPYRmzU9U6A==", 519 | "license": "ISC", 520 | "bin": { 521 | "semver": "bin/semver.js" 522 | }, 523 | "engines": { 524 | "node": ">=10" 525 | } 526 | }, 527 | "node_modules/simple-concat": { 528 | "version": "1.0.1", 529 | "resolved": "https://registry.npmjs.org/simple-concat/-/simple-concat-1.0.1.tgz", 530 | "integrity": "sha512-cSFtAPtRhljv69IK0hTVZQ+OfE9nePi/rtJmw5UjHeVyVroEqJXP1sFztKUy1qU+xvz3u/sfYJLa947b7nAN2Q==", 531 | "funding": [ 532 | { 533 | "type": "github", 534 | "url": "https://github.com/sponsors/feross" 535 | }, 536 | { 537 | "type": "patreon", 538 | "url": "https://www.patreon.com/feross" 539 | }, 540 | { 541 | "type": "consulting", 542 | "url": "https://feross.org/support" 543 | } 544 | ], 545 | "license": "MIT" 546 | }, 547 | "node_modules/simple-get": { 548 | "version": "4.0.1", 549 | "resolved": "https://registry.npmjs.org/simple-get/-/simple-get-4.0.1.tgz", 550 | "integrity": "sha512-brv7p5WgH0jmQJr1ZDDfKDOSeWWg+OVypG99A/5vYGPqJ6pxiaHLy8nxtFjBA7oMa01ebA9gfh1uMCFqOuXxvA==", 551 | "funding": [ 552 | { 553 | "type": "github", 554 | "url": "https://github.com/sponsors/feross" 555 | }, 556 | { 557 | "type": "patreon", 558 | "url": "https://www.patreon.com/feross" 559 | }, 560 | { 561 | "type": "consulting", 562 | "url": "https://feross.org/support" 563 | } 564 | ], 565 | "license": "MIT", 566 | "dependencies": { 567 | "decompress-response": "^6.0.0", 568 | "once": "^1.3.1", 569 | "simple-concat": "^1.0.0" 570 | } 571 | }, 572 | "node_modules/string_decoder": { 573 | "version": "1.3.0", 574 | "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.3.0.tgz", 575 | "integrity": "sha512-hkRX8U1WjJFd8LsDJ2yQ/wWWxaopEsABU1XfkM8A+j0+85JAGppt16cr1Whg6KIbb4okU6Mql6BOj+uup/wKeA==", 576 | "license": "MIT", 577 | "dependencies": { 578 | "safe-buffer": "~5.2.0" 579 | } 580 | }, 581 | "node_modules/strip-json-comments": { 582 | "version": "2.0.1", 583 | "resolved": "https://registry.npmjs.org/strip-json-comments/-/strip-json-comments-2.0.1.tgz", 584 | "integrity": "sha512-4gB8na07fecVVkOI6Rs4e7T6NOTki5EmL7TUduTs6bu3EdnSycntVJ4re8kgZA+wx9IueI2Y11bfbgwtzuE0KQ==", 585 | "license": "MIT", 586 | "engines": { 587 | "node": ">=0.10.0" 588 | } 589 | }, 590 | "node_modules/tar-fs": { 591 | "version": "2.1.1", 592 | "resolved": "https://registry.npmjs.org/tar-fs/-/tar-fs-2.1.1.tgz", 593 | "integrity": "sha512-V0r2Y9scmbDRLCNex/+hYzvp/zyYjvFbHPNgVTKfQvVrb6guiE/fxP+XblDNR011utopbkex2nM4dHNV6GDsng==", 594 | "license": "MIT", 595 | "dependencies": { 596 | "chownr": "^1.1.1", 597 | "mkdirp-classic": "^0.5.2", 598 | "pump": "^3.0.0", 599 | "tar-stream": "^2.1.4" 600 | } 601 | }, 602 | "node_modules/tar-stream": { 603 | "version": "2.2.0", 604 | "resolved": "https://registry.npmjs.org/tar-stream/-/tar-stream-2.2.0.tgz", 605 | "integrity": "sha512-ujeqbceABgwMZxEJnk2HDY2DlnUZ+9oEcb1KzTVfYHio0UE6dG71n60d8D2I4qNvleWrrXpmjpt7vZeF1LnMZQ==", 606 | "license": "MIT", 607 | "dependencies": { 608 | "bl": "^4.0.3", 609 | "end-of-stream": "^1.4.1", 610 | "fs-constants": "^1.0.0", 611 | "inherits": "^2.0.3", 612 | "readable-stream": "^3.1.1" 613 | }, 614 | "engines": { 615 | "node": ">=6" 616 | } 617 | }, 618 | "node_modules/ts-node": { 619 | "version": "10.9.2", 620 | "resolved": "https://registry.npmjs.org/ts-node/-/ts-node-10.9.2.tgz", 621 | "integrity": "sha512-f0FFpIdcHgn8zcPSbf1dRevwt047YMnaiJM3u2w2RewrB+fob/zePZcrOyQoLMMO7aBIddLcQIEK5dYjkLnGrQ==", 622 | "dev": true, 623 | "license": "MIT", 624 | "dependencies": { 625 | "@cspotcode/source-map-support": "^0.8.0", 626 | "@tsconfig/node10": "^1.0.7", 627 | "@tsconfig/node12": "^1.0.7", 628 | "@tsconfig/node14": "^1.0.0", 629 | "@tsconfig/node16": "^1.0.2", 630 | "acorn": "^8.4.1", 631 | "acorn-walk": "^8.1.1", 632 | "arg": "^4.1.0", 633 | "create-require": "^1.1.0", 634 | "diff": "^4.0.1", 635 | "make-error": "^1.1.1", 636 | "v8-compile-cache-lib": "^3.0.1", 637 | "yn": "3.1.1" 638 | }, 639 | "bin": { 640 | "ts-node": "dist/bin.js", 641 | "ts-node-cwd": "dist/bin-cwd.js", 642 | "ts-node-esm": "dist/bin-esm.js", 643 | "ts-node-script": "dist/bin-script.js", 644 | "ts-node-transpile-only": "dist/bin-transpile.js", 645 | "ts-script": "dist/bin-script-deprecated.js" 646 | }, 647 | "peerDependencies": { 648 | "@swc/core": ">=1.2.50", 649 | "@swc/wasm": ">=1.2.50", 650 | "@types/node": "*", 651 | "typescript": ">=2.7" 652 | }, 653 | "peerDependenciesMeta": { 654 | "@swc/core": { 655 | "optional": true 656 | }, 657 | "@swc/wasm": { 658 | "optional": true 659 | } 660 | } 661 | }, 662 | "node_modules/tunnel-agent": { 663 | "version": "0.6.0", 664 | "resolved": "https://registry.npmjs.org/tunnel-agent/-/tunnel-agent-0.6.0.tgz", 665 | "integrity": "sha512-McnNiV1l8RYeY8tBgEpuodCC1mLUdbSN+CYBL7kJsJNInOP8UjDDEwdk6Mw60vdLLrr5NHKZhMAOSrR2NZuQ+w==", 666 | "license": "Apache-2.0", 667 | "dependencies": { 668 | "safe-buffer": "^5.0.1" 669 | }, 670 | "engines": { 671 | "node": "*" 672 | } 673 | }, 674 | "node_modules/typescript": { 675 | "version": "5.5.4", 676 | "resolved": "https://registry.npmjs.org/typescript/-/typescript-5.5.4.tgz", 677 | "integrity": "sha512-Mtq29sKDAEYP7aljRgtPOpTvOfbwRWlS6dPRzwjdE+C0R4brX/GUyhHSecbHMFLNBLcJIPt9nl9yG5TZ1weH+Q==", 678 | "license": "Apache-2.0", 679 | "bin": { 680 | "tsc": "bin/tsc", 681 | "tsserver": "bin/tsserver" 682 | }, 683 | "engines": { 684 | "node": ">=14.17" 685 | } 686 | }, 687 | "node_modules/undici-types": { 688 | "version": "6.19.6", 689 | "resolved": "https://registry.npmjs.org/undici-types/-/undici-types-6.19.6.tgz", 690 | "integrity": "sha512-e/vggGopEfTKSvj4ihnOLTsqhrKRN3LeO6qSN/GxohhuRv8qH9bNQ4B8W7e/vFL+0XTnmHPB4/kegunZGA4Org==", 691 | "license": "MIT" 692 | }, 693 | "node_modules/util-deprecate": { 694 | "version": "1.0.2", 695 | "resolved": "https://registry.npmjs.org/util-deprecate/-/util-deprecate-1.0.2.tgz", 696 | "integrity": "sha512-EPD5q1uXyFxJpCrLnCc1nHnq3gOa6DZBocAIiI2TaSCA7VCJ1UJDMagCzIkXNsUYfD1daK//LTEQ8xiIbrHtcw==", 697 | "license": "MIT" 698 | }, 699 | "node_modules/v8-compile-cache-lib": { 700 | "version": "3.0.1", 701 | "resolved": "https://registry.npmjs.org/v8-compile-cache-lib/-/v8-compile-cache-lib-3.0.1.tgz", 702 | "integrity": "sha512-wa7YjyUGfNZngI/vtK0UHAN+lgDCxBPCylVXGp0zu59Fz5aiGtNXaq3DhIov063MorB+VfufLh3JlF2KdTK3xg==", 703 | "dev": true, 704 | "license": "MIT" 705 | }, 706 | "node_modules/validator": { 707 | "version": "13.12.0", 708 | "resolved": "https://registry.npmjs.org/validator/-/validator-13.12.0.tgz", 709 | "integrity": "sha512-c1Q0mCiPlgdTVVVIJIrBuxNicYE+t/7oKeI9MWLj3fh/uq2Pxh/3eeWbVZ4OcGW1TUf53At0njHw5SMdA3tmMg==", 710 | "license": "MIT", 711 | "engines": { 712 | "node": ">= 0.10" 713 | } 714 | }, 715 | "node_modules/wrappy": { 716 | "version": "1.0.2", 717 | "resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz", 718 | "integrity": "sha512-l4Sp/DRseor9wL6EvV2+TuQn63dMkPjZ/sp9XkghTEbV9KlPS1xUsZ3u7/IQO4wxtcFB4bgpQPRcR3QCvezPcQ==", 719 | "license": "ISC" 720 | }, 721 | "node_modules/yn": { 722 | "version": "3.1.1", 723 | "resolved": "https://registry.npmjs.org/yn/-/yn-3.1.1.tgz", 724 | "integrity": "sha512-Ux4ygGWsu2c7isFWe8Yu1YluJmqVhxqK2cLXNQA5AcC3QfbGNpM7fu0Y8b/z16pXLnFxZYvWhd3fhBY9DLmC6Q==", 725 | "dev": true, 726 | "license": "MIT", 727 | "engines": { 728 | "node": ">=6" 729 | } 730 | } 731 | } 732 | } 733 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "gitswitcher", 3 | "version": "2.0.1", 4 | "description": "Program that helps you switch between your GitHub, GitLab & Bitbucket accounts.", 5 | "main": "dist/index.js", 6 | "scripts": { 7 | "build": "node build.js && ./node_modules/.bin/tsc", 8 | "postinstall": "node ./postinstall-message.js && chmod +x ./dist/index.js", 9 | "prepare": "npm run build" 10 | }, 11 | "bin": { 12 | "gitswitcher": "./dist/index.js" 13 | }, 14 | "keywords": [ 15 | "git", 16 | "switch", 17 | "GitHub", 18 | "GitLab", 19 | "Bitbucket" 20 | ], 21 | "author": "Denis Yasyuchenya ZNN", 22 | "license": "ISC", 23 | "dependencies": { 24 | "@types/better-sqlite3": "^7.6.11", 25 | "@types/node": "^22.4.1", 26 | "@types/readline-sync": "^1.4.8", 27 | "@types/validator": "^13.12.0", 28 | "better-sqlite3": "^11.1.2", 29 | "readline-sync": "^1.4.10", 30 | "typescript": "^5.5.4", 31 | "validator": "^13.12.0" 32 | }, 33 | "devDependencies": { 34 | "ts-node": "^10.9.2" 35 | } 36 | } 37 | -------------------------------------------------------------------------------- /postinstall-message.js: -------------------------------------------------------------------------------- 1 | console.log(` 2 | ▄▀▒░█░▀█▀░▄▀▀░█ ░▒█░█░▀█▀░▄▀▀░█▄█▒██▀▒█▀▄ 3 | ░▀▄█░█ ▒█▒▒▄██░▀▄▀▄▀░█ ▒█▒░▀▄▄▒█▒█░█▄▄░█▀▄ 4 | `); -------------------------------------------------------------------------------- /secure-database.db: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/z-nnovation/GitSwitcher/877f6dbc80cbbd7568680d6bbc89b0676069f36f/secure-database.db -------------------------------------------------------------------------------- /src/index.ts: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env node 2 | 3 | import { createTable, deleteTable, addAccount, deleteAccount, showAccounts, showTables, switchAccount } from './services/credentials'; 4 | 5 | const command = process.argv[2]; 6 | const tableName = process.argv[3]; 7 | const identifier = process.argv[4]; 8 | const email = process.argv[5]; 9 | 10 | console.log('Command received:', command); 11 | function printHelp() { 12 | console.log(` 13 | ▄▀▒░█░▀█▀░▄▀▀░█ ░▒█░█░▀█▀░▄▀▀░█▄█▒██▀▒█▀▄ 14 | ░▀▄█░█ ▒█▒▒▄██░▀▄▀▄▀░█ ▒█▒░▀▄▄▒█▒█░█▄▄░█▀▄ 15 | 16 | Usage: 17 | gitswitcher create 18 | gitswitcher delete-table 19 | gitswitcher add [token] 20 | gitswitcher delete-account 21 | gitswitcher show 22 | gitswitcher show-folders 23 | gitswitcher use 24 | `); 25 | } 26 | 27 | if (!command || command === '--help') { 28 | printHelp(); 29 | process.exit(0); 30 | } 31 | 32 | if (command === 'create') { 33 | createTable(tableName); 34 | } else if (command === 'delete-table') { 35 | deleteTable(tableName); 36 | } else if (command === 'add') { 37 | if (!identifier || !email) { 38 | console.error('Please provide both a name and an email.'); 39 | process.exit(1); 40 | } 41 | addAccount(tableName, identifier, email, process.argv[6]); 42 | } else if (command === 'delete-account') { 43 | if (!identifier) { 44 | console.error('Please provide an account ID or name.'); 45 | process.exit(1); 46 | } 47 | deleteAccount(tableName, identifier); 48 | } else if (command === 'show') { 49 | showAccounts(tableName); 50 | } else if (command === 'show-folders') { 51 | showTables(); 52 | } else if (command === 'use') { 53 | switchAccount(tableName, identifier); 54 | } else { 55 | console.error('Unknown command.'); 56 | printHelp(); 57 | process.exit(1); 58 | } 59 | -------------------------------------------------------------------------------- /src/services/credentials.ts: -------------------------------------------------------------------------------- 1 | import { db } from './database'; 2 | import { encrypt, decrypt } from './encryption'; 3 | import * as validator from 'validator'; 4 | import { storeCredentials } from './utils'; 5 | import { execSync } from 'child_process'; 6 | import readlineSync from 'readline-sync'; 7 | 8 | interface AccountConfig { 9 | id: number; 10 | name: string; 11 | email: string; 12 | token?: string; 13 | } 14 | 15 | export function createTable(tableName: string): void { 16 | const tableExists = db.prepare(`SELECT name FROM sqlite_master WHERE type='table' AND name=?;`).get(tableName); 17 | 18 | if (tableExists) { 19 | console.log(`Table '${tableName}' already exists.`); 20 | } else { 21 | db.exec(` 22 | CREATE TABLE ${tableName} ( 23 | id INTEGER PRIMARY KEY AUTOINCREMENT, 24 | name TEXT NOT NULL, 25 | email TEXT NOT NULL, 26 | token TEXT, /* Поле для хранения зашифрованного токена или пароля */ 27 | UNIQUE(name, email) 28 | ); 29 | `); 30 | console.log(`Table '${tableName}' created successfully.`); 31 | } 32 | } 33 | 34 | export function deleteTable(tableName: string): void { 35 | const tableExists = db.prepare(`SELECT name FROM sqlite_master WHERE type='table' AND name=?;`).get(tableName); 36 | 37 | if (!tableExists) { 38 | console.error(`Table '${tableName}' does not exist.`); 39 | } else { 40 | db.exec(`DROP TABLE ${tableName}`); 41 | console.log(`Table '${tableName}' deleted successfully.`); 42 | } 43 | } 44 | 45 | // export function addAccount(tableName: string, name: string, email: string, token?: string): void { 46 | // const tableExists = db.prepare(`SELECT name FROM sqlite_master WHERE type='table' AND name=?;`).get(tableName); 47 | // if (!tableExists) { 48 | // console.error(`Error: Table '${tableName}' does not exist. Please create the table first using 'gitswitcher create ${tableName}'.`); 49 | // process.exit(1); 50 | // } 51 | 52 | // if (!validator.isEmail(email)) { 53 | // console.error('Invalid email address.'); 54 | // process.exit(1); 55 | // } 56 | 57 | // const exists = db.prepare(`SELECT * FROM ${tableName} WHERE name = ? OR email = ?`).get(name, email); 58 | // if (exists) { 59 | // console.error('Account with this name or email already exists.'); 60 | // process.exit(1); 61 | // } 62 | 63 | // const encryptedToken = token ? encrypt(token) : null; 64 | // const stmt = db.prepare(`INSERT INTO ${tableName} (name, email, token) VALUES (?, ?, ?)`); 65 | // stmt.run(name, email, encryptedToken); 66 | // console.log(`Account '${name}' added to table '${tableName}'.`); 67 | 68 | // if (token) { 69 | // storeCredentials("github.com", name, decrypt(encryptedToken!)); 70 | // } 71 | // } 72 | 73 | export function addAccount(tableName: string, name: string, email: string, token?: string): void { 74 | // Проверка на существование таблицы 75 | const tableExists = db.prepare(`SELECT name FROM sqlite_master WHERE type='table' AND name=?;`).get(tableName); 76 | if (!tableExists) { 77 | console.error(`Error: Table '${tableName}' does not exist. Please create the table first using 'gitswitcher create ${tableName}'.`); 78 | process.exit(1); 79 | } 80 | 81 | if (!validator.isEmail(email)) { 82 | console.error('Invalid email address.'); 83 | process.exit(1); 84 | } 85 | 86 | const exists = db.prepare(`SELECT * FROM ${tableName} WHERE name = ? OR email = ?`).get(name, email); 87 | if (exists) { 88 | console.error('Account with this name or email already exists.'); 89 | process.exit(1); 90 | } 91 | 92 | const encryptedToken = token ? encrypt(token) : null; 93 | const stmt = db.prepare(`INSERT INTO ${tableName} (name, email, token) VALUES (?, ?, ?)`); 94 | stmt.run(name, email, encryptedToken); 95 | console.log(`Account '${name}' added to table '${tableName}'.`); 96 | 97 | if (token) { 98 | // Определяем хост по умолчанию для известных сервисов 99 | let host = tableName.toLowerCase() === 'github' ? 'github.com' : 100 | tableName.toLowerCase() === 'gitlab' ? 'gitlab.com' : 101 | tableName.toLowerCase() === 'bitbucket' ? 'bitbucket.org' : 102 | null; 103 | 104 | // Если хост не распознан, спрашиваем пользователя 105 | if (!host) { 106 | host = readlineSync.question('Please enter the host for this account (e.g., pixietown.com): '); 107 | } 108 | 109 | storeCredentials(host, name, decrypt(encryptedToken!)); 110 | console.log(`Credentials for ${name} have been stored with host ${host}.`); 111 | } 112 | } 113 | 114 | export function deleteAccount(tableName: string, identifier: string): void { 115 | const stmt = db.prepare(`DELETE FROM ${tableName} WHERE id = ? OR name = ?`); 116 | const result = stmt.run(identifier, identifier); 117 | 118 | if (result.changes > 0) { 119 | console.log(`Account with identifier '${identifier}' deleted successfully from table '${tableName}'.`); 120 | } else { 121 | console.error(`No account found with identifier '${identifier}' in table '${tableName}'.`); 122 | } 123 | } 124 | 125 | export function showAccounts(tableName: string): void { 126 | const rows = db.prepare(`SELECT id, name FROM ${tableName}`).all() as AccountConfig[]; 127 | 128 | if (rows.length === 0) { 129 | console.log(`No accounts found in folder '${tableName}'.`); 130 | } else { 131 | console.log(`Accounts in table '${tableName}':`); 132 | rows.forEach((row) => { 133 | console.log(`${row.id}: ${row.name}`); 134 | }); 135 | } 136 | } 137 | 138 | export function showTables(): void { 139 | const tables = db.prepare(`SELECT name FROM sqlite_master WHERE type='table' AND name NOT IN ('sqlite_sequence', 'accounts')`).all() as { name: string }[]; 140 | 141 | if (tables.length === 0) { 142 | console.log('No folders found.'); 143 | } else { 144 | console.log('Your folders:'); 145 | tables.forEach((table) => { 146 | console.log(table.name); 147 | }); 148 | } 149 | } 150 | 151 | export function switchAccount(tableName: string, identifier: string): void { 152 | // Проверяем, существует ли таблица 153 | const tableExists = db.prepare(` 154 | SELECT name FROM sqlite_master WHERE type='table' AND name=?; 155 | `).get(tableName); 156 | 157 | if (!tableExists) { 158 | console.error(`Table '${tableName}' does not exist.`); 159 | process.exit(1); 160 | } 161 | 162 | let row: AccountConfig | undefined; 163 | 164 | if (!isNaN(Number(identifier))) { 165 | const id = parseInt(identifier, 10); 166 | row = db.prepare(`SELECT * FROM ${tableName} WHERE id = ?`).get(id) as AccountConfig; 167 | } else { 168 | row = db.prepare(`SELECT * FROM ${tableName} WHERE name = ?`).get(identifier) as AccountConfig; 169 | } 170 | 171 | if (!row) { 172 | console.error(`Account with ${!isNaN(Number(identifier)) ? 'ID' : 'name'} '${identifier}' not found in table '${tableName}'`); 173 | process.exit(1); 174 | } 175 | 176 | console.log(`Switching to account '${row.name}' with the following details:`); 177 | console.log(`Name: ${row.name}`); 178 | console.log(`Email: ${row.email}`); 179 | if (row.token) { 180 | console.log(`Token/Password: ****`); 181 | storeCredentials("github.com", row.name, decrypt(row.token!)); 182 | } 183 | 184 | execSync(`git config --global user.name "${row.name}"`); 185 | execSync(`git config --global user.email "${row.email}"`); 186 | 187 | console.log(`Switched to account '${row.name}'`); 188 | } 189 | -------------------------------------------------------------------------------- /src/services/database.ts: -------------------------------------------------------------------------------- 1 | import * as path from 'path'; 2 | import * as fs from 'fs'; 3 | import Database from 'better-sqlite3'; 4 | import * as crypto from 'crypto'; 5 | 6 | const encryptionKeyPath = path.join(__dirname, '../../encryption-key.txt'); 7 | const databasePath = path.join(__dirname, '../../secure-database.db'); 8 | 9 | let encryptionKey: string; 10 | if (!fs.existsSync(encryptionKeyPath)) { 11 | encryptionKey = crypto.randomBytes(32).toString('hex'); 12 | fs.writeFileSync(encryptionKeyPath, encryptionKey); 13 | //console.log(`Encryption key generated and saved to ${encryptionKeyPath}`); 14 | } else { 15 | encryptionKey = fs.readFileSync(encryptionKeyPath, 'utf-8').trim(); 16 | //console.log(`Encryption key loaded from ${encryptionKeyPath}`); 17 | } 18 | 19 | const db = new Database(databasePath); 20 | db.exec(`PRAGMA key = '${encryptionKey}';`); 21 | 22 | export { db }; 23 | -------------------------------------------------------------------------------- /src/services/encryption.ts: -------------------------------------------------------------------------------- 1 | import * as crypto from 'crypto'; 2 | 3 | const encryptionSecret = crypto.createHash('sha256').update('your-encryption-secret-key').digest('base64').substr(0, 32); 4 | const iv = crypto.randomBytes(16); 5 | 6 | export function encrypt(text: string): string { 7 | const cipher = crypto.createCipheriv('aes-256-cbc', Buffer.from(encryptionSecret), iv); 8 | let encrypted = cipher.update(text, 'utf8', 'hex'); 9 | encrypted += cipher.final('hex'); 10 | return iv.toString('hex') + ':' + encrypted; 11 | } 12 | 13 | export function decrypt(text: string): string { 14 | const textParts = text.split(':'); 15 | const iv = Buffer.from(textParts.shift() as string, 'hex'); 16 | const encryptedText = textParts.join(':'); 17 | const decipher = crypto.createDecipheriv('aes-256-cbc', Buffer.from(encryptionSecret), iv); 18 | let decrypted = decipher.update(encryptedText, 'hex', 'utf8'); 19 | decrypted += decipher.final('utf8'); 20 | return decrypted; 21 | } 22 | -------------------------------------------------------------------------------- /src/services/utils.ts: -------------------------------------------------------------------------------- 1 | import * as fs from 'fs'; 2 | import * as path from 'path'; 3 | 4 | export function storeCredentials(remoteUrl: string, name: string, token: string): void { 5 | const credsDir = path.join(__dirname, '.creds'); 6 | 7 | if (!fs.existsSync(credsDir)) { 8 | fs.mkdirSync(credsDir); 9 | } 10 | 11 | const credentialsFile = path.join(credsDir, 'git-credentials'); 12 | const credentialsEntry = `https://${name}:${token}@${remoteUrl}`; 13 | 14 | fs.appendFileSync(credentialsFile, `${credentialsEntry}\n`, 'utf8'); 15 | console.log(`Credentials for ${name} have been stored.`); 16 | } 17 | -------------------------------------------------------------------------------- /tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "compilerOptions": { 3 | "target": "ES6", // Или выше 4 | "module": "CommonJS", // Убедитесь, что используется CommonJS 5 | "rootDir": "src", 6 | "outDir": "dist", // Скомпилированные файлы помещаются в "dist" 7 | "esModuleInterop": true, // Включает совместимость с модулями ES6 8 | "forceConsistentCasingInFileNames": true, 9 | "strict": true, 10 | "skipLibCheck": true 11 | } 12 | } 13 | --------------------------------------------------------------------------------