Skip to content

Commit 327491a

Browse files
authored
refactor: clean up project structure (#61)
1 parent 3c229b3 commit 327491a

14 files changed

Lines changed: 1028 additions & 1160 deletions

File tree

auth.ts

Lines changed: 89 additions & 37 deletions
Original file line numberDiff line numberDiff line change
@@ -15,15 +15,14 @@ import {
1515
import { observable } from "@trpc/server/observable";
1616
import { Spinner } from "@std/cli/unstable-spinner";
1717
import { error } from "./util.ts";
18-
import token_storage, { tokenIsTemp } from "./token_storage.ts";
1918
import { EventSourcePolyfill } from "event-source-polyfill";
19+
import type { GlobalContext } from "./main.ts";
2020

2121
export function createTrpcClient(
22-
debug: boolean,
23-
deployUrl: string,
22+
context: GlobalContext,
2423
quiet: boolean = false,
2524
) {
26-
let storedAuth = token_storage.get();
25+
let storedAuth = tokenStorage.get();
2726

2827
// deno-lint-ignore no-explicit-any
2928
const errorLink: TRPCLink<any> = () => {
@@ -34,11 +33,11 @@ export function createTrpcClient(
3433
observer.next(value);
3534
},
3635
error(err) {
37-
if (debug) {
36+
if (context.debug) {
3837
console.error(err);
3938
}
4039
error(
41-
debug,
40+
context,
4241
err.message || Deno.inspect(err),
4342
err.meta?.response as Response | undefined,
4443
);
@@ -70,7 +69,7 @@ export function createTrpcClient(
7069
errorLink,
7170
retryLink({
7271
retry(opts) {
73-
if (debug) {
72+
if (context.debug) {
7473
console.log(opts);
7574
}
7675

@@ -82,21 +81,21 @@ export function createTrpcClient(
8281

8382
if (tokenIsTemp) {
8483
error(
85-
debug,
84+
context,
8685
"The token specified via 'DENO_DEPLOY_TOKEN' or the '--token' flag is invalid.",
8786
);
8887
}
8988

9089
if (typeof retryPromise !== "undefined") {
91-
token_storage.remove();
90+
tokenStorage.remove();
9291
error(
93-
debug,
92+
context,
9493
"Already re-attempted authorization, please re-run this command",
9594
);
9695
}
9796

98-
token_storage.remove();
99-
retryPromise = getAuth(debug, deployUrl, quiet).then((auth) => {
97+
tokenStorage.remove();
98+
retryPromise = getAuth(context, quiet).then((auth) => {
10099
storedAuth = auth;
101100
});
102101
return true;
@@ -106,7 +105,7 @@ export function createTrpcClient(
106105
// uses the httpSubscriptionLink for subscriptions
107106
condition: (op) => op.type === "subscription",
108107
false: httpBatchStreamLink({
109-
url: deployUrl + "/api",
108+
url: context.endpoint + "/api",
110109
fetch: async (url, options) => {
111110
// deno-lint-ignore no-explicit-any
112111
const response = await fetch(url, options as any);
@@ -144,7 +143,7 @@ export function createTrpcClient(
144143
transformer,
145144
}),
146145
true: httpSubscriptionLink({
147-
url: deployUrl + "/api",
146+
url: context.endpoint + "/api",
148147
EventSource: EventSourcePolyfill,
149148
async eventSourceOptions() {
150149
if (retryPromise) {
@@ -170,18 +169,17 @@ export function createTrpcClient(
170169
}
171170

172171
export async function getAuth(
173-
debug: boolean,
174-
deployUrl: string,
172+
context: GlobalContext,
175173
quiet: boolean = false,
176174
): Promise<string> {
177-
const storedAuth = token_storage.get();
175+
const storedAuth = tokenStorage.get();
178176
if (storedAuth) {
179177
return storedAuth;
180178
}
181179

182-
const { code, exchangeToken, verifier } = await interactive(debug, deployUrl);
180+
const { code, exchangeToken, verifier } = await interactive(context);
183181

184-
const authUrl = `${deployUrl}/auth?code=${code}`;
182+
const authUrl = `${context.endpoint}/auth?code=${code}`;
185183

186184
const spinner = new Spinner({
187185
message: `Visit ${authUrl} to authorize deploying your project.`,
@@ -192,31 +190,30 @@ export async function getAuth(
192190
await open(authUrl);
193191

194192
return await tokenExchange(
195-
debug,
196-
deployUrl,
193+
context,
197194
exchangeToken,
198195
verifier,
199196
spinner,
200197
quiet,
201198
);
202199
}
203200

204-
export async function interactive(debug: boolean, deployUrl: string): Promise<
201+
export async function interactive(context: GlobalContext): Promise<
205202
{ code: string; exchangeToken: string; verifier: string }
206203
> {
207204
const verifier = crypto.randomUUID();
208205
const data = (new TextEncoder()).encode(verifier);
209206
const hash = await crypto.subtle.digest("SHA-256", data);
210207
const challenge = encodeBase64(hash);
211208

212-
const res = await fetch(`${deployUrl}/auth/interactive`, {
209+
const res = await fetch(`${context.endpoint}/auth/interactive`, {
213210
method: "POST",
214211
body: JSON.stringify({ challenge }),
215212
});
216213

217214
if (!res.ok) {
218215
console.error("An error occurred during authentication, exiting...");
219-
if (debug) {
216+
if (context.debug) {
220217
console.log(res);
221218
console.log(await res.json());
222219
}
@@ -233,16 +230,15 @@ export async function interactive(debug: boolean, deployUrl: string): Promise<
233230
}
234231

235232
export function tokenExchange(
236-
debug: boolean,
237-
deployUrl: string,
233+
context: GlobalContext,
238234
exchangeToken: string,
239235
verifier: string,
240236
spinner: Spinner,
241237
quiet: boolean,
242238
): Promise<string> {
243239
return new Promise((resolve) => {
244240
const interval = setInterval(async () => {
245-
const res = await fetch(`${deployUrl}/auth/exchange`, {
241+
const res = await fetch(`${context.endpoint}/auth/exchange`, {
246242
method: "POST",
247243
body: JSON.stringify({
248244
exchangeToken,
@@ -261,7 +257,7 @@ export function tokenExchange(
261257
);
262258
}
263259
clearInterval(interval);
264-
token_storage.set(token);
260+
tokenStorage.set(token);
265261
resolve(token);
266262
} else {
267263
const err = await res.json();
@@ -273,23 +269,22 @@ export function tokenExchange(
273269
) {
274270
clearInterval(interval);
275271
spinner.stop();
276-
error(debug, err.message, res);
272+
error(context, err.message, res);
277273
}
278274
}
279275
}, 2000);
280276
});
281277
}
282278

283279
export async function authedFetch(
284-
debug: boolean,
285-
deployUrl: string,
280+
context: GlobalContext,
286281
endpoint: string,
287282
init: RequestInit,
288283
) {
289-
let auth = await token_storage.get();
284+
let auth = await tokenStorage.get();
290285

291286
if (!auth) {
292-
auth = await getAuth(debug, deployUrl);
287+
auth = await getAuth(context);
293288
}
294289

295290
const headers = new Headers(init.headers);
@@ -298,7 +293,7 @@ export async function authedFetch(
298293
`token=${auth}; deno_auth_ghid=force`,
299294
);
300295

301-
const url = new URL(endpoint, deployUrl);
296+
const url = new URL(endpoint, context.endpoint);
302297

303298
let fallbackBody: ReadableStream | undefined;
304299
if (init.body instanceof ReadableStream) {
@@ -314,8 +309,8 @@ export async function authedFetch(
314309

315310
if (res.status === 401) {
316311
console.log(await res.text());
317-
token_storage.remove();
318-
auth = await getAuth(debug, deployUrl);
312+
tokenStorage.remove();
313+
auth = await getAuth(context);
319314

320315
const headers = new Headers(init.headers);
321316
headers.set(
@@ -330,11 +325,68 @@ export async function authedFetch(
330325

331326
if (retryRes.status === 401) {
332327
const err = await retryRes.json();
333-
error(debug, `unexpected authentication failure\n${err.message}`);
328+
error(context, `unexpected authentication failure\n${err.message}`);
334329
} else {
335330
return retryRes;
336331
}
337332
} else {
338333
return res;
339334
}
340335
}
336+
337+
let cachedToken: string | null = null;
338+
export let tokenIsTemp = false;
339+
let cannotInteractWithKeychain = false;
340+
341+
const KEYCHAIN_WARNING =
342+
"Unable to interact with keychain.\nThe authentication will not be stored and will only work on this execution.";
343+
344+
export const tokenStorage = {
345+
get(): string | null {
346+
if (cachedToken) {
347+
return cachedToken;
348+
} else {
349+
try {
350+
// @ts-ignore deno internals
351+
return Deno[Deno.internal].core.ops.op_deploy_token_get();
352+
} catch {
353+
if (!cannotInteractWithKeychain) {
354+
cannotInteractWithKeychain = true;
355+
console.log(KEYCHAIN_WARNING);
356+
}
357+
return null;
358+
}
359+
}
360+
},
361+
set(token: string, temp: boolean = false) {
362+
cachedToken = token;
363+
if (!temp) {
364+
try {
365+
// @ts-ignore deno internals
366+
Deno[Deno.internal].core.ops.op_deploy_token_set(token);
367+
} catch {
368+
if (!cannotInteractWithKeychain) {
369+
cannotInteractWithKeychain = true;
370+
console.log(KEYCHAIN_WARNING);
371+
}
372+
}
373+
} else {
374+
tokenIsTemp = temp;
375+
}
376+
},
377+
remove() {
378+
if (tokenIsTemp) {
379+
return;
380+
}
381+
cachedToken = null;
382+
try {
383+
// @ts-ignore deno internals
384+
Deno[Deno.internal].core.ops.op_deploy_token_delete();
385+
} catch {
386+
if (!cannotInteractWithKeychain) {
387+
cannotInteractWithKeychain = true;
388+
console.log(KEYCHAIN_WARNING);
389+
}
390+
}
391+
},
392+
};

0 commit comments

Comments
 (0)