parent
228a710f1e
commit
878a28c89f
|
|
@ -20,6 +20,7 @@ CREATE TABLE "user_tokens" (
|
||||||
"id" UUID PRIMARY KEY DEFAULT gen_random_uuid(),
|
"id" UUID PRIMARY KEY DEFAULT gen_random_uuid(),
|
||||||
"user_id" UUID NOT NULL,
|
"user_id" UUID NOT NULL,
|
||||||
"token" CHARACTER VARYING (1000) NOT NULL,
|
"token" CHARACTER VARYING (1000) NOT NULL,
|
||||||
|
"realm" CHARACTER VARYING (10) NOT NULL CHECK ("realm" IN ('invite', 'forgot')),
|
||||||
"insert_time" TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP,
|
"insert_time" TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP,
|
||||||
CONSTRAINT "user_tokens_user_fk" FOREIGN KEY ("user_id") REFERENCES "users" ("id") ON DELETE CASCADE
|
CONSTRAINT "user_tokens_user_fk" FOREIGN KEY ("user_id") REFERENCES "users" ("id") ON DELETE CASCADE
|
||||||
);
|
);
|
||||||
|
|
|
||||||
|
|
@ -13,9 +13,11 @@ WITH "created" AS (
|
||||||
SELECT "id", 'admin'
|
SELECT "id", 'admin'
|
||||||
FROM "created"
|
FROM "created"
|
||||||
)
|
)
|
||||||
INSERT INTO "user_tokens" ("user_id", "token")
|
INSERT INTO "user_tokens" ("user_id", "token", "realm")
|
||||||
SELECT "id", (SELECT string_agg (substr (c, (random() * length (c) + 1)::integer, 1), '') AS "token"
|
SELECT "id",
|
||||||
|
(SELECT string_agg (substr (c, (random() * length (c) + 1)::integer, 1), '') AS "token"
|
||||||
FROM (VALUES ('ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789')) AS x(c),
|
FROM (VALUES ('ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789')) AS x(c),
|
||||||
generate_series (1, 32))
|
generate_series (1, 32)),
|
||||||
|
'invite'
|
||||||
FROM "created"
|
FROM "created"
|
||||||
RETURNING 'https://example.com/auth/password/' || "token" AS "Password URL"
|
RETURNING 'https://example.com/auth/password/' || "token" AS "Password URL"
|
||||||
|
|
|
||||||
|
|
@ -49,8 +49,8 @@ extension ManagedUser {
|
||||||
TRUE)
|
TRUE)
|
||||||
RETURNING "id"
|
RETURNING "id"
|
||||||
)
|
)
|
||||||
INSERT INTO "user_tokens" ("user_id", "token")
|
INSERT INTO "user_tokens" ("user_id", "token", "realm")
|
||||||
SELECT "id", \(bind: token)
|
SELECT "id", \(bind: token), 'invite'
|
||||||
FROM created
|
FROM created
|
||||||
""")
|
""")
|
||||||
.run()
|
.run()
|
||||||
|
|
@ -72,8 +72,8 @@ extension ManagedUser {
|
||||||
FROM "created"
|
FROM "created"
|
||||||
CROSS JOIN unnest (\(bind: roles)) AS "role_name"
|
CROSS JOIN unnest (\(bind: roles)) AS "role_name"
|
||||||
)
|
)
|
||||||
INSERT INTO "user_tokens" ("user_id", "token")
|
INSERT INTO "user_tokens" ("user_id", "token", "realm")
|
||||||
SELECT "id", \(bind: token)
|
SELECT "id", \(bind: token), 'invite'
|
||||||
FROM "created"
|
FROM "created"
|
||||||
""")
|
""")
|
||||||
.run()
|
.run()
|
||||||
|
|
@ -121,8 +121,8 @@ extension ManagedUser {
|
||||||
|
|
||||||
public static func store (token: String, userId: UUID, on connection: any SQLDatabase) async throws {
|
public static func store (token: String, userId: UUID, on connection: any SQLDatabase) async throws {
|
||||||
try await connection.raw("""
|
try await connection.raw("""
|
||||||
INSERT INTO "user_tokens" ("user_id", "token")
|
INSERT INTO "user_tokens" ("user_id", "token", "realm")
|
||||||
VALUES (\(bind: userId), \(bind: token))
|
VALUES (\(bind: userId), \(bind: token), 'forgot')
|
||||||
""")
|
""")
|
||||||
.run()
|
.run()
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -30,7 +30,9 @@ struct UserToken: Decodable {
|
||||||
JOIN "users"
|
JOIN "users"
|
||||||
ON "users"."id" = "user_tokens"."user_id"
|
ON "users"."id" = "user_tokens"."user_id"
|
||||||
WHERE "token" = \(bind: token)
|
WHERE "token" = \(bind: token)
|
||||||
AND "insert_time" >= CURRENT_TIMESTAMP - INTERVAL '1 HOUR'
|
AND "insert_time" >= CURRENT_TIMESTAMP - CASE WHEN "realm" = 'invite'
|
||||||
|
THEN INTERVAL '1 DAY'
|
||||||
|
ELSE INTERVAL '1 HOUR' END
|
||||||
""")
|
""")
|
||||||
.first (decoding: Token.self)
|
.first (decoding: Token.self)
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -9,6 +9,8 @@ struct AuthorizationTests {
|
||||||
private func withApp(_ test: (Application) async throws -> ()) async throws {
|
private func withApp(_ test: (Application) async throws -> ()) async throws {
|
||||||
let app = try await Application.make (.testing)
|
let app = try await Application.make (.testing)
|
||||||
do {
|
do {
|
||||||
|
setenv ("BASE_URL", "http://localhost", 0)
|
||||||
|
setenv ("EMAIL_SENDER", "nobody@example.com", 0)
|
||||||
try await SampleApp.configure (app)
|
try await SampleApp.configure (app)
|
||||||
let mockDatabase = MockDatabase (eventLoop: app.eventLoopGroup.next())
|
let mockDatabase = MockDatabase (eventLoop: app.eventLoopGroup.next())
|
||||||
app.storage[Application.MockDatabaseKey.self] = mockDatabase
|
app.storage[Application.MockDatabaseKey.self] = mockDatabase
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue