@clipdone/cli 0.1.2 → 0.1.3
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/bin/clipdone.js +30 -5
- package/package.json +1 -1
package/bin/clipdone.js
CHANGED
|
@@ -148,8 +148,9 @@ var OAUTH_AUTHORIZE_PATH = "/api/auth/oauth2/authorize";
|
|
|
148
148
|
var OAUTH_REGISTER_PATH = "/api/auth/oauth2/register";
|
|
149
149
|
var OAUTH_TOKEN_PATH = "/api/auth/oauth2/token";
|
|
150
150
|
var OAUTH_REVOKE_PATH = "/api/auth/oauth2/revoke";
|
|
151
|
-
var OAUTH_CLIENT_REGISTRATION_VERSION =
|
|
151
|
+
var OAUTH_CLIENT_REGISTRATION_VERSION = 3;
|
|
152
152
|
var OAUTH_LOOPBACK_PORTS = [59852, 59853, 59854, 59855, 59856, 59857, 59858, 59859];
|
|
153
|
+
var OAUTH_CALLBACK_PATH = "/agents/callback";
|
|
153
154
|
var PRODUCTION_APP_URL = "https://app.clipdone.app";
|
|
154
155
|
var LOCAL_APP_URL = "http://localhost:3000";
|
|
155
156
|
var REQUEST_TIMEOUT_MS = 15e3;
|
|
@@ -537,7 +538,7 @@ async function oauthRegisterClient({ scope }) {
|
|
|
537
538
|
},
|
|
538
539
|
body: JSON.stringify({
|
|
539
540
|
client_name: "ClipDone CLI",
|
|
540
|
-
redirect_uris:
|
|
541
|
+
redirect_uris: [new URL(OAUTH_CALLBACK_PATH, appBase()).toString()],
|
|
541
542
|
grant_types: ["authorization_code", "refresh_token"],
|
|
542
543
|
response_types: ["code"],
|
|
543
544
|
token_endpoint_auth_method: "none",
|
|
@@ -955,6 +956,9 @@ function parseLegacyCommand(args, parts) {
|
|
|
955
956
|
}
|
|
956
957
|
function parseTopLevelCommand(args) {
|
|
957
958
|
const parts = Array.isArray(args._) ? args._ : [];
|
|
959
|
+
if (args.version === true || parts[0] === "version") {
|
|
960
|
+
return { key: "version" };
|
|
961
|
+
}
|
|
958
962
|
if (parts.length === 0 || parts[0] === "help") {
|
|
959
963
|
return { key: "help" };
|
|
960
964
|
}
|
|
@@ -1044,6 +1048,7 @@ function printHelp() {
|
|
|
1044
1048
|
writeLine();
|
|
1045
1049
|
writeLine("Useful options:");
|
|
1046
1050
|
writeLine(" --help Show command help");
|
|
1051
|
+
writeLine(" --version Show the installed CLI version");
|
|
1047
1052
|
if (devHelp) {
|
|
1048
1053
|
writeLine();
|
|
1049
1054
|
writeLine("Development target options:");
|
|
@@ -1060,6 +1065,10 @@ function readJsonFile(filePath) {
|
|
|
1060
1065
|
throw new Error(`Could not read JSON from ${filePath}: ${error instanceof Error ? error.message : String(error)}`);
|
|
1061
1066
|
}
|
|
1062
1067
|
}
|
|
1068
|
+
function cliVersion() {
|
|
1069
|
+
const packageJson = readJsonFile(join(BIN_DIR, "..", "package.json"));
|
|
1070
|
+
return normalizeString(packageJson?.version) || "0.0.0";
|
|
1071
|
+
}
|
|
1063
1072
|
function normalizeFeedbackNotes(value) {
|
|
1064
1073
|
if (!value) return [];
|
|
1065
1074
|
if (Array.isArray(value)) return value;
|
|
@@ -1106,6 +1115,16 @@ function base64UrlEncode(bytes) {
|
|
|
1106
1115
|
function randomState() {
|
|
1107
1116
|
return base64UrlEncode(webcrypto.getRandomValues(new Uint8Array(24)));
|
|
1108
1117
|
}
|
|
1118
|
+
function buildOAuthState(csrfState, localRedirectUri) {
|
|
1119
|
+
return base64UrlEncode(
|
|
1120
|
+
new TextEncoder().encode(
|
|
1121
|
+
JSON.stringify({
|
|
1122
|
+
csrfState,
|
|
1123
|
+
localRedirectUri
|
|
1124
|
+
})
|
|
1125
|
+
)
|
|
1126
|
+
);
|
|
1127
|
+
}
|
|
1109
1128
|
function generateCodeVerifier() {
|
|
1110
1129
|
return base64UrlEncode(webcrypto.getRandomValues(new Uint8Array(48)));
|
|
1111
1130
|
}
|
|
@@ -1139,11 +1158,13 @@ async function listenOnLoopbackPort() {
|
|
|
1139
1158
|
async function login(args) {
|
|
1140
1159
|
const authConfig = { resource: API_OAUTH_RESOURCE, scope: API_OAUTH_SCOPES.join(" ") };
|
|
1141
1160
|
const oauthClient = await resolveOAuthClient(authConfig);
|
|
1142
|
-
const
|
|
1161
|
+
const csrfState = randomState();
|
|
1143
1162
|
const codeVerifier = generateCodeVerifier();
|
|
1144
1163
|
const codeChallenge = await generateCodeChallenge(codeVerifier);
|
|
1145
1164
|
const { server, port } = await listenOnLoopbackPort();
|
|
1146
|
-
const
|
|
1165
|
+
const localRedirectUri = `http://127.0.0.1:${port}/callback`;
|
|
1166
|
+
const state = buildOAuthState(csrfState, localRedirectUri);
|
|
1167
|
+
const redirectUri = new URL(OAUTH_CALLBACK_PATH, appBase()).toString();
|
|
1147
1168
|
const authUrl = new URL(OAUTH_AUTHORIZE_PATH, appBase());
|
|
1148
1169
|
authUrl.searchParams.set("client_id", oauthClient.clientId);
|
|
1149
1170
|
authUrl.searchParams.set("response_type", "code");
|
|
@@ -1166,7 +1187,7 @@ async function login(args) {
|
|
|
1166
1187
|
}, 5 * 60 * 1e3);
|
|
1167
1188
|
server.on("request", async (req, res) => {
|
|
1168
1189
|
try {
|
|
1169
|
-
const url = new URL(req.url || "/",
|
|
1190
|
+
const url = new URL(req.url || "/", localRedirectUri);
|
|
1170
1191
|
if (url.pathname !== "/callback") {
|
|
1171
1192
|
res.writeHead(404).end("Not found");
|
|
1172
1193
|
return;
|
|
@@ -1332,6 +1353,10 @@ async function main() {
|
|
|
1332
1353
|
printHelp();
|
|
1333
1354
|
return;
|
|
1334
1355
|
}
|
|
1356
|
+
if (command === "version") {
|
|
1357
|
+
writeLine(cliVersion());
|
|
1358
|
+
return;
|
|
1359
|
+
}
|
|
1335
1360
|
if (command === "login") return await login(args);
|
|
1336
1361
|
if (command === "logout") {
|
|
1337
1362
|
if (!hasStoredAuth()) {
|