Skip to content

Commit

Permalink
Merge pull request #26 from brandonnorsworthy/guest-auth
Browse files Browse the repository at this point in the history
added guest login and register flow
  • Loading branch information
brandonnorsworthy authored Sep 15, 2024
2 parents 902fe10 + e569958 commit 985d220
Show file tree
Hide file tree
Showing 5 changed files with 120 additions and 2 deletions.
47 changes: 47 additions & 0 deletions controllers/auth.controller.ts
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,37 @@ export default {
}
},

registerGuest: async (request: Request, response: Response) => {
try {
const { username, password } = request.body;
const userId = (request as AuthenticatedRequest).tokenData.userId;

const existingUser = await userService.getUserById(userId);

if (!existingUser || existingUser.role !== 'guest') {
return response.status(401).json({ error: 'Only guests can register through this endpoint' });
}

const userWithUsername = await userService.getUserByUsername(username);

if (userWithUsername !== null) {
return response.status(400).json({ error: 'Username already taken' });
}

const updatedUser = await authService.registerGuest(userId, username, password);
const token = await authService.createTokenSession(updatedUser, password);

if (!token) {
throw new Error('Error creating token session');
}

return response.status(200).json({ token });
} catch (error) {
console.error('Error during guest registration:', error);
return response.status(500).send('An unexpected error occurred while registering as a guest');
}
},

login: async (request: Request, response: Response) => {
try {
const { username, password } = request.body;
Expand All @@ -51,6 +82,22 @@ export default {
}
},

guestLogin: async (request: Request, response: Response) => {
try {
const newUser = await authService.loginGuest();
const token = await authService.createGuestTokenSession(newUser);

if (!token) {
throw new Error('Error creating token session');
}

response.status(201).json({ token });
} catch (error) {
console.error('Error during guest login:', error);
return response.status(500).send('An unexpected error occurred while logging in as guest');
}
},

token: async (request: Request, response: Response) => {
try {
const { userId } = (request as AuthenticatedRequest).tokenData;
Expand Down
4 changes: 3 additions & 1 deletion database/init.sql
Original file line number Diff line number Diff line change
Expand Up @@ -66,7 +66,9 @@ CREATE TABLE quests (
INSERT INTO roles (name) VALUES
('user'),
('moderator'),
('admin');
('admin'),
('guest');


-- Insert categories into categories table
INSERT INTO categories (name) VALUES
Expand Down
2 changes: 1 addition & 1 deletion models/role.ts
Original file line number Diff line number Diff line change
@@ -1,3 +1,3 @@
type Role = "admin" | "moderator" | "user";
type Role = "admin" | "moderator" | "user" | "guest";

export default Role;
11 changes: 11 additions & 0 deletions routes/auth.router.ts
Original file line number Diff line number Diff line change
Expand Up @@ -21,15 +21,26 @@ authRouter.post(
validateBody(authSchema.register),
authController.register
);
authRouter.post(
'/register-guest',
validateBody(authSchema.register),
authenticate,
authController.registerGuest
);
authRouter.post(
'/login',
validateBody(authSchema.login),
authController.login
);
authRouter.post(
'/login-guest',
authController.guestLogin,
);
authRouter.post(
'/token',
authenticate,
authController.token
);


export default authRouter;
58 changes: 58 additions & 0 deletions services/auth.service.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ import Role from "../models/role";
import User, { metadata } from "../models/user";
import { comparePassword, hashPassword } from "../utils/passwordHash";
import { signToken } from "../utils/signToken";
import crypto from 'crypto';

export default {
register: async (username: string, password: string): Promise<User> => {
Expand All @@ -20,6 +21,58 @@ export default {
}
},

registerGuest: async (userId: number, username: string, password: string): Promise<User> => {
try {
const passwordHash = await hashPassword(password);

const queryString = `
UPDATE users
SET username = $1, password = $2, role_id = (SELECT id FROM roles WHERE name = 'user' LIMIT 1)
WHERE id = $3
RETURNING *
`;

const result = await executeQuery(queryString, [username, passwordHash, userId], true);

if (!result) {
throw new Error('Failed to update guest user to registered user');
}

return result;
} catch (error) {
console.error('Error during guest-to-user registration:', error);
throw new Error('Error during guest registration');
}
},

loginGuest: async (): Promise<User> => {
try {
const guestIdentifier = `anon-${crypto.randomBytes(12).toString('hex')}`;

const queryString = `
WITH inserted_user AS (
INSERT INTO users (username, role_id)
VALUES ($1, (SELECT id FROM roles WHERE name = 'guest' LIMIT 1))
RETURNING *
)
SELECT inserted_user.*, roles.name AS role
FROM inserted_user
JOIN roles ON inserted_user.role_id = roles.id
`;

const result = await executeQuery(queryString, [guestIdentifier], true);

if (!result || result.length === 0) {
throw new Error('Failed to insert guest user');
}

return result;
} catch (error) {
console.error('Error during guest login:', error);
throw new Error('Error during guest login');
}
},

createTokenSession: async (user: User, plaintextPassword: string): Promise<string | null> => {
const passwordsMatch = await comparePassword(plaintextPassword, user.password);

Expand All @@ -31,6 +84,11 @@ export default {
return signToken(tokenData);
},

createGuestTokenSession: async (user: User): Promise<string> => {
const tokenData = { userId: user.id, username: 'Anonymous', role: user.role, metadata: user.metadata };
return signToken(tokenData);
},

refreshToken: (userId: number, username: string, role: Role, metadata: metadata): string => {
const tokenData = { userId, username, role, metadata };

Expand Down

0 comments on commit 985d220

Please sign in to comment.