@fredlackey/devutils 0.0.18 → 0.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +214 -141
- package/package.json +8 -83
- package/src/api/loader.js +229 -0
- package/src/api/registry.json +62 -0
- package/src/cli.js +293 -60
- package/src/commands/ai/index.js +16 -0
- package/src/commands/ai/launch.js +112 -0
- package/src/commands/ai/list.js +54 -0
- package/src/commands/ai/resume.js +70 -0
- package/src/commands/ai/sessions.js +121 -0
- package/src/commands/ai/set.js +131 -0
- package/src/commands/ai/show.js +74 -0
- package/src/commands/ai/tools.js +46 -0
- package/src/commands/alias/add.js +93 -0
- package/src/commands/alias/helpers.js +107 -0
- package/src/commands/alias/index.js +14 -0
- package/src/commands/alias/list.js +55 -0
- package/src/commands/alias/remove.js +62 -0
- package/src/commands/alias/sync.js +109 -0
- package/src/commands/api/disable.js +73 -0
- package/src/commands/api/enable.js +148 -0
- package/src/commands/api/index.js +15 -0
- package/src/commands/api/list.js +66 -0
- package/src/commands/api/update.js +87 -0
- package/src/commands/auth/index.js +15 -0
- package/src/commands/auth/list.js +49 -0
- package/src/commands/auth/login.js +384 -0
- package/src/commands/auth/logout.js +111 -0
- package/src/commands/auth/refresh.js +184 -0
- package/src/commands/auth/services.js +169 -0
- package/src/commands/auth/status.js +104 -0
- package/src/commands/config/export.js +224 -0
- package/src/commands/config/get.js +52 -0
- package/src/commands/config/import.js +308 -0
- package/src/commands/config/index.js +17 -0
- package/src/commands/config/init.js +143 -0
- package/src/commands/config/reset.js +57 -0
- package/src/commands/config/set.js +93 -0
- package/src/commands/config/show.js +35 -0
- package/src/commands/help.js +338 -0
- package/src/commands/identity/add.js +133 -0
- package/src/commands/identity/index.js +17 -0
- package/src/commands/identity/link.js +76 -0
- package/src/commands/identity/list.js +48 -0
- package/src/commands/identity/remove.js +72 -0
- package/src/commands/identity/show.js +65 -0
- package/src/commands/identity/sync.js +172 -0
- package/src/commands/identity/unlink.js +57 -0
- package/src/commands/ignore/add.js +165 -0
- package/src/commands/ignore/index.js +14 -0
- package/src/commands/ignore/list.js +89 -0
- package/src/commands/ignore/markers.js +43 -0
- package/src/commands/ignore/remove.js +164 -0
- package/src/commands/ignore/show.js +169 -0
- package/src/commands/machine/detect.js +122 -0
- package/src/commands/machine/index.js +14 -0
- package/src/commands/machine/list.js +74 -0
- package/src/commands/machine/set.js +106 -0
- package/src/commands/machine/show.js +35 -0
- package/src/commands/schema.js +152 -0
- package/src/commands/search/collections.js +134 -0
- package/src/commands/search/get.js +71 -0
- package/src/commands/search/index-cmd.js +54 -0
- package/src/commands/search/index.js +21 -0
- package/src/commands/search/keyword.js +60 -0
- package/src/commands/search/qmd.js +70 -0
- package/src/commands/search/query.js +64 -0
- package/src/commands/search/semantic.js +62 -0
- package/src/commands/search/status.js +46 -0
- package/src/commands/status.js +224 -171
- package/src/commands/tools/check.js +79 -0
- package/src/commands/tools/index.js +14 -0
- package/src/commands/tools/install.js +110 -0
- package/src/commands/tools/list.js +91 -0
- package/src/commands/tools/search.js +60 -0
- package/src/commands/update.js +83 -112
- package/src/commands/util/add.js +151 -0
- package/src/commands/util/index.js +15 -0
- package/src/commands/util/list.js +97 -0
- package/src/commands/util/remove.js +76 -0
- package/src/commands/util/run.js +79 -0
- package/src/commands/util/show.js +67 -0
- package/src/commands/version.js +21 -88
- package/src/installers/_template.js +104 -0
- package/src/installers/git.js +150 -0
- package/src/installers/homebrew.js +190 -0
- package/src/installers/node.js +223 -0
- package/src/installers/registry.json +29 -0
- package/src/lib/config.js +125 -0
- package/src/lib/detect.js +74 -0
- package/src/lib/errors.js +114 -0
- package/src/lib/github.js +315 -0
- package/src/lib/installer.js +225 -0
- package/src/lib/output.js +239 -0
- package/src/lib/platform.js +112 -0
- package/src/lib/platforms/amazon-linux.js +41 -0
- package/src/lib/platforms/gitbash.js +46 -0
- package/src/lib/platforms/macos.js +45 -0
- package/src/lib/platforms/raspbian.js +41 -0
- package/src/lib/platforms/ubuntu.js +39 -0
- package/src/lib/platforms/windows.js +45 -0
- package/src/lib/prompt.js +161 -0
- package/src/lib/schema.js +211 -0
- package/src/lib/shell.js +75 -0
- package/src/patterns/gitignore/claude-code.txt +25 -0
- package/src/patterns/gitignore/docker.txt +15 -0
- package/src/patterns/gitignore/go.txt +24 -0
- package/src/patterns/gitignore/java.txt +38 -0
- package/src/patterns/gitignore/jetbrains.txt +26 -0
- package/src/patterns/gitignore/linux.txt +18 -0
- package/src/patterns/gitignore/macos.txt +27 -0
- package/src/patterns/gitignore/node.txt +51 -0
- package/src/patterns/gitignore/python.txt +55 -0
- package/src/patterns/gitignore/rust.txt +14 -0
- package/src/patterns/gitignore/terraform.txt +30 -0
- package/src/patterns/gitignore/vscode.txt +15 -0
- package/src/patterns/gitignore/windows.txt +25 -0
- package/src/utils/clone/index.js +165 -0
- package/src/utils/git-push/index.js +230 -0
- package/src/utils/git-status/index.js +116 -0
- package/src/utils/git-status/unix.sh +75 -0
- package/src/utils/registry.json +41 -0
- package/bin/dev.js +0 -16
- package/files/README.md +0 -0
- package/files/claude/.claude/commands/setup-context.md +0 -3
- package/files/monorepos/_archive/README.md +0 -36
- package/files/monorepos/_legacy/README.md +0 -36
- package/files/monorepos/ai-docs/README.md +0 -33
- package/files/monorepos/apps/README.md +0 -24
- package/files/monorepos/docs/README.md +0 -40
- package/files/monorepos/packages/README.md +0 -25
- package/files/monorepos/research/README.md +0 -29
- package/files/monorepos/scripts/README.md +0 -24
- package/src/commands/README.md +0 -41
- package/src/commands/configure.js +0 -199
- package/src/commands/identity.js +0 -1630
- package/src/commands/ignore.js +0 -247
- package/src/commands/install.js +0 -526
- package/src/commands/setup.js +0 -246
- package/src/completion.js +0 -284
- package/src/constants.js +0 -45
- package/src/ignore/claude-code.txt +0 -10
- package/src/ignore/docker.txt +0 -18
- package/src/ignore/linux.txt +0 -23
- package/src/ignore/macos.txt +0 -36
- package/src/ignore/node.txt +0 -55
- package/src/ignore/terraform.txt +0 -37
- package/src/ignore/vscode.txt +0 -18
- package/src/ignore/windows.txt +0 -35
- package/src/index.js +0 -0
- package/src/installs/README.md +0 -399
- package/src/installs/adobe-creative-cloud.js +0 -546
- package/src/installs/adobe-creative-cloud.md +0 -605
- package/src/installs/appcleaner.js +0 -321
- package/src/installs/appcleaner.md +0 -699
- package/src/installs/apt-transport-https.js +0 -390
- package/src/installs/apt-transport-https.md +0 -678
- package/src/installs/atomicparsley.js +0 -642
- package/src/installs/atomicparsley.md +0 -795
- package/src/installs/aws-cli.js +0 -797
- package/src/installs/aws-cli.md +0 -727
- package/src/installs/balena-etcher.js +0 -710
- package/src/installs/balena-etcher.md +0 -761
- package/src/installs/bambu-studio.js +0 -1143
- package/src/installs/bambu-studio.md +0 -780
- package/src/installs/bash-completion.js +0 -575
- package/src/installs/bash-completion.md +0 -833
- package/src/installs/bash.js +0 -417
- package/src/installs/bash.md +0 -993
- package/src/installs/beyond-compare.js +0 -603
- package/src/installs/beyond-compare.md +0 -813
- package/src/installs/brave-browser.js +0 -968
- package/src/installs/brave-browser.md +0 -650
- package/src/installs/build-essential.js +0 -529
- package/src/installs/build-essential.md +0 -977
- package/src/installs/ca-certificates.js +0 -618
- package/src/installs/ca-certificates.md +0 -937
- package/src/installs/caffeine.js +0 -508
- package/src/installs/caffeine.md +0 -839
- package/src/installs/camtasia.js +0 -596
- package/src/installs/camtasia.md +0 -762
- package/src/installs/chatgpt.js +0 -476
- package/src/installs/chatgpt.md +0 -814
- package/src/installs/chocolatey.js +0 -456
- package/src/installs/chocolatey.md +0 -661
- package/src/installs/chrome-canary.js +0 -419
- package/src/installs/chrome-canary.md +0 -641
- package/src/installs/chromium.js +0 -667
- package/src/installs/chromium.md +0 -838
- package/src/installs/claude-code.js +0 -576
- package/src/installs/claude-code.md +0 -1173
- package/src/installs/cloudflare-warp.js +0 -900
- package/src/installs/cloudflare-warp.md +0 -1047
- package/src/installs/comet-browser.js +0 -588
- package/src/installs/comet-browser.md +0 -731
- package/src/installs/curl.js +0 -379
- package/src/installs/curl.md +0 -714
- package/src/installs/cursor.js +0 -579
- package/src/installs/cursor.md +0 -970
- package/src/installs/dbeaver.js +0 -924
- package/src/installs/dbeaver.md +0 -939
- package/src/installs/dbschema.js +0 -692
- package/src/installs/dbschema.md +0 -925
- package/src/installs/dependencies.md +0 -453
- package/src/installs/development-tools.js +0 -600
- package/src/installs/development-tools.md +0 -977
- package/src/installs/docker.js +0 -1029
- package/src/installs/docker.md +0 -1109
- package/src/installs/drawio.js +0 -1019
- package/src/installs/drawio.md +0 -795
- package/src/installs/elmedia-player.js +0 -347
- package/src/installs/elmedia-player.md +0 -556
- package/src/installs/ffmpeg.js +0 -889
- package/src/installs/ffmpeg.md +0 -852
- package/src/installs/file.js +0 -464
- package/src/installs/file.md +0 -987
- package/src/installs/gemini-cli.js +0 -811
- package/src/installs/gemini-cli.md +0 -1153
- package/src/installs/git.js +0 -400
- package/src/installs/git.md +0 -907
- package/src/installs/gitego.js +0 -949
- package/src/installs/gitego.md +0 -1172
- package/src/installs/go.js +0 -931
- package/src/installs/go.md +0 -958
- package/src/installs/google-antigravity.js +0 -913
- package/src/installs/google-antigravity.md +0 -1075
- package/src/installs/google-chrome.js +0 -833
- package/src/installs/google-chrome.md +0 -862
- package/src/installs/gpg.js +0 -480
- package/src/installs/gpg.md +0 -1056
- package/src/installs/homebrew.js +0 -1028
- package/src/installs/homebrew.md +0 -988
- package/src/installs/imageoptim.js +0 -968
- package/src/installs/imageoptim.md +0 -1119
- package/src/installs/installers.json +0 -4032
- package/src/installs/installers.json.tmp +0 -3953
- package/src/installs/jq.js +0 -400
- package/src/installs/jq.md +0 -809
- package/src/installs/keyboard-maestro.js +0 -719
- package/src/installs/keyboard-maestro.md +0 -825
- package/src/installs/kiro.js +0 -864
- package/src/installs/kiro.md +0 -1015
- package/src/installs/latex.js +0 -789
- package/src/installs/latex.md +0 -1095
- package/src/installs/lftp.js +0 -356
- package/src/installs/lftp.md +0 -907
- package/src/installs/lsb-release.js +0 -346
- package/src/installs/lsb-release.md +0 -814
- package/src/installs/messenger.js +0 -847
- package/src/installs/messenger.md +0 -900
- package/src/installs/microsoft-office.js +0 -568
- package/src/installs/microsoft-office.md +0 -760
- package/src/installs/microsoft-teams.js +0 -801
- package/src/installs/microsoft-teams.md +0 -886
- package/src/installs/moom.js +0 -326
- package/src/installs/moom.md +0 -570
- package/src/installs/node.js +0 -904
- package/src/installs/node.md +0 -1153
- package/src/installs/nordpass.js +0 -716
- package/src/installs/nordpass.md +0 -921
- package/src/installs/nordvpn.js +0 -892
- package/src/installs/nordvpn.md +0 -1052
- package/src/installs/nvm.js +0 -995
- package/src/installs/nvm.md +0 -1057
- package/src/installs/ohmyzsh.js +0 -529
- package/src/installs/ohmyzsh.md +0 -1094
- package/src/installs/openssh.js +0 -804
- package/src/installs/openssh.md +0 -1056
- package/src/installs/pandoc.js +0 -662
- package/src/installs/pandoc.md +0 -1036
- package/src/installs/parallels-desktop.js +0 -431
- package/src/installs/parallels-desktop.md +0 -446
- package/src/installs/pinentry.js +0 -510
- package/src/installs/pinentry.md +0 -1142
- package/src/installs/pngyu.js +0 -869
- package/src/installs/pngyu.md +0 -896
- package/src/installs/postman.js +0 -799
- package/src/installs/postman.md +0 -940
- package/src/installs/procps.js +0 -425
- package/src/installs/procps.md +0 -851
- package/src/installs/safari-tech-preview.js +0 -374
- package/src/installs/safari-tech-preview.md +0 -533
- package/src/installs/sfnt2woff.js +0 -658
- package/src/installs/sfnt2woff.md +0 -795
- package/src/installs/shellcheck.js +0 -481
- package/src/installs/shellcheck.md +0 -1005
- package/src/installs/slack.js +0 -741
- package/src/installs/slack.md +0 -865
- package/src/installs/snagit.js +0 -585
- package/src/installs/snagit.md +0 -844
- package/src/installs/software-properties-common.js +0 -372
- package/src/installs/software-properties-common.md +0 -805
- package/src/installs/spotify.js +0 -877
- package/src/installs/spotify.md +0 -901
- package/src/installs/studio-3t.js +0 -823
- package/src/installs/studio-3t.md +0 -918
- package/src/installs/sublime-text.js +0 -804
- package/src/installs/sublime-text.md +0 -914
- package/src/installs/superwhisper.js +0 -706
- package/src/installs/superwhisper.md +0 -630
- package/src/installs/tailscale.js +0 -745
- package/src/installs/tailscale.md +0 -1100
- package/src/installs/tar.js +0 -389
- package/src/installs/tar.md +0 -946
- package/src/installs/termius.js +0 -798
- package/src/installs/termius.md +0 -844
- package/src/installs/terraform.js +0 -779
- package/src/installs/terraform.md +0 -899
- package/src/installs/tfenv.js +0 -778
- package/src/installs/tfenv.md +0 -1091
- package/src/installs/tidal.js +0 -771
- package/src/installs/tidal.md +0 -864
- package/src/installs/tmux.js +0 -346
- package/src/installs/tmux.md +0 -1030
- package/src/installs/tree.js +0 -411
- package/src/installs/tree.md +0 -833
- package/src/installs/unzip.js +0 -460
- package/src/installs/unzip.md +0 -879
- package/src/installs/vim.js +0 -421
- package/src/installs/vim.md +0 -1040
- package/src/installs/vlc.js +0 -821
- package/src/installs/vlc.md +0 -927
- package/src/installs/vscode.js +0 -843
- package/src/installs/vscode.md +0 -1002
- package/src/installs/wget.js +0 -420
- package/src/installs/wget.md +0 -791
- package/src/installs/whatsapp.js +0 -729
- package/src/installs/whatsapp.md +0 -854
- package/src/installs/winpty.js +0 -352
- package/src/installs/winpty.md +0 -620
- package/src/installs/woff2.js +0 -553
- package/src/installs/woff2.md +0 -977
- package/src/installs/wsl.js +0 -572
- package/src/installs/wsl.md +0 -699
- package/src/installs/xcode-clt.js +0 -520
- package/src/installs/xcode-clt.md +0 -351
- package/src/installs/xcode.js +0 -560
- package/src/installs/xcode.md +0 -573
- package/src/installs/yarn.js +0 -824
- package/src/installs/yarn.md +0 -1074
- package/src/installs/yq.js +0 -654
- package/src/installs/yq.md +0 -944
- package/src/installs/yt-dlp.js +0 -701
- package/src/installs/yt-dlp.md +0 -946
- package/src/installs/yum-utils.js +0 -297
- package/src/installs/yum-utils.md +0 -648
- package/src/installs/zoom.js +0 -759
- package/src/installs/zoom.md +0 -884
- package/src/installs/zsh.js +0 -455
- package/src/installs/zsh.md +0 -1008
- package/src/scripts/README.md +0 -617
- package/src/scripts/STATUS.md +0 -208
- package/src/scripts/afk.js +0 -411
- package/src/scripts/backup-all.js +0 -746
- package/src/scripts/backup-source.js +0 -727
- package/src/scripts/brewd.js +0 -389
- package/src/scripts/brewi.js +0 -520
- package/src/scripts/brewr.js +0 -527
- package/src/scripts/brews.js +0 -477
- package/src/scripts/brewu.js +0 -504
- package/src/scripts/c.js +0 -201
- package/src/scripts/ccurl.js +0 -341
- package/src/scripts/certbot-crontab-init.js +0 -504
- package/src/scripts/certbot-init.js +0 -657
- package/src/scripts/ch.js +0 -355
- package/src/scripts/claude-danger.js +0 -268
- package/src/scripts/clean-dev.js +0 -435
- package/src/scripts/clear-dns-cache.js +0 -541
- package/src/scripts/clone.js +0 -435
- package/src/scripts/code-all.js +0 -437
- package/src/scripts/count-files.js +0 -211
- package/src/scripts/count-folders.js +0 -211
- package/src/scripts/count.js +0 -264
- package/src/scripts/d.js +0 -219
- package/src/scripts/datauri.js +0 -389
- package/src/scripts/delete-files.js +0 -380
- package/src/scripts/docker-clean.js +0 -426
- package/src/scripts/dp.js +0 -442
- package/src/scripts/e.js +0 -390
- package/src/scripts/empty-trash.js +0 -513
- package/src/scripts/evm.js +0 -444
- package/src/scripts/fetch-github-repos.js +0 -456
- package/src/scripts/get-channel.js +0 -345
- package/src/scripts/get-course.js +0 -399
- package/src/scripts/get-dependencies.js +0 -306
- package/src/scripts/get-folder.js +0 -799
- package/src/scripts/get-tunes.js +0 -426
- package/src/scripts/get-video.js +0 -367
- package/src/scripts/git-backup.js +0 -577
- package/src/scripts/git-clone.js +0 -493
- package/src/scripts/git-pup.js +0 -319
- package/src/scripts/git-push.js +0 -396
- package/src/scripts/h.js +0 -622
- package/src/scripts/hide-desktop-icons.js +0 -499
- package/src/scripts/hide-hidden-files.js +0 -538
- package/src/scripts/install-dependencies-from.js +0 -456
- package/src/scripts/ips.js +0 -663
- package/src/scripts/iso.js +0 -370
- package/src/scripts/killni.js +0 -577
- package/src/scripts/ll.js +0 -467
- package/src/scripts/local-ip.js +0 -325
- package/src/scripts/m.js +0 -524
- package/src/scripts/map.js +0 -309
- package/src/scripts/mkd.js +0 -351
- package/src/scripts/ncu-update-all.js +0 -457
- package/src/scripts/nginx-init.js +0 -718
- package/src/scripts/npmi.js +0 -382
- package/src/scripts/o.js +0 -511
- package/src/scripts/org-by-date.js +0 -338
- package/src/scripts/p.js +0 -224
- package/src/scripts/packages.js +0 -330
- package/src/scripts/path.js +0 -225
- package/src/scripts/ports.js +0 -597
- package/src/scripts/q.js +0 -305
- package/src/scripts/refresh-files.js +0 -394
- package/src/scripts/remove-smaller-files.js +0 -516
- package/src/scripts/rename-files-with-date.js +0 -533
- package/src/scripts/resize-image.js +0 -539
- package/src/scripts/rm-safe.js +0 -669
- package/src/scripts/s.js +0 -540
- package/src/scripts/set-git-public.js +0 -365
- package/src/scripts/show-desktop-icons.js +0 -475
- package/src/scripts/show-hidden-files.js +0 -472
- package/src/scripts/tpa.js +0 -280
- package/src/scripts/tpo.js +0 -280
- package/src/scripts/u.js +0 -505
- package/src/scripts/vpush.js +0 -437
- package/src/scripts/y.js +0 -283
- package/src/utils/README.md +0 -95
- package/src/utils/common/apps.js +0 -143
- package/src/utils/common/display.js +0 -157
- package/src/utils/common/network.js +0 -185
- package/src/utils/common/os.js +0 -294
- package/src/utils/common/package-manager.js +0 -301
- package/src/utils/common/privileges.js +0 -138
- package/src/utils/common/shell.js +0 -261
- package/src/utils/macos/apps.js +0 -228
- package/src/utils/macos/brew.js +0 -315
- package/src/utils/ubuntu/apt.js +0 -307
- package/src/utils/ubuntu/desktop.js +0 -292
- package/src/utils/ubuntu/snap.js +0 -344
- package/src/utils/ubuntu/systemd.js +0 -286
- package/src/utils/windows/choco.js +0 -465
- package/src/utils/windows/env.js +0 -246
- package/src/utils/windows/registry.js +0 -269
- package/src/utils/windows/shell.js +0 -240
- package/src/utils/windows/winget.js +0 -489
|
@@ -0,0 +1,111 @@
|
|
|
1
|
+
'use strict';
|
|
2
|
+
|
|
3
|
+
const fs = require('fs');
|
|
4
|
+
const path = require('path');
|
|
5
|
+
const https = require('https');
|
|
6
|
+
const { AUTH_SERVICES, AUTH_DIR, readCredential } = require('./services');
|
|
7
|
+
|
|
8
|
+
const meta = {
|
|
9
|
+
description: 'Revoke and remove stored credentials for a service',
|
|
10
|
+
arguments: [
|
|
11
|
+
{ name: 'service', description: 'Service name to log out from', required: true }
|
|
12
|
+
],
|
|
13
|
+
flags: []
|
|
14
|
+
};
|
|
15
|
+
|
|
16
|
+
/**
|
|
17
|
+
* Attempt to revoke an OAuth token by POSTing to the provider's revocation endpoint.
|
|
18
|
+
* This is best-effort: if revocation fails (network error, token already expired, etc.),
|
|
19
|
+
* we log a warning but continue with local cleanup.
|
|
20
|
+
*
|
|
21
|
+
* @param {string} revokeUrl - The revocation endpoint URL.
|
|
22
|
+
* @param {string} token - The access token to revoke.
|
|
23
|
+
* @returns {Promise<boolean>} True if revocation succeeded, false otherwise.
|
|
24
|
+
*/
|
|
25
|
+
function revokeToken(revokeUrl, token) {
|
|
26
|
+
return new Promise((resolve) => {
|
|
27
|
+
const postData = new URLSearchParams({ token }).toString();
|
|
28
|
+
const parsed = new URL(revokeUrl);
|
|
29
|
+
|
|
30
|
+
const options = {
|
|
31
|
+
hostname: parsed.hostname,
|
|
32
|
+
port: parsed.port || 443,
|
|
33
|
+
path: parsed.pathname + parsed.search,
|
|
34
|
+
method: 'POST',
|
|
35
|
+
headers: {
|
|
36
|
+
'Content-Type': 'application/x-www-form-urlencoded',
|
|
37
|
+
'Content-Length': Buffer.byteLength(postData)
|
|
38
|
+
}
|
|
39
|
+
};
|
|
40
|
+
|
|
41
|
+
const req = https.request(options, (res) => {
|
|
42
|
+
// Consume the response body so the socket is released
|
|
43
|
+
res.on('data', () => {});
|
|
44
|
+
res.on('end', () => {
|
|
45
|
+
resolve(res.statusCode >= 200 && res.statusCode < 300);
|
|
46
|
+
});
|
|
47
|
+
});
|
|
48
|
+
|
|
49
|
+
req.on('error', () => {
|
|
50
|
+
resolve(false);
|
|
51
|
+
});
|
|
52
|
+
|
|
53
|
+
req.write(postData);
|
|
54
|
+
req.end();
|
|
55
|
+
});
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
/**
|
|
59
|
+
* Run the auth logout command.
|
|
60
|
+
* Validates the service, attempts token revocation for OAuth services,
|
|
61
|
+
* and deletes the local credential file.
|
|
62
|
+
*
|
|
63
|
+
* @param {object} args - Parsed CLI arguments (positional, flags).
|
|
64
|
+
* @param {object} context - CLI context (output, prompt, errors).
|
|
65
|
+
*/
|
|
66
|
+
async function run(args, context) {
|
|
67
|
+
const service = args.positional[0];
|
|
68
|
+
|
|
69
|
+
if (!service) {
|
|
70
|
+
context.errors.throwError(400, 'Missing required argument: <service>. Example: dev auth logout google', 'auth');
|
|
71
|
+
return;
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
const serviceConfig = AUTH_SERVICES[service];
|
|
75
|
+
if (!serviceConfig) {
|
|
76
|
+
const supported = Object.keys(AUTH_SERVICES).join(', ');
|
|
77
|
+
context.errors.throwError(400, `Unknown service '${service}'. Supported services: ${supported}`, 'auth');
|
|
78
|
+
return;
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
// Check if credentials exist
|
|
82
|
+
const credential = readCredential(service);
|
|
83
|
+
if (!credential) {
|
|
84
|
+
context.output.info(`Not logged into ${service}.`);
|
|
85
|
+
return;
|
|
86
|
+
}
|
|
87
|
+
|
|
88
|
+
// Attempt token revocation for OAuth services
|
|
89
|
+
if (credential.type === 'oauth' && serviceConfig.revokeUrl && credential.accessToken) {
|
|
90
|
+
context.output.info(`Revoking ${service} token...`);
|
|
91
|
+
const revoked = await revokeToken(serviceConfig.revokeUrl, credential.accessToken);
|
|
92
|
+
if (revoked) {
|
|
93
|
+
context.output.info('Token revoked successfully.');
|
|
94
|
+
} else {
|
|
95
|
+
context.output.info('Warning: Token revocation failed. The token may still be valid on the provider side.');
|
|
96
|
+
context.output.info('Continuing with local cleanup.');
|
|
97
|
+
}
|
|
98
|
+
}
|
|
99
|
+
|
|
100
|
+
// Delete the credential file
|
|
101
|
+
const credFile = path.join(AUTH_DIR, `${service}.json`);
|
|
102
|
+
try {
|
|
103
|
+
fs.unlinkSync(credFile);
|
|
104
|
+
} catch {
|
|
105
|
+
// File may have already been deleted -- not an error
|
|
106
|
+
}
|
|
107
|
+
|
|
108
|
+
context.output.info(`Logged out of ${service}.`);
|
|
109
|
+
}
|
|
110
|
+
|
|
111
|
+
module.exports = { meta, run };
|
|
@@ -0,0 +1,184 @@
|
|
|
1
|
+
'use strict';
|
|
2
|
+
|
|
3
|
+
const fs = require('fs');
|
|
4
|
+
const path = require('path');
|
|
5
|
+
const https = require('https');
|
|
6
|
+
const { AUTH_SERVICES, AUTH_DIR, CLIENTS_DIR, readCredential } = require('./services');
|
|
7
|
+
|
|
8
|
+
const meta = {
|
|
9
|
+
description: 'Force a token refresh for an OAuth service without re-authenticating',
|
|
10
|
+
arguments: [
|
|
11
|
+
{ name: 'service', description: 'Service name to refresh', required: true }
|
|
12
|
+
],
|
|
13
|
+
flags: []
|
|
14
|
+
};
|
|
15
|
+
|
|
16
|
+
/**
|
|
17
|
+
* Make an HTTPS POST request with form-encoded data.
|
|
18
|
+
* Uses Node.js built-in https module (no external dependencies).
|
|
19
|
+
*
|
|
20
|
+
* @param {string} targetUrl - The URL to POST to.
|
|
21
|
+
* @param {Object<string, string>} data - Key/value pairs to send as form data.
|
|
22
|
+
* @returns {Promise<{ statusCode: number, body: string }>}
|
|
23
|
+
*/
|
|
24
|
+
function httpsPost(targetUrl, data) {
|
|
25
|
+
return new Promise((resolve, reject) => {
|
|
26
|
+
const postData = new URLSearchParams(data).toString();
|
|
27
|
+
const parsed = new URL(targetUrl);
|
|
28
|
+
|
|
29
|
+
const options = {
|
|
30
|
+
hostname: parsed.hostname,
|
|
31
|
+
port: parsed.port || 443,
|
|
32
|
+
path: parsed.pathname + parsed.search,
|
|
33
|
+
method: 'POST',
|
|
34
|
+
headers: {
|
|
35
|
+
'Content-Type': 'application/x-www-form-urlencoded',
|
|
36
|
+
'Content-Length': Buffer.byteLength(postData)
|
|
37
|
+
}
|
|
38
|
+
};
|
|
39
|
+
|
|
40
|
+
const req = https.request(options, (res) => {
|
|
41
|
+
let body = '';
|
|
42
|
+
res.on('data', (chunk) => { body += chunk; });
|
|
43
|
+
res.on('end', () => {
|
|
44
|
+
resolve({ statusCode: res.statusCode, body });
|
|
45
|
+
});
|
|
46
|
+
});
|
|
47
|
+
|
|
48
|
+
req.on('error', reject);
|
|
49
|
+
req.write(postData);
|
|
50
|
+
req.end();
|
|
51
|
+
});
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
/**
|
|
55
|
+
* Run the auth refresh command.
|
|
56
|
+
* Exchanges the stored refresh token for a new access token and updates
|
|
57
|
+
* the credential file. Only works for OAuth services.
|
|
58
|
+
*
|
|
59
|
+
* @param {object} args - Parsed CLI arguments (positional, flags).
|
|
60
|
+
* @param {object} context - CLI context (output, prompt, errors).
|
|
61
|
+
*/
|
|
62
|
+
async function run(args, context) {
|
|
63
|
+
const service = args.positional[0];
|
|
64
|
+
|
|
65
|
+
if (!service) {
|
|
66
|
+
context.errors.throwError(400, 'Missing required argument: <service>. Example: dev auth refresh google', 'auth');
|
|
67
|
+
return;
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
const serviceConfig = AUTH_SERVICES[service];
|
|
71
|
+
if (!serviceConfig) {
|
|
72
|
+
const supported = Object.keys(AUTH_SERVICES).join(', ');
|
|
73
|
+
context.errors.throwError(400, `Unknown service '${service}'. Supported services: ${supported}`, 'auth');
|
|
74
|
+
return;
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
// Read existing credentials
|
|
78
|
+
const credential = readCredential(service);
|
|
79
|
+
if (!credential) {
|
|
80
|
+
context.output.info(`Not authenticated with ${service}. Run "dev auth login ${service}" to authenticate first.`);
|
|
81
|
+
return;
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
// API key services don't support refresh
|
|
85
|
+
if (credential.type === 'api-key') {
|
|
86
|
+
context.output.info('Refresh is not applicable for API key services. API keys don\'t expire through DevUtils.');
|
|
87
|
+
return;
|
|
88
|
+
}
|
|
89
|
+
|
|
90
|
+
// OAuth services need a refresh token
|
|
91
|
+
if (credential.type !== 'oauth') {
|
|
92
|
+
context.output.info(`Unrecognized credential type: ${credential.type}`);
|
|
93
|
+
return;
|
|
94
|
+
}
|
|
95
|
+
|
|
96
|
+
if (!credential.refreshToken) {
|
|
97
|
+
context.output.info(`No refresh token available for ${service}. Run "dev auth login ${service}" to re-authenticate.`);
|
|
98
|
+
return;
|
|
99
|
+
}
|
|
100
|
+
|
|
101
|
+
// Read client credentials
|
|
102
|
+
if (!serviceConfig.clientFile) {
|
|
103
|
+
context.errors.throwError(500, `No client credentials file configured for ${service}.`, 'auth');
|
|
104
|
+
return;
|
|
105
|
+
}
|
|
106
|
+
|
|
107
|
+
const clientFile = path.join(CLIENTS_DIR, serviceConfig.clientFile);
|
|
108
|
+
if (!fs.existsSync(clientFile)) {
|
|
109
|
+
context.output.info(`Client credentials not found: ${clientFile}`);
|
|
110
|
+
context.output.info(`Cannot refresh without client credentials. Run "dev auth login ${service}" to re-authenticate.`);
|
|
111
|
+
return;
|
|
112
|
+
}
|
|
113
|
+
|
|
114
|
+
let clientCreds;
|
|
115
|
+
try {
|
|
116
|
+
clientCreds = JSON.parse(fs.readFileSync(clientFile, 'utf8'));
|
|
117
|
+
} catch {
|
|
118
|
+
context.errors.throwError(500, `Invalid client credentials file: ${clientFile}`, 'auth');
|
|
119
|
+
return;
|
|
120
|
+
}
|
|
121
|
+
|
|
122
|
+
if (!clientCreds.clientId || !clientCreds.clientSecret) {
|
|
123
|
+
context.errors.throwError(400, 'Client credentials file must contain "clientId" and "clientSecret".', 'auth');
|
|
124
|
+
return;
|
|
125
|
+
}
|
|
126
|
+
|
|
127
|
+
// Exchange refresh token for new access token
|
|
128
|
+
context.output.info(`Refreshing ${service} token...`);
|
|
129
|
+
|
|
130
|
+
let tokenResponse;
|
|
131
|
+
try {
|
|
132
|
+
tokenResponse = await httpsPost(serviceConfig.tokenUrl, {
|
|
133
|
+
grant_type: 'refresh_token',
|
|
134
|
+
refresh_token: credential.refreshToken,
|
|
135
|
+
client_id: clientCreds.clientId,
|
|
136
|
+
client_secret: clientCreds.clientSecret
|
|
137
|
+
});
|
|
138
|
+
} catch (err) {
|
|
139
|
+
context.errors.throwError(500, `Token refresh failed: ${err.message}`, 'auth');
|
|
140
|
+
return;
|
|
141
|
+
}
|
|
142
|
+
|
|
143
|
+
let tokenData;
|
|
144
|
+
try {
|
|
145
|
+
tokenData = JSON.parse(tokenResponse.body);
|
|
146
|
+
} catch {
|
|
147
|
+
context.errors.throwError(500, 'Failed to parse token refresh response.', 'auth');
|
|
148
|
+
return;
|
|
149
|
+
}
|
|
150
|
+
|
|
151
|
+
if (tokenData.error) {
|
|
152
|
+
context.errors.throwError(500, `Token refresh error: ${tokenData.error_description || tokenData.error}`, 'auth');
|
|
153
|
+
return;
|
|
154
|
+
}
|
|
155
|
+
|
|
156
|
+
// Update the credential file with the new token
|
|
157
|
+
const now = new Date();
|
|
158
|
+
const expiresAt = tokenData.expires_in
|
|
159
|
+
? new Date(now.getTime() + tokenData.expires_in * 1000).toISOString()
|
|
160
|
+
: credential.expiresAt;
|
|
161
|
+
|
|
162
|
+
const updated = {
|
|
163
|
+
type: 'oauth',
|
|
164
|
+
accessToken: tokenData.access_token,
|
|
165
|
+
// Some providers return a new refresh token, some don't.
|
|
166
|
+
// If a new one is returned, use it. Otherwise, keep the old one.
|
|
167
|
+
refreshToken: tokenData.refresh_token || credential.refreshToken,
|
|
168
|
+
expiresAt: expiresAt,
|
|
169
|
+
scopes: credential.scopes,
|
|
170
|
+
authenticatedAt: credential.authenticatedAt
|
|
171
|
+
};
|
|
172
|
+
|
|
173
|
+
fs.writeFileSync(
|
|
174
|
+
path.join(AUTH_DIR, `${service}.json`),
|
|
175
|
+
JSON.stringify(updated, null, 2) + '\n'
|
|
176
|
+
);
|
|
177
|
+
|
|
178
|
+
context.output.info(`Token refreshed successfully for ${service}.`);
|
|
179
|
+
if (expiresAt) {
|
|
180
|
+
context.output.info(`New expiry: ${expiresAt}`);
|
|
181
|
+
}
|
|
182
|
+
}
|
|
183
|
+
|
|
184
|
+
module.exports = { meta, run };
|
|
@@ -0,0 +1,169 @@
|
|
|
1
|
+
'use strict';
|
|
2
|
+
|
|
3
|
+
const fs = require('fs');
|
|
4
|
+
const path = require('path');
|
|
5
|
+
const os = require('os');
|
|
6
|
+
|
|
7
|
+
const AUTH_DIR = path.join(os.homedir(), '.devutils', 'auth');
|
|
8
|
+
const CLIENTS_DIR = path.join(AUTH_DIR, 'clients');
|
|
9
|
+
|
|
10
|
+
/**
|
|
11
|
+
* Registry of all supported authentication services.
|
|
12
|
+
* Each entry describes how the service authenticates and what credentials it needs.
|
|
13
|
+
*
|
|
14
|
+
* - OAuth services use a browser-based consent flow (e.g., Google).
|
|
15
|
+
* - API key services prompt the user for static credentials (e.g., AWS, Cloudflare).
|
|
16
|
+
*
|
|
17
|
+
* This object is the single source of truth for all auth commands (login, logout,
|
|
18
|
+
* list, status, refresh). Add new services here -- all commands will pick them up.
|
|
19
|
+
*/
|
|
20
|
+
const AUTH_SERVICES = {
|
|
21
|
+
google: {
|
|
22
|
+
type: 'oauth',
|
|
23
|
+
authUrl: 'https://accounts.google.com/o/oauth2/v2/auth',
|
|
24
|
+
tokenUrl: 'https://oauth2.googleapis.com/token',
|
|
25
|
+
revokeUrl: 'https://oauth2.googleapis.com/revoke',
|
|
26
|
+
defaultScopes: ['openid', 'email', 'profile'],
|
|
27
|
+
clientFile: 'google.json'
|
|
28
|
+
},
|
|
29
|
+
aws: {
|
|
30
|
+
type: 'api-key',
|
|
31
|
+
fields: ['accessKeyId', 'secretAccessKey', 'region'],
|
|
32
|
+
fieldLabels: ['AWS Access Key ID', 'AWS Secret Access Key', 'Default Region']
|
|
33
|
+
},
|
|
34
|
+
cloudflare: {
|
|
35
|
+
type: 'api-key',
|
|
36
|
+
fields: ['apiToken'],
|
|
37
|
+
fieldLabels: ['Cloudflare API Token']
|
|
38
|
+
},
|
|
39
|
+
dokploy: {
|
|
40
|
+
type: 'api-key',
|
|
41
|
+
fields: ['apiUrl', 'apiToken'],
|
|
42
|
+
fieldLabels: ['Dokploy API URL', 'Dokploy API Token']
|
|
43
|
+
},
|
|
44
|
+
namecheap: {
|
|
45
|
+
type: 'api-key',
|
|
46
|
+
fields: ['apiUser', 'apiKey', 'clientIp'],
|
|
47
|
+
fieldLabels: ['Namecheap API User', 'API Key', 'Whitelisted Client IP']
|
|
48
|
+
},
|
|
49
|
+
flowroute: {
|
|
50
|
+
type: 'api-key',
|
|
51
|
+
fields: ['accessKey', 'secretKey'],
|
|
52
|
+
fieldLabels: ['Flowroute Access Key', 'Secret Key']
|
|
53
|
+
},
|
|
54
|
+
mailu: {
|
|
55
|
+
type: 'api-key',
|
|
56
|
+
fields: ['apiUrl', 'apiKey'],
|
|
57
|
+
fieldLabels: ['Mailu API URL', 'API Key']
|
|
58
|
+
}
|
|
59
|
+
};
|
|
60
|
+
|
|
61
|
+
/**
|
|
62
|
+
* Read a credential file from ~/.devutils/auth/<service>.json.
|
|
63
|
+
* Returns the parsed JSON content, or null if the file is missing or invalid.
|
|
64
|
+
*
|
|
65
|
+
* @param {string} service - The service name (e.g., 'google', 'aws').
|
|
66
|
+
* @returns {object|null} The parsed credential data, or null.
|
|
67
|
+
*/
|
|
68
|
+
function readCredential(service) {
|
|
69
|
+
const filePath = path.join(AUTH_DIR, `${service}.json`);
|
|
70
|
+
try {
|
|
71
|
+
const raw = fs.readFileSync(filePath, 'utf8');
|
|
72
|
+
return JSON.parse(raw);
|
|
73
|
+
} catch {
|
|
74
|
+
return null;
|
|
75
|
+
}
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
/**
|
|
79
|
+
* Determine the status of a credential.
|
|
80
|
+
* - 'missing' means no credential file exists.
|
|
81
|
+
* - 'valid' means the credential exists and (for OAuth) is not expired.
|
|
82
|
+
* - 'expired' means the OAuth token's expiresAt is in the past.
|
|
83
|
+
* - 'unknown' means the credential exists but can't be evaluated.
|
|
84
|
+
*
|
|
85
|
+
* @param {object|null} credential - The parsed credential data from readCredential().
|
|
86
|
+
* @returns {string} One of 'missing', 'valid', 'expired', 'unknown'.
|
|
87
|
+
*/
|
|
88
|
+
function getTokenStatus(credential) {
|
|
89
|
+
if (!credential) return 'missing';
|
|
90
|
+
if (credential.type === 'api-key') return 'valid';
|
|
91
|
+
if (credential.type === 'oauth') {
|
|
92
|
+
if (!credential.expiresAt) return 'unknown';
|
|
93
|
+
return new Date(credential.expiresAt) > new Date() ? 'valid' : 'expired';
|
|
94
|
+
}
|
|
95
|
+
return 'unknown';
|
|
96
|
+
}
|
|
97
|
+
|
|
98
|
+
/**
|
|
99
|
+
* Check if a field name looks like it holds sensitive data.
|
|
100
|
+
* Fields with "secret", "key", "token", or "password" in the name
|
|
101
|
+
* should be masked in output and use password-style input.
|
|
102
|
+
*
|
|
103
|
+
* @param {string} fieldName - The field name to check.
|
|
104
|
+
* @returns {boolean} True if the field is sensitive.
|
|
105
|
+
*/
|
|
106
|
+
function isSensitiveField(fieldName) {
|
|
107
|
+
const lower = fieldName.toLowerCase();
|
|
108
|
+
return lower.includes('secret') ||
|
|
109
|
+
lower.includes('key') ||
|
|
110
|
+
lower.includes('token') ||
|
|
111
|
+
lower.includes('password');
|
|
112
|
+
}
|
|
113
|
+
|
|
114
|
+
/**
|
|
115
|
+
* Mask a sensitive value for display.
|
|
116
|
+
* Shows the first 4 and last 3 characters for partially-sensitive values,
|
|
117
|
+
* or '****' for fully-sensitive ones.
|
|
118
|
+
*
|
|
119
|
+
* @param {string} value - The value to mask.
|
|
120
|
+
* @param {boolean} fullMask - If true, mask the entire value with '****'.
|
|
121
|
+
* @returns {string} The masked value.
|
|
122
|
+
*/
|
|
123
|
+
function maskValue(value, fullMask) {
|
|
124
|
+
if (!value || typeof value !== 'string') return '****';
|
|
125
|
+
if (fullMask) return '****';
|
|
126
|
+
if (value.length <= 8) return '****';
|
|
127
|
+
return value.substring(0, 4) + '...' + value.substring(value.length - 3);
|
|
128
|
+
}
|
|
129
|
+
|
|
130
|
+
/**
|
|
131
|
+
* Format a time difference as a human-readable string.
|
|
132
|
+
* Handles both future ("47 minutes") and past ("expired 12 minutes ago") times.
|
|
133
|
+
*
|
|
134
|
+
* @param {Date} target - The target time (e.g., expiresAt).
|
|
135
|
+
* @param {Date} now - The current time.
|
|
136
|
+
* @returns {string} Human-readable duration string.
|
|
137
|
+
*/
|
|
138
|
+
function formatTimeDiff(target, now) {
|
|
139
|
+
const diffMs = target.getTime() - now.getTime();
|
|
140
|
+
const absDiffMs = Math.abs(diffMs);
|
|
141
|
+
const isPast = diffMs < 0;
|
|
142
|
+
|
|
143
|
+
let value;
|
|
144
|
+
if (absDiffMs < 60000) {
|
|
145
|
+
value = 'less than a minute';
|
|
146
|
+
} else if (absDiffMs < 3600000) {
|
|
147
|
+
const mins = Math.floor(absDiffMs / 60000);
|
|
148
|
+
value = `${mins} minute${mins === 1 ? '' : 's'}`;
|
|
149
|
+
} else if (absDiffMs < 86400000) {
|
|
150
|
+
const hours = Math.floor(absDiffMs / 3600000);
|
|
151
|
+
value = `${hours} hour${hours === 1 ? '' : 's'}`;
|
|
152
|
+
} else {
|
|
153
|
+
const days = Math.floor(absDiffMs / 86400000);
|
|
154
|
+
value = `${days} day${days === 1 ? '' : 's'}`;
|
|
155
|
+
}
|
|
156
|
+
|
|
157
|
+
return isPast ? `expired ${value} ago` : value;
|
|
158
|
+
}
|
|
159
|
+
|
|
160
|
+
module.exports = {
|
|
161
|
+
AUTH_SERVICES,
|
|
162
|
+
AUTH_DIR,
|
|
163
|
+
CLIENTS_DIR,
|
|
164
|
+
readCredential,
|
|
165
|
+
getTokenStatus,
|
|
166
|
+
isSensitiveField,
|
|
167
|
+
maskValue,
|
|
168
|
+
formatTimeDiff
|
|
169
|
+
};
|
|
@@ -0,0 +1,104 @@
|
|
|
1
|
+
'use strict';
|
|
2
|
+
|
|
3
|
+
const {
|
|
4
|
+
AUTH_SERVICES,
|
|
5
|
+
readCredential,
|
|
6
|
+
getTokenStatus,
|
|
7
|
+
isSensitiveField,
|
|
8
|
+
maskValue,
|
|
9
|
+
formatTimeDiff
|
|
10
|
+
} = require('./services');
|
|
11
|
+
|
|
12
|
+
const meta = {
|
|
13
|
+
description: 'Show detailed auth state for one service',
|
|
14
|
+
arguments: [
|
|
15
|
+
{ name: 'service', description: 'Service name to check', required: true }
|
|
16
|
+
],
|
|
17
|
+
flags: []
|
|
18
|
+
};
|
|
19
|
+
|
|
20
|
+
/**
|
|
21
|
+
* Run the auth status command.
|
|
22
|
+
* Shows detailed credential information for a single service, including
|
|
23
|
+
* scopes and expiry for OAuth, or masked field values for API key services.
|
|
24
|
+
*
|
|
25
|
+
* @param {object} args - Parsed CLI arguments (positional, flags).
|
|
26
|
+
* @param {object} context - CLI context (output, prompt, errors).
|
|
27
|
+
*/
|
|
28
|
+
async function run(args, context) {
|
|
29
|
+
const service = args.positional[0];
|
|
30
|
+
|
|
31
|
+
if (!service) {
|
|
32
|
+
context.errors.throwError(400, 'Missing required argument: <service>. Example: dev auth status google', 'auth');
|
|
33
|
+
return;
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
const serviceConfig = AUTH_SERVICES[service];
|
|
37
|
+
if (!serviceConfig) {
|
|
38
|
+
const supported = Object.keys(AUTH_SERVICES).join(', ');
|
|
39
|
+
context.errors.throwError(400, `Unknown service '${service}'. Supported services: ${supported}`, 'auth');
|
|
40
|
+
return;
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
const credential = readCredential(service);
|
|
44
|
+
if (!credential) {
|
|
45
|
+
context.output.info(`Not authenticated with ${service}. Run "dev auth login ${service}" to connect.`);
|
|
46
|
+
return;
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
const status = getTokenStatus(credential);
|
|
50
|
+
|
|
51
|
+
if (credential.type === 'oauth') {
|
|
52
|
+
// Build detailed OAuth status
|
|
53
|
+
const now = new Date();
|
|
54
|
+
let expiresIn = null;
|
|
55
|
+
|
|
56
|
+
if (credential.expiresAt) {
|
|
57
|
+
expiresIn = formatTimeDiff(new Date(credential.expiresAt), now);
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
const result = {
|
|
61
|
+
service: service,
|
|
62
|
+
type: 'oauth',
|
|
63
|
+
status: status,
|
|
64
|
+
scopes: credential.scopes || [],
|
|
65
|
+
expiresAt: credential.expiresAt || '-',
|
|
66
|
+
expiresIn: expiresIn || '-',
|
|
67
|
+
authenticatedAt: credential.authenticatedAt || '-',
|
|
68
|
+
hasRefreshToken: !!credential.refreshToken
|
|
69
|
+
};
|
|
70
|
+
|
|
71
|
+
context.output.out(result);
|
|
72
|
+
} else if (credential.type === 'api-key') {
|
|
73
|
+
// Build detailed API key status with masked values
|
|
74
|
+
const fields = credential.credentials ? Object.keys(credential.credentials) : [];
|
|
75
|
+
const maskedValues = {};
|
|
76
|
+
|
|
77
|
+
for (const field of fields) {
|
|
78
|
+
const val = credential.credentials[field];
|
|
79
|
+
if (isSensitiveField(field)) {
|
|
80
|
+
// Fully mask sensitive fields
|
|
81
|
+
maskedValues[field] = maskValue(val, true);
|
|
82
|
+
} else {
|
|
83
|
+
// Show non-sensitive values in full (like region)
|
|
84
|
+
maskedValues[field] = val;
|
|
85
|
+
}
|
|
86
|
+
}
|
|
87
|
+
|
|
88
|
+
const result = {
|
|
89
|
+
service: service,
|
|
90
|
+
type: 'api-key',
|
|
91
|
+
status: status,
|
|
92
|
+
fields: fields,
|
|
93
|
+
maskedValues: maskedValues,
|
|
94
|
+
authenticatedAt: credential.authenticatedAt || '-'
|
|
95
|
+
};
|
|
96
|
+
|
|
97
|
+
context.output.out(result);
|
|
98
|
+
} else {
|
|
99
|
+
// Unknown credential type
|
|
100
|
+
context.output.info(`Credential file exists for ${service} but has an unrecognized type: ${credential.type}`);
|
|
101
|
+
}
|
|
102
|
+
}
|
|
103
|
+
|
|
104
|
+
module.exports = { meta, run };
|