Skip to content
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

fix: user uuid is used instead of user id for its uniqueness #355

Merged
merged 15 commits into from
Apr 5, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
53 changes: 53 additions & 0 deletions prisma/migrations/20230405024416_user_uuid/migration.sql
Original file line number Diff line number Diff line change
@@ -0,0 +1,53 @@
/*
Warnings:

- A unique constraint covering the columns `[uuid]` on the table `User` will be added. If there are existing duplicate values, this will fail.

*/
-- PRISMA GENERATED BELOW
-- -- DropForeignKey
-- ALTER TABLE "OAuth" DROP CONSTRAINT "OAuth_userId_fkey";
--
-- -- AlterTable
-- ALTER TABLE "OAuth" ALTER COLUMN "userId" SET DATA TYPE TEXT;
--
-- -- AlterTable
-- ALTER TABLE "User" ADD COLUMN "uuid" UUID NOT NULL DEFAULT gen_random_uuid();
--
-- -- CreateIndex
-- CREATE UNIQUE INDEX "User_uuid_key" ON "User"("uuid");
--
-- -- AddForeignKey
-- ALTER TABLE "OAuth" ADD CONSTRAINT "OAuth_userId_fkey" FOREIGN KEY ("userId") REFERENCES "User"("uuid") ON DELETE CASCADE ON UPDATE CASCADE;

-- User made changes below

-- Rename old foreign key
ALTER TABLE "OAuth" RENAME CONSTRAINT "OAuth_userId_fkey" TO "OAuth_userId_old_fkey";

-- Rename old column
ALTER TABLE "OAuth" RENAME COLUMN "userId" TO "userId_old";

-- Add new column
ALTER TABLE "OAuth" ADD COLUMN "userId" UUID;

-- Add user uuid
ALTER TABLE "User" ADD COLUMN "uuid" UUID NOT NULL DEFAULT gen_random_uuid();

-- Update table "OAuth" with uuid
UPDATE "OAuth" SET "userId" = "User"."uuid" FROM "User" WHERE "OAuth"."userId_old" = "User"."id";

-- Alter table "OAuth" to make "userId" required
ALTER TABLE "OAuth" ALTER COLUMN "userId" SET NOT NULL;

-- Create index
CREATE UNIQUE INDEX "User_uuid_key" ON "User"("uuid");

-- Add new foreign key
ALTER TABLE "OAuth" ADD CONSTRAINT "OAuth_userId_fkey" FOREIGN KEY ("userId") REFERENCES "User"("uuid") ON DELETE CASCADE ON UPDATE CASCADE;

-- Drop old foreign key
ALTER TABLE "OAuth" DROP CONSTRAINT "OAuth_userId_old_fkey";

-- Drop old column
ALTER TABLE "OAuth" DROP COLUMN "userId_old";
39 changes: 20 additions & 19 deletions prisma/schema.prisma
Original file line number Diff line number Diff line change
Expand Up @@ -8,23 +8,24 @@ generator client {
}

model User {
id Int @id @default(autoincrement())
username String
password String?
avatar String?
token String
administrator Boolean @default(false)
superAdmin Boolean @default(false)
systemTheme String @default("system")
embed Json @default("{}")
ratelimit DateTime?
totpSecret String?
domains String[]
oauth OAuth[]
files File[]
urls Url[]
Invite Invite[]
Folder Folder[]
id Int @id @default(autoincrement())
uuid String @unique @default(dbgenerated("gen_random_uuid()")) @db.Uuid
username String
password String?
avatar String?
token String
administrator Boolean @default(false)
superAdmin Boolean @default(false)
systemTheme String @default("system")
embed Json @default("{}")
ratelimit DateTime?
totpSecret String?
domains String[]
oauth OAuth[]
files File[]
urls Url[]
Invite Invite[]
Folder Folder[]
IncompleteFile IncompleteFile[]
}

Expand Down Expand Up @@ -112,8 +113,8 @@ model Invite {
model OAuth {
id Int @id @default(autoincrement())
provider OauthProviders
user User @relation(fields: [userId], references: [id], onDelete: Cascade)
userId Int
user User @relation(fields: [userId], references: [uuid], onDelete: Cascade)
userId String
username String
oauthId String?
token String
Expand Down
6 changes: 3 additions & 3 deletions src/lib/middleware/withOAuth.ts
Original file line number Diff line number Diff line change
Expand Up @@ -135,7 +135,7 @@ export const withOAuth =
} else throw e;
}

res.setUserCookie(user.id);
res.setUserCookie(user.uuid);
logger.info(`User ${user.username} (${user.id}) linked account via oauth(${provider})`);

return res.redirect('/');
Expand All @@ -153,7 +153,7 @@ export const withOAuth =
},
});

res.setUserCookie(user.id);
res.setUserCookie(user.uuid);
logger.info(`User ${user.username} (${user.id}) logged in via oauth(${provider})`);

return res.redirect('/dashboard');
Expand Down Expand Up @@ -203,7 +203,7 @@ export const withOAuth =
logger.debug(`created user ${JSON.stringify(nuser)} via oauth(${provider})`);
logger.info(`Created user ${nuser.username} via oauth(${provider})`);

res.setUserCookie(nuser.id);
res.setUserCookie(nuser.uuid);
logger.info(`User ${nuser.username} (${nuser.id}) logged in via oauth(${provider})`);

return res.redirect('/dashboard');
Expand Down
12 changes: 6 additions & 6 deletions src/lib/middleware/withZipline.ts
Original file line number Diff line number Diff line change
Expand Up @@ -54,7 +54,7 @@ export type NextApiRes = NextApiResponse &
NextApiResExtraObj & {
json: (json: Record<string, unknown>, status?: number) => void;
setCookie: (name: string, value: unknown, options: CookieSerializeOptions) => void;
setUserCookie: (id: number) => void;
setUserCookie: (id: string) => void;
};

export type ZiplineApiConfig = {
Expand Down Expand Up @@ -184,7 +184,7 @@ export const withZipline =

const user = await prisma.user.findFirst({
where: {
id: Number(userId),
uuid: userId,
},
include: {
oauth: true,
Expand All @@ -202,22 +202,22 @@ export const withZipline =
}
};

res.setCookie = (name: string, value: unknown, options: CookieSerializeOptions = {}) => {
res.setCookie = (name: string, value: string, options: CookieSerializeOptions = {}) => {
if ('maxAge' in options) {
options.expires = new Date(Date.now() + options.maxAge * 1000);
options.maxAge /= 1000;
}

const signed = sign64(String(value), config.core.secret);
const signed = sign64(value, config.core.secret);

Logger.get('api').debug(`headers(${JSON.stringify(req.headers)}): cookie(${name}, ${value})`);

res.setHeader('Set-Cookie', serialize(name, signed, options));
};

res.setUserCookie = (id: number) => {
res.setUserCookie = (id: string) => {
req.cleanCookie('user');
res.setCookie('user', String(id), {
res.setCookie('user', id, {
sameSite: 'lax',
expires: new Date(Date.now() + 6.048e8 * 2),
path: '/',
Expand Down
2 changes: 1 addition & 1 deletion src/lib/utils/parser.ts
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,7 @@ export function parseString(str: string, value: ParseValue) {
continue;
}

if (['password', 'avatar'].includes(matches.groups.prop)) {
if (['password', 'avatar', 'uuid'].includes(matches.groups.prop)) {
str = replaceCharsFromString(str, '{unknown_property}', matches.index, re.lastIndex);
re.lastIndex = matches.index;
continue;
Expand Down
2 changes: 1 addition & 1 deletion src/pages/api/auth/login.ts
Original file line number Diff line number Diff line change
Expand Up @@ -56,7 +56,7 @@ async function handler(req: NextApiReq, res: NextApiRes) {
if (!success) return res.badRequest('Invalid code', { totp: true });
}

res.setUserCookie(user.id);
res.setUserCookie(user.uuid);
logger.info(`User ${user.username} (${user.id}) logged in`);

return res.json({ success: true });
Expand Down
5 changes: 3 additions & 2 deletions src/pages/oauth_error.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,8 @@ export default function OauthError({ error, provider }) {

useEffect(() => {
const interval = setInterval(() => {
setRemaining((remaining) => remaining - 1);
if (remaining > 0) setRemaining((remaining) => remaining - 1);
else clearInterval(interval);
}, 1000);

return () => clearInterval(interval);
Expand Down Expand Up @@ -43,7 +44,7 @@ export default function OauthError({ error, provider }) {
</Title>
<MutedText sx={{ fontSize: 40, fontWeight: 500 }}>{error}</MutedText>
<MutedText>
Redirecting to login in {remaining} second{remaining === 1 ? 's' : ''}
Redirecting to login in {remaining} second{remaining !== 1 ? 's' : ''}
</MutedText>
<Button component={Link} href='/dashboard'>
Head to the Dashboard
Expand Down
2 changes: 2 additions & 0 deletions src/server/decorators/postUrl.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,8 @@ function postUrlDecorator(fastify: FastifyInstance, _, done) {
done();

async function postUrl(this: FastifyReply, url: Url) {
if (!url) return true;

const nUrl = await this.server.prisma.url.update({
where: {
id: url.id,
Expand Down