add register and login endpoints

This commit is contained in:
StarAppeal
2024-12-02 20:36:46 +01:00
parent 7ce0e853e7
commit 10a7c37fa9
8 changed files with 1068 additions and 20 deletions
+965
View File
File diff suppressed because it is too large Load Diff
+2
View File
@@ -14,11 +14,13 @@
"license": "MIT",
"description": "",
"dependencies": {
"@types/bcrypt": "^5.0.2",
"@types/express": "^4.17.21",
"@types/jsonwebtoken": "^9.0.5",
"@types/node": "^20.11.19",
"@types/ws": "^8.5.10",
"axios": "^1.7.7",
"bcrypt": "^5.1.1",
"cors": "^2.8.5",
"dotenv": "^16.4.4",
"express": "5.0.0",
+7 -16
View File
@@ -6,11 +6,12 @@ import mongoose from "mongoose";
export interface IUser {
name: string,
password?: string,
uuid: string,
id: ObjectId,
config: UserConfig,
lastState: MatrixState,
spotifyConfig: SpotifyConfig,
lastState?: MatrixState,
spotifyConfig?: SpotifyConfig,
timezone: string
location: string
}
@@ -56,6 +57,10 @@ const userSchema = new mongoose.Schema<IUser>({
type: String,
required: true,
},
password: {
type: String,
required: true,
},
uuid: {
type: String,
required: true,
@@ -78,70 +83,56 @@ const userSchema = new mongoose.Schema<IUser>({
global: {
mode: {
type: String,
required: true,
},
brightness: {
type: Number,
required: true,
},
},
text: {
text: {
type: String,
required: true,
},
align: {
type: String,
required: true,
},
speed: {
type: Number,
required: true,
},
size: {
type: Number,
required: true,
},
color: {
type: [Number],
required: true,
},
},
image: {
image: {
type: String,
required: true,
},
},
clock: {
color: {
type: [Number],
required: true,
},
},
music: {
fullscreen: {
type: Boolean,
required: true,
}
}
},
spotifyConfig: {
accessToken: {
type: String,
required: true,
},
refreshToken: {
type: String,
required: true,
},
expirationDate: {
type: Date,
required: true,
},
scope: {
type: String,
required: true,
},
},
timezone: {
+8
View File
@@ -35,4 +35,12 @@ export class UserService {
public async getUserByUUID(uuid: string): Promise<IUser | null> {
return await UserModel.findOne({uuid}).exec();
}
public async getUserByName(name: string): Promise<IUser | null> {
return await UserModel.findOne({name}).exec();
}
public async createUser(user: IUser): Promise<IUser> {
return await UserModel.create(user);
}
}
+4 -2
View File
@@ -6,10 +6,10 @@ import {authenticateJwt} from "./rest/middleware/authenticateJwt";
import {JwtTokenPropertiesExtractor} from "./rest/jwtTokenPropertiesExtractor";
import cors from "cors";
import {SpotifyTokenGenerator} from "./rest/spotifyTokenGenerator";
import {RestAuth} from "./rest/auth";
const app = express();
const port = process.env.PORT || 3000;
console.log("server startet");
const server = app.listen(port, () => {
console.log(`Server is running on port ${port}`);
});
@@ -26,6 +26,7 @@ app.use(express.json({limit: "15mb"}));
const webSocketServer = new ExtendedWebSocketServer(server);
const restWebSocket = new RestWebSocket(webSocketServer);
const restUser = new RestUser();
const auth = new RestAuth();
const jwtTokenPropertiesExtractor = new JwtTokenPropertiesExtractor();
const spotify = new SpotifyTokenGenerator();
@@ -36,5 +37,6 @@ app.use(
authenticateJwt,
jwtTokenPropertiesExtractor.createRouter(),
);
app.use("/api/spotify", authenticateJwt, spotify.createRouter());
app.use("/api/auth", auth.createRouter());
+72
View File
@@ -0,0 +1,72 @@
import express from "express";
import {UserService} from "../db/services/db/UserService";
import {IUser} from "../db/models/user";
import {ObjectId} from "mongodb";
import {JwtAuthenticator} from "../utils/jwtAuthenticator";
import bcrypt from "bcrypt";
export class RestAuth {
public createRouter() {
const router = express.Router();
router.put("/register", async (req, res) => {
const username = req.body.username;
const timezone = req.body.timezone;
const location = req.body.location;
const password = req.body.password;
const userService = await UserService.create();
const user = await userService.getUserByName(username);
if (user) {
res.status(409).send({message: "Username already exists"});
} else {
const hashedPassword = await bcrypt.hash(password, 10);
const newUser: IUser = {
name: username,
password: hashedPassword,
uuid: crypto.randomUUID(),
id: ObjectId.createFromTime(Date.now()),
config: {
isVisible: false,
isAdmin: false,
canBeModified: false
},
timezone,
location
};
const result = await userService.createUser(newUser);
result.password = undefined;
res.status(201).send({success: true, user: result});
}
});
router.post("/login", async (req, res) => {
const username = req.body.username;
const password = req.body.password;
const userService = await UserService.create();
const user = await userService.getUserByName(username);
if (!user) {
res.status(404).send({success: false, message: "User not found"});
return;
}
const isValid = await bcrypt.compare(password, user.password!);
if (!isValid) {
res.status(401).send({success: false, message: "Invalid password"});
return;
}
// generate JWT token here
const jwtToken = new JwtAuthenticator(
process.env.SECRET_KEY!,
).generateToken({username: user.name, id: user.id, uuid: user.uuid});
res.status(200).send({success: true, token: jwtToken});
});
return router;
}
}
+4
View File
@@ -17,4 +17,8 @@ export class JwtAuthenticator {
return null;
}
public generateToken(payload: object): string {
return jwt.sign(payload, this.secret);
}
}
+6 -2
View File
@@ -97,13 +97,17 @@ export class WebsocketEventHandler {
console.log("Checking Spotify")
const user = this.webSocket.user;
const spotifyConfig = user.spotifyConfig;
if (!spotifyConfig) {
console.log("No Spotify config found");
return;
}
if (Date.now() > spotifyConfig.expirationDate.getTime()) {
console.log("Token expired");
const token = await new SpotifyTokenService().refreshToken(spotifyConfig.refreshToken);
user.spotifyConfig = {
// use old refresh token because you don't get a new one
refreshToken: user.spotifyConfig.refreshToken,
refreshToken: user.spotifyConfig!.refreshToken,
accessToken: token.access_token,
expirationDate: new Date(Date.now() + token.expires_in * 1000),
scope: token.scope,
@@ -112,7 +116,7 @@ export class WebsocketEventHandler {
await userService.updateUser(user);
console.log("Token refreshed and database updated");
}
const musicData = await getCurrentlyPlaying(user.spotifyConfig.accessToken);
const musicData = await getCurrentlyPlaying(user.spotifyConfig!.accessToken);
this.webSocket.send(JSON.stringify({
type: "SPOTIFY_UPDATE",