-
Notifications
You must be signed in to change notification settings - Fork 4
Aligned command with tailscale login flow #428
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: staging
Are you sure you want to change the base?
Changes from all commits
5991220
ceb85cb
4a067b6
7a7cff1
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1 +1 @@ | ||
sha256-23Yx1RJcaNEL1YmNz/LRFYL+5g++B+aoT0CSSbreAx8= | ||
sha256-XCPXt+ESgufgJBBTvy+TZBjcovFef4pW/E0f4/JaAc0= |
Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,35 +1,24 @@ | ||
import type PolykeyClient from 'polykey/PolykeyClient.js'; | ||
import type { | ||
TokenPayloadEncoded, | ||
TokenProtectedHeaderEncoded, | ||
TokenSignatureEncoded, | ||
} from 'polykey/tokens/types.js'; | ||
import type { IdentityRequestData } from 'polykey/client/types.js'; | ||
import CommandPolykey from '../CommandPolykey.js'; | ||
import * as binProcessors from '../utils/processors.js'; | ||
import * as binParsers from '../utils/parsers.js'; | ||
import * as binUtils from '../utils/index.js'; | ||
import * as binOptions from '../utils/options.js'; | ||
import * as errors from '../errors.js'; | ||
|
||
class CommandLogin extends CommandPolykey { | ||
constructor(...args: ConstructorParameters<typeof CommandPolykey>) { | ||
super(...args); | ||
this.name('login'); | ||
this.description('Login to a platform with Polykey identity'); | ||
this.argument( | ||
'<token>', | ||
'Token provided by platform for logging in', | ||
binParsers.parseCompactJWT, | ||
); | ||
this.argument('<url>', 'The URL to login using Polykey'); | ||
this.addOption(binOptions.nodeId); | ||
this.addOption(binOptions.clientHost); | ||
this.addOption(binOptions.clientPort); | ||
this.action(async (encodedToken, options) => { | ||
this.addOption(binOptions.returnURLPath); | ||
this.action(async (url: string, options) => { | ||
const { default: PolykeyClient } = await import( | ||
'polykey/PolykeyClient.js' | ||
); | ||
const tokensUtils = await import('polykey/tokens/utils.js'); | ||
const { default: open } = await import('open'); | ||
const clientOptions = await binProcessors.processClientOptions( | ||
options.nodePath, | ||
options.nodeId, | ||
|
@@ -58,51 +47,33 @@ class CommandLogin extends CommandPolykey { | |
logger: this.logger.getChild(PolykeyClient.name), | ||
}); | ||
|
||
// Create a JSON representation of the encoded header | ||
const [protectedHeader, payload, signature] = encodedToken; | ||
const incomingTokenEncoded = { | ||
payload: payload as TokenPayloadEncoded, | ||
signatures: [ | ||
{ | ||
protected: protectedHeader as TokenProtectedHeaderEncoded, | ||
signature: signature as TokenSignatureEncoded, | ||
}, | ||
], | ||
}; | ||
|
||
// Get it verified and signed by the agent | ||
// Get a signed token by the agent | ||
const response = await binUtils.retryAuthentication( | ||
(auth) => | ||
pkClient.rpcClient.methods.authSignToken({ | ||
metadata: auth, | ||
...incomingTokenEncoded, | ||
}), | ||
pkClient.rpcClient.methods.authIdentityToken({ metadata: auth }), | ||
meta, | ||
); | ||
|
||
// Send the returned JWT to the returnURL provided by the initial token | ||
const compactHeader = binUtils.jsonToCompactJWT(response); | ||
const incomingPayload = | ||
tokensUtils.parseTokenPayload<IdentityRequestData>(payload); | ||
let result: Response; | ||
const targetURL = new URL( | ||
url.endsWith('/') ? url.slice(0, url.length) : url, | ||
); | ||
const subPath: string = options.returnURLPath ?? '/oauth2/oidc'; | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I don't think this check is needed anymore, because the command only expects the url now. So this can just be |
||
targetURL.pathname = subPath.startsWith('/') ? subPath : `/${subPath}`; | ||
targetURL.searchParams.append('token', compactHeader); | ||
|
||
// Print out the URL to stderr | ||
process.stderr.write( | ||
`Open the following URL in your browser:\n\t${targetURL}\n`, | ||
); | ||
|
||
// Try to open the URL in the browser | ||
try { | ||
result = await fetch(incomingPayload.returnURL, { | ||
method: 'POST', | ||
headers: { 'Content-Type': 'application/json' }, | ||
body: JSON.stringify({ token: compactHeader }), | ||
}); | ||
process.stderr.write('Opening URL in browser...\n'); | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. This is all client facing code as the user will be reading this of course. So I think for clarity this should be changed to |
||
await open(targetURL.toString()); | ||
} catch (e) { | ||
throw new errors.ErrorPolykeyCLILoginFailed( | ||
'Failed to send token to return url', | ||
{ cause: e }, | ||
); | ||
} | ||
|
||
// Handle non-200 response | ||
if (!result.ok) { | ||
throw new errors.ErrorPolykeyCLILoginFailed( | ||
`Return url returned failure with code ${result.status}`, | ||
); | ||
process.stderr.write(`Failed to open browser: ${e.message}\n`); | ||
} | ||
} finally { | ||
if (pkClient! != null) await pkClient.stop(); | ||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This should be `Login to a platform with your Polykey identity', just for user clarity.