tangled
alpha
login
or
join now
socksthewolf.com
/
skyscheduler
2
fork
atom
Schedule posts to Bluesky with Cloudflare workers.
skyscheduler.work
cf
tool
bsky-tool
cloudflare
bluesky
schedule
bsky
service
social-media
cloudflare-workers
2
fork
atom
overview
issues
pulls
pipelines
fix up reset passwords
also just make it look better
SocksTheWolf
2 weeks ago
26e59ce9
644d168a
+15
-35
5 changed files
expand all
collapse all
unified
split
assets
js
reset.js
src
auth
index.ts
endpoints
openapi.tsx
index.tsx
validation
accountResetSchema.ts
+1
-1
assets/js/reset.js
···
1
1
function handleResetLoad() {
2
2
if (resetToken = new URLSearchParams(window.location.search).get("token")) {
3
3
const resetTokenField = document.getElementById("resetToken");
4
4
-
const submitButton = document.getElementById("submitButton");
4
4
+
const submitButton = document.querySelector('button[type="submit"]');
5
5
if (resetTokenField && submitButton) {
6
6
resetTokenField.value = encodeURI(resetToken);
7
7
submitButton.removeAttribute("disabled");
+4
-4
src/auth/index.ts
···
5
5
import { drizzle, DrizzleD1Database } from "drizzle-orm/d1";
6
6
import { schema } from "../db";
7
7
import { BSKY_MAX_USERNAME_LENGTH, BSKY_MIN_USERNAME_LENGTH } from "../limits";
8
8
-
import { APP_NAME } from "../siteinfo";
8
8
+
import { APP_NAME, SITE_URL } from "../siteinfo";
9
9
import { Bindings } from "../types";
10
10
import { lookupBskyHandle } from "../utils/bskyApi";
11
11
import { createDMWithUser } from "../utils/bskyMsg";
12
12
13
13
-
function createPasswordResetMessage(url: string) {
13
13
+
function createPasswordResetMessage(url: string, token: string) {
14
14
return `Your ${APP_NAME} password reset url is:
15
15
-
${url}
15
15
+
${SITE_URL}/reset-password/${token}
16
16
17
17
This URL will expire in about an hour.
18
18
···
71
71
const userName = (user as any).username;
72
72
const bskyUserId = await lookupBskyHandle(userName);
73
73
if (bskyUserId !== null) {
74
74
-
const response = await createDMWithUser(env!, bskyUserId, createPasswordResetMessage(url));
74
74
+
const response = await createDMWithUser(env!, bskyUserId, createPasswordResetMessage(url, token));
75
75
if (!response)
76
76
throw new Error("FAILED_MESSAGE");
77
77
} else {
+1
-16
src/endpoints/openapi.tsx
···
5
5
import { ContextVariables } from "../auth";
6
6
import { Bindings } from "../types";
7
7
import { AccountDeleteSchema, AccountForgotSchema } from "../validation/accountForgotDeleteSchema";
8
8
-
import {
9
9
-
AccountResetSchema, PasswordResetCheckCallbackParam,
10
10
-
PasswordResetTokenParam
11
11
-
} from "../validation/accountResetSchema";
8
8
+
import { AccountResetSchema } from "../validation/accountResetSchema";
12
9
import { AccountUpdateSchema } from "../validation/accountUpdateSchema";
13
10
import { LoginSchema } from "../validation/loginSchema";
14
11
import { FileDeleteSchema } from "../validation/mediaSchema";
···
423
420
}
424
421
}
425
422
}), validator("param", CheckFileSchema));
426
426
-
427
427
-
openapiRoutes.get("/api/auth/reset-password/:id", describeRoute({
428
428
-
description: "resets a password",
429
429
-
responses: {
430
430
-
200: {
431
431
-
description: "valid token, redirect to reset"
432
432
-
},
433
433
-
404: {
434
434
-
description: "reset token is invalid"
435
435
-
}
436
436
-
}
437
437
-
}), validator("param", PasswordResetTokenParam), validator("query", PasswordResetCheckCallbackParam));
+8
src/index.tsx
···
113
113
// Reset Password route
114
114
app.get("/reset", redirectToDashIfLogin, (c) => c.html(<ResetPassword />));
115
115
116
116
+
// Reset Password Confirm route
117
117
+
app.get("/reset-password/:id", (c) => {
118
118
+
// Alternatively you can just URL rewrite this in cloudflare and it'll look
119
119
+
// 100x times better.
120
120
+
const { id } = c.req.param();
121
121
+
return c.redirect(`/api/auth/reset-password/${id}?callbackURL=%2Freset`);
122
122
+
});
123
123
+
116
124
// Startup Application
117
125
app.get("/setup", async (c) => await setupAccounts(c));
118
126
+1
-14
src/validation/accountResetSchema.ts
···
13
13
.max(MAX_DASHBOARD_PASS, "confirm password too long")
14
14
.nonempty("confirm password cannot be empty")
15
15
.nonoptional(),
16
16
-
}).refine((schema) => schema.confirmPassword === schema.password, "Passwords do not match");
17
17
-
18
18
-
// encoded strings
19
19
-
const uriComponent = z.codec(z.string(), z.string(), {
20
20
-
decode: (encodedString) => decodeURIComponent(encodedString),
21
21
-
encode: (decodedString) => encodeURIComponent(decodedString),
22
22
-
});
23
23
-
export const PasswordResetCheckCallbackParam = z.object({
24
24
-
callbackURL: z.literal(z.encode(uriComponent, "/reset"))
25
25
-
});
26
26
-
27
27
-
export const PasswordResetTokenParam = z.object({
28
28
-
id: z.string().min(20).max(64)
29
29
-
});
16
16
+
}).refine((schema) => schema.confirmPassword === schema.password, "Passwords do not match");