mirror of
https://github.com/20kaushik02/spotify-manager.git
synced 2025-12-06 10:44:06 +00:00
package checks, healthcheck, lot of cookie fiddling, some logging, bug fixing
This commit is contained in:
parent
d999db53ae
commit
79060661a6
@ -1,4 +1,6 @@
|
|||||||
|
BASE_DOMAIN = localhost
|
||||||
REDIRECT_URI = http://localhost:9001/api/auth/callback
|
REDIRECT_URI = http://localhost:9001/api/auth/callback
|
||||||
|
APP_URI = http://localhost:3000
|
||||||
DB_USER = your_database_username
|
DB_USER = your_database_username
|
||||||
DB_PASSWD = your_database_password
|
DB_PASSWD = your_database_password
|
||||||
DB_NAME = your_database_name
|
DB_NAME = your_database_name
|
||||||
|
|||||||
@ -1 +1,3 @@
|
|||||||
REDIRECT_URI = https://domain.for.this.app/api/auth/callback
|
BASE_DOMAIN = domain.app
|
||||||
|
REDIRECT_URI = https://backend.app/api/auth/callback
|
||||||
|
APP_URI = https://frontend.app
|
||||||
@ -35,6 +35,11 @@ const singleRequest = async (req, res, method, path, config = {}, data = null, i
|
|||||||
// Non 2XX response received
|
// Non 2XX response received
|
||||||
let logMsg;
|
let logMsg;
|
||||||
if (error.response.status >= 400 && error.response.status < 600) {
|
if (error.response.status >= 400 && error.response.status < 600) {
|
||||||
|
if (error.response.status === 401) {
|
||||||
|
logMsg="reauth, attempting...";
|
||||||
|
logger.info(logPrefix + logMsg);
|
||||||
|
// reauth here?
|
||||||
|
}
|
||||||
res.status(error.response.status).send(error.response.data);
|
res.status(error.response.status).send(error.response.data);
|
||||||
logMsg = "" + error.response.status
|
logMsg = "" + error.response.status
|
||||||
}
|
}
|
||||||
@ -42,7 +47,7 @@ const singleRequest = async (req, res, method, path, config = {}, data = null, i
|
|||||||
res.sendStatus(error.response.status);
|
res.sendStatus(error.response.status);
|
||||||
logMsg = "???";
|
logMsg = "???";
|
||||||
}
|
}
|
||||||
logger.error(logPrefix + logMsg, {
|
logger.warn(logPrefix + logMsg, {
|
||||||
response: {
|
response: {
|
||||||
data: error.response.data,
|
data: error.response.data,
|
||||||
status: error.response.status,
|
status: error.response.status,
|
||||||
@ -51,7 +56,7 @@ const singleRequest = async (req, res, method, path, config = {}, data = null, i
|
|||||||
} else if (error.request) {
|
} else if (error.request) {
|
||||||
// No response received
|
// No response received
|
||||||
res.sendStatus(504);
|
res.sendStatus(504);
|
||||||
logger.warn(logPrefix + "No response", { error });
|
logger.error(logPrefix + "No response", { error });
|
||||||
} else {
|
} else {
|
||||||
// Something happened in setting up the request that triggered an Error
|
// Something happened in setting up the request that triggered an Error
|
||||||
res.sendStatus(500);
|
res.sendStatus(500);
|
||||||
@ -144,7 +149,7 @@ const checkPlaylistEditable = async (req, res, playlistID, userID) => {
|
|||||||
message: "You cannot edit this playlist, you must be the owner/the playlist must be collaborative",
|
message: "You cannot edit this playlist, you must be the owner/the playlist must be collaborative",
|
||||||
playlistID: playlistID
|
playlistID: playlistID
|
||||||
});
|
});
|
||||||
logger.warn("user cannot edit target playlist", { playlistID: playlistID });
|
logger.info("user cannot edit target playlist", { playlistID: playlistID });
|
||||||
return false;
|
return false;
|
||||||
} else {
|
} else {
|
||||||
return true;
|
return true;
|
||||||
|
|||||||
@ -49,10 +49,10 @@ const callback = async (req, res) => {
|
|||||||
// check state
|
// check state
|
||||||
if (state === null || state !== storedState) {
|
if (state === null || state !== storedState) {
|
||||||
res.redirect(409, "/");
|
res.redirect(409, "/");
|
||||||
logger.error("state mismatch");
|
logger.warn("state mismatch");
|
||||||
return;
|
return;
|
||||||
} else if (error) {
|
} else if (error) {
|
||||||
res.status(401).send("Auth callback error");
|
res.status(401).send({ message: "Auth callback error" });
|
||||||
logger.error("callback error", { error });
|
logger.error("callback error", { error });
|
||||||
return;
|
return;
|
||||||
} else {
|
} else {
|
||||||
@ -73,10 +73,9 @@ const callback = async (req, res) => {
|
|||||||
logger.debug("Tokens obtained.");
|
logger.debug("Tokens obtained.");
|
||||||
req.session.accessToken = tokenResponse.data.access_token;
|
req.session.accessToken = tokenResponse.data.access_token;
|
||||||
req.session.refreshToken = tokenResponse.data.refresh_token;
|
req.session.refreshToken = tokenResponse.data.refresh_token;
|
||||||
req.session.cookie.maxAge = 7 * 24 * 60 * 60 * 1000 // 1 week
|
|
||||||
} else {
|
} else {
|
||||||
logger.error("login failed", { statusCode: tokenResponse.status });
|
logger.error("login failed", { statusCode: tokenResponse.status });
|
||||||
res.status(tokenResponse.status).send("Error: Login failed");
|
res.status(tokenResponse.status).send({ message: "Error: Login failed" });
|
||||||
}
|
}
|
||||||
|
|
||||||
const userData = await getUserProfile(req, res);
|
const userData = await getUserProfile(req, res);
|
||||||
@ -88,8 +87,9 @@ const callback = async (req, res) => {
|
|||||||
id: userData.id,
|
id: userData.id,
|
||||||
};
|
};
|
||||||
|
|
||||||
res.sendStatus(200);
|
// res.sendStatus(200);
|
||||||
logger.info("New login.", { username: userData.display_name });
|
res.redirect(process.env.APP_URI + "?login=success");
|
||||||
|
logger.debug("New login.", { username: userData.display_name });
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
@ -120,10 +120,10 @@ const refresh = async (req, res) => {
|
|||||||
req.session.refreshToken = response.data.refresh_token ?? req.session.refreshToken; // refresh token rotation
|
req.session.refreshToken = response.data.refresh_token ?? req.session.refreshToken; // refresh token rotation
|
||||||
|
|
||||||
res.sendStatus(200);
|
res.sendStatus(200);
|
||||||
logger.info(`Access token refreshed${(response.data.refresh_token !== null) ? " and refresh token updated" : ""}.`);
|
logger.debug(`Access token refreshed${(response.data.refresh_token !== null) ? " and refresh token updated" : ""}.`);
|
||||||
return;
|
return;
|
||||||
} else {
|
} else {
|
||||||
res.status(response.status).send("Error: Refresh token flow failed.");
|
res.status(response.status).send({ message: "Error: Refresh token flow failed." });
|
||||||
logger.error("refresh failed", { statusCode: response.status });
|
logger.error("refresh failed", { statusCode: response.status });
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@ -141,15 +141,15 @@ const refresh = async (req, res) => {
|
|||||||
*/
|
*/
|
||||||
const logout = async (req, res) => {
|
const logout = async (req, res) => {
|
||||||
try {
|
try {
|
||||||
const delSession = req.session.destroy((err) => {
|
const delSession = req.session.destroy((error) => {
|
||||||
if (err) {
|
if (error) {
|
||||||
res.sendStatus(500);
|
res.sendStatus(500);
|
||||||
logger.error("Error while logging out", { err });
|
logger.error("Error while logging out", { error });
|
||||||
return;
|
return;
|
||||||
} else {
|
} else {
|
||||||
res.clearCookie(sessionName);
|
res.clearCookie(sessionName);
|
||||||
res.sendStatus(200);
|
res.sendStatus(200);
|
||||||
logger.info("Logged out.", { sessionID: delSession.id });
|
logger.debug("Logged out.", { sessionID: delSession.id });
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
|||||||
@ -98,7 +98,7 @@ const updateUser = async (req, res) => {
|
|||||||
});
|
});
|
||||||
if (cleanedUser !== toRemovePls.length) {
|
if (cleanedUser !== toRemovePls.length) {
|
||||||
res.sendStatus(500);
|
res.sendStatus(500);
|
||||||
logger.error("Could not remove all old playlists", { error: new Error("Playlists.destroy failed?") });
|
logger.warn("Could not remove all old playlists", { error: new Error("Playlists.destroy failed?") });
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -116,7 +116,7 @@ const updateUser = async (req, res) => {
|
|||||||
}
|
}
|
||||||
|
|
||||||
res.status(200).send({ removedLinks: removedLinks > 0 });
|
res.status(200).send({ removedLinks: removedLinks > 0 });
|
||||||
logger.info("Updated user data", { delLinks: removedLinks, delPls: cleanedUser, addPls: updatedUser.length });
|
logger.debug("Updated user data", { delLinks: removedLinks, delPls: cleanedUser, addPls: updatedUser.length });
|
||||||
return;
|
return;
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
res.sendStatus(500);
|
res.sendStatus(500);
|
||||||
@ -154,7 +154,7 @@ const fetchUser = async (req, res) => {
|
|||||||
playlists: currentPlaylists,
|
playlists: currentPlaylists,
|
||||||
links: currentLinks
|
links: currentLinks
|
||||||
});
|
});
|
||||||
logger.info("Fetched user data", { pls: currentPlaylists.length, links: currentLinks.length });
|
logger.debug("Fetched user data", { pls: currentPlaylists.length, links: currentLinks.length });
|
||||||
return;
|
return;
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
res.sendStatus(500);
|
res.sendStatus(500);
|
||||||
@ -174,17 +174,16 @@ const createLink = async (req, res) => {
|
|||||||
|
|
||||||
let fromPl, toPl;
|
let fromPl, toPl;
|
||||||
try {
|
try {
|
||||||
fromPl = parseSpotifyLink(req.body["from"]);
|
fromPl = parseSpotifyLink(req.body.from);
|
||||||
toPl = parseSpotifyLink(req.body["to"]);
|
toPl = parseSpotifyLink(req.body.to);
|
||||||
if (fromPl.type !== "playlist" || toPl.type !== "playlist") {
|
if (fromPl.type !== "playlist" || toPl.type !== "playlist") {
|
||||||
res.status(400).send({ message: "Link is not a playlist" });
|
res.status(400).send({ message: "Link is not a playlist" });
|
||||||
logger.warn("non-playlist link provided", { from: fromPl, to: toPl });
|
logger.info("non-playlist link provided", { from: fromPl, to: toPl });
|
||||||
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
res.status(400).send({ message: error.message });
|
res.status(400).send({ message: "Could not parse link" });
|
||||||
logger.error("parseSpotifyLink", { error });
|
logger.warn("parseSpotifyLink", { error });
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -197,8 +196,8 @@ const createLink = async (req, res) => {
|
|||||||
|
|
||||||
// if playlists are unknown
|
// if playlists are unknown
|
||||||
if (![fromPl, toPl].every(pl => playlists.includes(pl.id))) {
|
if (![fromPl, toPl].every(pl => playlists.includes(pl.id))) {
|
||||||
res.sendStatus(404);
|
res.status(404).send({ message: "Playlists out of sync "});
|
||||||
logger.error("unknown playlists, resync");
|
logger.warn("unknown playlists, resync");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -214,7 +213,7 @@ const createLink = async (req, res) => {
|
|||||||
});
|
});
|
||||||
if (existingLink) {
|
if (existingLink) {
|
||||||
res.sendStatus(409);
|
res.sendStatus(409);
|
||||||
logger.error("link already exists");
|
logger.info("link already exists");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -228,7 +227,7 @@ const createLink = async (req, res) => {
|
|||||||
|
|
||||||
if (newGraph.detectCycle()) {
|
if (newGraph.detectCycle()) {
|
||||||
res.status(400).send({ message: "Proposed link cannot cause a cycle in the graph" });
|
res.status(400).send({ message: "Proposed link cannot cause a cycle in the graph" });
|
||||||
logger.error("potential cycle detected");
|
logger.warn("potential cycle detected");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -244,7 +243,7 @@ const createLink = async (req, res) => {
|
|||||||
}
|
}
|
||||||
|
|
||||||
res.sendStatus(201);
|
res.sendStatus(201);
|
||||||
logger.info("Created link");
|
logger.debug("Created link");
|
||||||
return;
|
return;
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
res.sendStatus(500);
|
res.sendStatus(500);
|
||||||
@ -265,16 +264,16 @@ const removeLink = async (req, res) => {
|
|||||||
|
|
||||||
let fromPl, toPl;
|
let fromPl, toPl;
|
||||||
try {
|
try {
|
||||||
fromPl = parseSpotifyLink(req.body["from"]);
|
fromPl = parseSpotifyLink(req.body.from);
|
||||||
toPl = parseSpotifyLink(req.body["to"]);
|
toPl = parseSpotifyLink(req.body.to);
|
||||||
if (fromPl.type !== "playlist" || toPl.type !== "playlist") {
|
if (fromPl.type !== "playlist" || toPl.type !== "playlist") {
|
||||||
res.status(400).send({ message: "Link is not a playlist" });
|
res.status(400).send({ message: "Link is not a playlist" });
|
||||||
logger.warn("non-playlist link provided", { from: fromPl, to: toPl });
|
logger.info("non-playlist link provided", { from: fromPl, to: toPl });
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
res.status(400).send({ message: error.message });
|
res.status(400).send({ message: "Could not parse link" });
|
||||||
logger.error("parseSpotifyLink", { error });
|
logger.warn("parseSpotifyLink", { error });
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -290,7 +289,7 @@ const removeLink = async (req, res) => {
|
|||||||
});
|
});
|
||||||
if (!existingLink) {
|
if (!existingLink) {
|
||||||
res.sendStatus(409);
|
res.sendStatus(409);
|
||||||
logger.error("link does not exist");
|
logger.warn("link does not exist");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -310,7 +309,7 @@ const removeLink = async (req, res) => {
|
|||||||
}
|
}
|
||||||
|
|
||||||
res.sendStatus(200);
|
res.sendStatus(200);
|
||||||
logger.info("Deleted link");
|
logger.debug("Deleted link");
|
||||||
return;
|
return;
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
res.sendStatus(500);
|
res.sendStatus(500);
|
||||||
@ -350,12 +349,12 @@ const populateSingleLink = async (req, res) => {
|
|||||||
toPl = parseSpotifyLink(req.body.to);
|
toPl = parseSpotifyLink(req.body.to);
|
||||||
if (fromPl.type !== "playlist" || toPl.type !== "playlist") {
|
if (fromPl.type !== "playlist" || toPl.type !== "playlist") {
|
||||||
res.status(400).send({ message: "Link is not a playlist" });
|
res.status(400).send({ message: "Link is not a playlist" });
|
||||||
logger.warn("non-playlist link provided", link);
|
logger.info("non-playlist link provided", link);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
res.status(400).send({ message: error.message });
|
res.status(400).send({ message: "Could not parse link" });
|
||||||
logger.error("parseSpotifyLink", { error });
|
logger.warn("parseSpotifyLink", { error });
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -400,7 +399,7 @@ const populateSingleLink = async (req, res) => {
|
|||||||
|
|
||||||
|
|
||||||
// keep getting batches of 50 till exhausted
|
// keep getting batches of 50 till exhausted
|
||||||
for (let i = 1; "next" in fromPlaylist; i++) {
|
while (fromPlaylist.next) {
|
||||||
const nextData = await getPlaylistDetailsNextPage(req, res, fromPlaylist.next);
|
const nextData = await getPlaylistDetailsNextPage(req, res, fromPlaylist.next);
|
||||||
if (res.headersSent) return;
|
if (res.headersSent) return;
|
||||||
|
|
||||||
@ -436,7 +435,7 @@ const populateSingleLink = async (req, res) => {
|
|||||||
});
|
});
|
||||||
|
|
||||||
// keep getting batches of 50 till exhausted
|
// keep getting batches of 50 till exhausted
|
||||||
for (let i = 1; "next" in toPlaylist; i++) {
|
while (toPlaylist.next) {
|
||||||
const nextData = await getPlaylistDetailsNextPage(req, res, toPlaylist.next);
|
const nextData = await getPlaylistDetailsNextPage(req, res, toPlaylist.next);
|
||||||
if (res.headersSent) return;
|
if (res.headersSent) return;
|
||||||
|
|
||||||
@ -475,7 +474,7 @@ const populateSingleLink = async (req, res) => {
|
|||||||
added: toAddNum,
|
added: toAddNum,
|
||||||
local: localNum,
|
local: localNum,
|
||||||
});
|
});
|
||||||
logger.info(`Backfilled ${toAddNum} tracks, could not add ${localNum} local files.`);
|
logger.debug(`Backfilled ${toAddNum} tracks, could not add ${localNum} local files.`);
|
||||||
return;
|
return;
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
res.sendStatus(500);
|
res.sendStatus(500);
|
||||||
@ -507,16 +506,16 @@ const pruneSingleLink = async (req, res) => {
|
|||||||
|
|
||||||
let fromPl, toPl;
|
let fromPl, toPl;
|
||||||
try {
|
try {
|
||||||
fromPl = parseSpotifyLink(req.body["from"]);
|
fromPl = parseSpotifyLink(req.body.from);
|
||||||
toPl = parseSpotifyLink(req.body["to"]);
|
toPl = parseSpotifyLink(req.body.to);
|
||||||
if (fromPl.type !== "playlist" || toPl.type !== "playlist") {
|
if (fromPl.type !== "playlist" || toPl.type !== "playlist") {
|
||||||
res.status(400).send({ message: "Link is not a playlist" });
|
res.status(400).send({ message: "Link is not a playlist" });
|
||||||
logger.warn("non-playlist link provided", { from: fromPl, to: toPl });
|
logger.info("non-playlist link provided", { from: fromPl, to: toPl });
|
||||||
return
|
return;
|
||||||
}
|
}
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
res.status(400).send({ message: error.message });
|
res.status(400).send({ message: error.message });
|
||||||
logger.error("parseSpotifyLink", { error });
|
logger.warn("parseSpotifyLink", { error });
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -532,7 +531,7 @@ const pruneSingleLink = async (req, res) => {
|
|||||||
});
|
});
|
||||||
if (!existingLink) {
|
if (!existingLink) {
|
||||||
res.sendStatus(409);
|
res.sendStatus(409);
|
||||||
logger.error("link does not exist");
|
logger.warn("link does not exist");
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -561,7 +560,7 @@ const pruneSingleLink = async (req, res) => {
|
|||||||
});
|
});
|
||||||
|
|
||||||
// keep getting batches of 50 till exhausted
|
// keep getting batches of 50 till exhausted
|
||||||
for (let i = 1; "next" in fromPlaylist; i++) {
|
while (fromPlaylist.next) {
|
||||||
const nextData = await getPlaylistDetailsNextPage(req, res, fromPlaylist.next);
|
const nextData = await getPlaylistDetailsNextPage(req, res, fromPlaylist.next);
|
||||||
if (res.headersSent) return;
|
if (res.headersSent) return;
|
||||||
|
|
||||||
@ -598,7 +597,7 @@ const pruneSingleLink = async (req, res) => {
|
|||||||
});
|
});
|
||||||
|
|
||||||
// keep getting batches of 50 till exhausted
|
// keep getting batches of 50 till exhausted
|
||||||
for (let i = 1; "next" in toPlaylist; i++) {
|
while (toPlaylist.next) {
|
||||||
const nextData = await getPlaylistDetailsNextPage(req, res, toPlaylist.next);
|
const nextData = await getPlaylistDetailsNextPage(req, res, toPlaylist.next);
|
||||||
if (res.headersSent) return;
|
if (res.headersSent) return;
|
||||||
|
|
||||||
@ -638,7 +637,7 @@ const pruneSingleLink = async (req, res) => {
|
|||||||
}
|
}
|
||||||
|
|
||||||
res.status(200).send({ message: `Removed ${toDelNum} tracks.` });
|
res.status(200).send({ message: `Removed ${toDelNum} tracks.` });
|
||||||
logger.info(`Pruned ${toDelNum} tracks`);
|
logger.debug(`Pruned ${toDelNum} tracks`);
|
||||||
return;
|
return;
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
res.sendStatus(500);
|
res.sendStatus(500);
|
||||||
|
|||||||
@ -51,7 +51,7 @@ const fetchUserPlaylists = async (req, res) => {
|
|||||||
delete userPlaylists.next;
|
delete userPlaylists.next;
|
||||||
|
|
||||||
res.status(200).send(userPlaylists);
|
res.status(200).send(userPlaylists);
|
||||||
logger.info("Fetched user playlists", { num: userPlaylists.total });
|
logger.debug("Fetched user playlists", { num: userPlaylists.total });
|
||||||
return;
|
return;
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
res.sendStatus(500);
|
res.sendStatus(500);
|
||||||
@ -83,7 +83,7 @@ const fetchPlaylistDetails = async (req, res) => {
|
|||||||
}
|
}
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
res.status(400).send({ message: error.message });
|
res.status(400).send({ message: error.message });
|
||||||
logger.error("parseSpotifyLink", { error });
|
logger.warn("parseSpotifyLink", { error });
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -144,7 +144,7 @@ const fetchPlaylistDetails = async (req, res) => {
|
|||||||
delete playlist.next;
|
delete playlist.next;
|
||||||
|
|
||||||
res.status(200).send(playlist);
|
res.status(200).send(playlist);
|
||||||
logger.info("Fetched playlist tracks", { num: playlist.tracks.length });
|
logger.debug("Fetched playlist tracks", { num: playlist.tracks.length });
|
||||||
return;
|
return;
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
res.sendStatus(500);
|
res.sendStatus(500);
|
||||||
|
|||||||
37
index.js
37
index.js
@ -13,6 +13,7 @@ const { sessionName } = require("./constants");
|
|||||||
const db = require("./models");
|
const db = require("./models");
|
||||||
|
|
||||||
const { isAuthenticated } = require("./middleware/authCheck");
|
const { isAuthenticated } = require("./middleware/authCheck");
|
||||||
|
const { getUserProfile } = require("./api/spotify");
|
||||||
|
|
||||||
const logger = require("./utils/logger")(module);
|
const logger = require("./utils/logger")(module);
|
||||||
|
|
||||||
@ -35,13 +36,21 @@ app.use(session({
|
|||||||
resave: false,
|
resave: false,
|
||||||
saveUninitialized: false,
|
saveUninitialized: false,
|
||||||
cookie: {
|
cookie: {
|
||||||
secure: "auto", // if true only transmit cookie over https
|
domain: process.env.BASE_DOMAIN,
|
||||||
httpOnly: true, // if true prevent client side JS from reading the cookie
|
httpOnly: true, // if true prevent client side JS from reading the cookie
|
||||||
|
maxAge: 7 * 24 * 60 * 60 * 1000, // 1 week
|
||||||
|
sameSite: process.env.NODE_ENV === "development" ? "lax" : "none", // cross-site for production
|
||||||
|
secure: process.env.NODE_ENV === "development" ? false : true, // if true only transmit cookie over https
|
||||||
}
|
}
|
||||||
}));
|
}));
|
||||||
|
|
||||||
app.use(cors());
|
app.use(cors({
|
||||||
app.use(helmet());
|
origin: process.env.APP_URI,
|
||||||
|
credentials: true
|
||||||
|
}));
|
||||||
|
app.use(helmet({
|
||||||
|
crossOriginOpenerPolicy: { policy: process.env.NODE_ENV === "development" ? "unsafe-none" : "same-origin" }
|
||||||
|
}));
|
||||||
app.disable("x-powered-by");
|
app.disable("x-powered-by");
|
||||||
|
|
||||||
app.use(cookieParser());
|
app.use(cookieParser());
|
||||||
@ -51,6 +60,24 @@ app.use(express.urlencoded({ extended: true }));
|
|||||||
// Static
|
// Static
|
||||||
app.use(express.static(__dirname + "/static"));
|
app.use(express.static(__dirname + "/static"));
|
||||||
|
|
||||||
|
// Healthcheck
|
||||||
|
app.use("/health", (req, res) => {
|
||||||
|
res.sendStatus(200);
|
||||||
|
return;
|
||||||
|
});
|
||||||
|
app.use("/auth-health", isAuthenticated, async (req, res) => {
|
||||||
|
try {
|
||||||
|
await getUserProfile(req, res);
|
||||||
|
if (res.headersSent) return;
|
||||||
|
res.sendStatus(200);
|
||||||
|
return;
|
||||||
|
} catch (error) {
|
||||||
|
res.sendStatus(500);
|
||||||
|
logger.error("authHealthCheck", { error });
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
// Routes
|
// Routes
|
||||||
app.use("/api/auth/", require("./routes/auth"));
|
app.use("/api/auth/", require("./routes/auth"));
|
||||||
app.use("/api/playlists", isAuthenticated, require("./routes/playlists"));
|
app.use("/api/playlists", isAuthenticated, require("./routes/playlists"));
|
||||||
@ -61,7 +88,7 @@ app.use((req, res) => {
|
|||||||
res.status(404).send(
|
res.status(404).send(
|
||||||
"Guess the <a href=\"https://github.com/20kaushik02/spotify-manager\">cat's</a> out of the bag!"
|
"Guess the <a href=\"https://github.com/20kaushik02/spotify-manager\">cat's</a> out of the bag!"
|
||||||
);
|
);
|
||||||
logger.info("Unrecognized URL", { url: req.url });
|
logger.info("404", { url: req.url });
|
||||||
return;
|
return;
|
||||||
});
|
});
|
||||||
|
|
||||||
@ -73,7 +100,7 @@ const server = app.listen(port, () => {
|
|||||||
|
|
||||||
const cleanupFunc = (signal) => {
|
const cleanupFunc = (signal) => {
|
||||||
if (signal)
|
if (signal)
|
||||||
logger.info(`${signal} signal received, shutting down now...`);
|
logger.debug(`${signal} signal received, shutting down now...`);
|
||||||
|
|
||||||
Promise.allSettled([
|
Promise.allSettled([
|
||||||
db.sequelize.close(),
|
db.sequelize.close(),
|
||||||
|
|||||||
@ -19,7 +19,7 @@ const isAuthenticated = (req, res, next) => {
|
|||||||
const delSession = req.session.destroy((err) => {
|
const delSession = req.session.destroy((err) => {
|
||||||
if (err) {
|
if (err) {
|
||||||
res.sendStatus(500);
|
res.sendStatus(500);
|
||||||
logger.error("Error while destroying session.", { err });
|
logger.error("session.destroy", { err });
|
||||||
return;
|
return;
|
||||||
} else {
|
} else {
|
||||||
res.clearCookie(sessionName);
|
res.clearCookie(sessionName);
|
||||||
|
|||||||
@ -18,7 +18,7 @@ if (config.use_env_variable) {
|
|||||||
(async () => {
|
(async () => {
|
||||||
try {
|
try {
|
||||||
await sequelize.authenticate();
|
await sequelize.authenticate();
|
||||||
logger.info("Sequelize auth success");
|
logger.debug("Sequelize auth success");
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
logger.error("Sequelize auth error", { error });
|
logger.error("Sequelize auth error", { error });
|
||||||
throw error;
|
throw error;
|
||||||
|
|||||||
542
package-lock.json
generated
542
package-lock.json
generated
File diff suppressed because it is too large
Load Diff
16
package.json
16
package.json
@ -4,8 +4,10 @@
|
|||||||
"description": "Personal Spotify playlist manager",
|
"description": "Personal Spotify playlist manager",
|
||||||
"main": "index.js",
|
"main": "index.js",
|
||||||
"scripts": {
|
"scripts": {
|
||||||
"start": "node index.js",
|
"dev": "cross-env NODE_ENV=development nodemon --delay 2 --exitcrash index.js",
|
||||||
"dev": "cross-env NODE_ENV=development nodemon --exitcrash index.js"
|
"test_setup": "npm i && cross-env NODE_ENV=test npx sequelize-cli db:migrate",
|
||||||
|
"test": "cross-env NODE_ENV=test node index.js",
|
||||||
|
"prod": "NODE_ENV=production node index.js"
|
||||||
},
|
},
|
||||||
"repository": {
|
"repository": {
|
||||||
"type": "git",
|
"type": "git",
|
||||||
@ -18,7 +20,7 @@
|
|||||||
},
|
},
|
||||||
"homepage": "https://github.com/20kaushik02/spotify-manager#readme",
|
"homepage": "https://github.com/20kaushik02/spotify-manager#readme",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"axios": "^1.7.8",
|
"axios": "^1.7.9",
|
||||||
"connect-sqlite3": "^0.9.15",
|
"connect-sqlite3": "^0.9.15",
|
||||||
"cookie-parser": "^1.4.7",
|
"cookie-parser": "^1.4.7",
|
||||||
"cors": "^2.8.5",
|
"cors": "^2.8.5",
|
||||||
@ -26,7 +28,7 @@
|
|||||||
"express": "^4.21.2",
|
"express": "^4.21.2",
|
||||||
"express-session": "^1.18.1",
|
"express-session": "^1.18.1",
|
||||||
"express-validator": "^7.2.0",
|
"express-validator": "^7.2.0",
|
||||||
"helmet": "^7.2.0",
|
"helmet": "^8.0.0",
|
||||||
"sequelize": "^6.37.5",
|
"sequelize": "^6.37.5",
|
||||||
"pg": "^8.13.1",
|
"pg": "^8.13.1",
|
||||||
"serializr": "^3.0.3",
|
"serializr": "^3.0.3",
|
||||||
@ -34,10 +36,10 @@
|
|||||||
},
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"@types/express": "^4.17.21",
|
"@types/express": "^4.17.21",
|
||||||
"@types/node": "^22.2.0",
|
"@types/node": "^22.10.2",
|
||||||
"cross-env": "^7.0.3",
|
"cross-env": "^7.0.3",
|
||||||
"nodemon": "^3.1.4",
|
"nodemon": "^3.1.9",
|
||||||
"sequelize-cli": "^6.6.2",
|
"sequelize-cli": "^6.6.2",
|
||||||
"typescript": "^5.5.4"
|
"typescript": "^5.7.2"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user