16 changes: 8 additions & 8 deletions apps/server/src/routes/search.ts
Original file line number Diff line number Diff line change
@@ -1,10 +1,10 @@
import { Router } from 'express';
import { z } from 'zod';
import { searchArtist, searchTrack } from '../database';
import { logger } from '../tools/logger';
import { isLoggedOrGuest, validating } from '../tools/middleware';
import { TypedPayload } from '../tools/types';
import { searchAlbum } from '../database/queries/album';
import { Router } from "express";
import { z } from "zod";
import { searchArtist, searchTrack } from "../database";
import { logger } from "../tools/logger";
import { isLoggedOrGuest, validating } from "../tools/middleware";
import { TypedPayload } from "../tools/types";
import { searchAlbum } from "../database/queries/album";

export const router = Router();

Expand All @@ -23,7 +23,7 @@ router.get(
const [artists, tracks, albums] = await Promise.all([
searchArtist(query),
searchTrack(query),
searchAlbum(query)
searchAlbum(query),
]);
return res.status(200).send({ artists, tracks, albums });
} catch (e) {
Expand Down
12 changes: 12 additions & 0 deletions apps/server/src/tools/crypto.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
import { getRandomValues, subtle } from "crypto";

export function generateRandomString(entropyBytes: number) {
const entropy = getRandomValues(new Uint8Array(entropyBytes));
return Buffer.from(entropy).toString("base64url");
}

export async function sha256(plain: string) {
const encoder = new TextEncoder();
const data = encoder.encode(plain);
return subtle.digest("SHA-256", data);
}
1 change: 0 additions & 1 deletion apps/server/src/tools/env.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,4 @@
import { z } from "zod";
import { logger } from "./logger";
import { toBoolean, toNumber } from "./zod";

const validators = {
Expand Down
26 changes: 18 additions & 8 deletions apps/server/src/tools/oauth/Provider.ts
Original file line number Diff line number Diff line change
@@ -1,12 +1,13 @@
/* eslint-disable @typescript-eslint/no-unused-vars */
import Axios from "axios";
import { generateRandomString, sha256 } from "../crypto";
import { credentials } from "./credentials";

export class Provider {
static getRedirect = () => {};

// @ts-ignore
static exchangeCode = code => {};
static exchangeCode = (code: string, state: string) => {};

// @ts-ignore
static refresh = refreshToken => {};
Expand All @@ -19,18 +20,26 @@ export class Provider {
}

export class Spotify extends Provider {
static getRedirect = () => {
static getRedirect = async () => {
const { scopes } = credentials.spotify;
const { redirectUri } = credentials.spotify;

return `https://accounts.spotify.com/authorize?response_type=code&client_id=${
credentials.spotify.public
}${
scopes ? `&scope=${encodeURIComponent(scopes)}` : ""
}&redirect_uri=${encodeURIComponent(redirectUri)}`;
const authorizeUrl = new URL("https://accounts.spotify.com/authorize");
const state = generateRandomString(32);

authorizeUrl.searchParams.append("client_id", credentials.spotify.public);
authorizeUrl.searchParams.append("response_type", "code");
authorizeUrl.searchParams.append("redirect_uri", redirectUri);
authorizeUrl.searchParams.append("state", state);
authorizeUrl.searchParams.append("scope", scopes);

return {
url: authorizeUrl.toString(),
state,
};
};

static exchangeCode = async (code: string) => {
static exchangeCode = async (code: string, state: string) => {
const { data } = await Axios.post(
"https://accounts.spotify.com/api/token",
null,
Expand All @@ -41,6 +50,7 @@ export class Spotify extends Provider {
redirect_uri: credentials.spotify.redirectUri,
client_id: credentials.spotify.public,
client_secret: credentials.spotify.secret,
state,
},
headers: {
"Content-Type": "application/x-www-form-urlencoded",
Expand Down
6 changes: 6 additions & 0 deletions monorepo.code-workspace
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,12 @@
],
"[typescript]": {
"editor.defaultFormatter": "dbaeumer.vscode-eslint"
},
"[json]": {
"editor.defaultFormatter": "vscode.json-language-features"
},
"[html]": {
"editor.defaultFormatter": "vscode.html-language-features"
}
},
"extensions": {
Expand Down