feat: shared OAuth client behind access key, login/logout commands - #20
Merged
Conversation
The author maintains a shared Google Cloud client as an alternative to setting up your own project. It is gated behind an access key, which is the client secret itself: the repository ships only the client id and a sha256 of the key. Google's token endpoint rejects this client without a secret, so the gate is real rather than decorative — the shared client cannot be used without the key, no matter what the sources reveal. The hash only allows failing fast instead of sending the user through the browser with a bad key. The first-run wizard now always sets up the user's own Cloud project; the shared client is reachable only via `goodoc login --key`.
`login` authorizes without uploading anything and accepts `--key` for the shared client; `logout` drops the stored token. Adding commands turns the app into a Click group, where a variadic argument on the callback swallows the command name — `goodoc login` would be read as a file path. `upload` is therefore a real command, and DefaultCommandGroup inserts it when the first argument is neither a known command nor an option. This keeps `goodoc file.docx` working, so the Automator Quick Action needs no change.
The shared client runs in production without verification: no whitelist, but a permanent cap of 100 authorizations that only verification lifts, and verification needs a domain.
CI installs linters unpinned, so ruff 0.16 broke the build the day it shipped by widening the default rule set. Six of the nine findings are present on master as well, so this is drift rather than a regression. Pin is temporary — raising it is tracked in the backlog.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
What
Two ways to authorize goodoc:
~/.config/goodoc/credentials.jsongoodoc login --key <KEY>client.pyPlus
login/logoutcommands.The access key is the client secret
Google's token endpoint rejects this client without a secret — measured, not assumed:
Since the secret has to reach the user anyway, the key handed out is the secret. The repository ships only
CLIENT_ID(public by nature — it appears in every authorization URL) and a sha256 of the key. So the secret never enters git history, and the gate is real rather than decorative: without the key the shared client cannot be used, however carefully the sources are read. The hash exists only to fail fast instead of sending the user through the browser with a bad key.Already-authorized users are unaffected:
token.jsoncarries client id, secret and refresh token, so refreshing never touchesclient.py.Shared client limits
Production without verification — no whitelist, but a cap of 100 authorizations for the lifetime of the project, which cannot be reset. Only verification lifts it, and verification requires a domain. Hence the key, and hence "own project" being the default.
Commands became a group
Adding commands turns the app into a Click group, where a variadic argument on the callback swallows the command name —
goodoc logingets read as a file path.uploadis now a real command, andDefaultCommandGroupinserts it when the first argument is neither a known command nor an option.goodoc file.docxkeeps working, so the Automator Quick Action (goodoc "$@") needs no change. This also moves--no-openout of the global options, where it did not belong.Checks
44 passed, ruff and mypy clean.