Skip to content

Commit a74b084

Browse files
committed
feat: one time login
1 parent 1f4ea1d commit a74b084

6 files changed

Lines changed: 44 additions & 31 deletions

File tree

.gitignore

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
/.env
2+
/auth.json
23
node_modules/
34
logs/
45
build/

eslint.config.js

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,7 @@ export default [
1515
prettier,
1616
globalIgnores(['./build/']),
1717
{
18-
ignores: ['package.json'],
18+
ignores: ['package.json', 'auth.json'],
1919
files: ['**/*.json'],
2020
plugins: { json },
2121
language: 'json/json',

src/Private/RequestHandler.ts

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
import SpotifyManagerError from './Error.js';
2+
import { readFileSync } from 'node:fs';
23
import type Application from '../Application.js';
34
import type { RequestOptions } from '../Types/Requests.js';
45

@@ -36,7 +37,6 @@ class RequestHandler {
3637
}
3738

3839
async request(endpoint: string, options?: RequestOptions): Promise<RequestData> {
39-
if (!this.Application.spotify.token) throw new SpotifyManagerError(this.Application.messages.accountNotLoggedIn);
4040
options = { raw: options?.raw ?? false, noCache: options?.noCache ?? false, method: options?.method ?? 'GET' };
4141
if (this.Application.cacheHandler.has(endpoint)) {
4242
const data = this.Application.cacheHandler.get(endpoint);
@@ -48,9 +48,10 @@ class RequestHandler {
4848
timestamp: data.timestamp
4949
});
5050
}
51+
const authData = JSON.parse(readFileSync('auth.json', 'utf-8'));
5152
const res = await fetch(BASE_URL + endpoint, {
5253
method: options.method,
53-
headers: { Authorization: `Bearer ${this.Application.spotify.token.key}` }
54+
headers: { Authorization: `Bearer ${authData.key}` }
5455
});
5556
if (options.method !== 'GET') {
5657
return new RequestData({}, res.headers, { status: res.status, options, url: endpoint, cached: false });

src/Spotify/Routes/Auth/CallbackRoute.ts

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
import Route from '../../Private/BaseRoute.js';
22
import SpotifyManager from '../../SpotifyManager.js';
3+
import { writeFileSync } from 'node:fs';
34
import type { Request, Response } from 'express';
45
import type { Token } from '../../../Types/Spotify.js';
56

@@ -15,7 +16,7 @@ class CallbackRoute extends Route {
1516
const verifier = req.session.verifier;
1617
if (!code || !verifier || typeof code !== 'string') return res.status(400).send('Invalid request.');
1718
const token = await this.getAccessToken(verifier, code);
18-
this.spotify.token = token;
19+
writeFileSync('auth.json', JSON.stringify(token, null, 2));
1920
res.status(200).json({ success: true, message: this.spotify.Application.messages.tokenGenerated });
2021
} catch (error) {
2122
if (error instanceof Error) this.spotify.Application.Logger.error(error);

src/Spotify/Routes/Auth/RefreshRoute.ts

Lines changed: 19 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,8 @@
11
/* eslint-disable camelcase */
2+
23
import Route from '../../Private/BaseRoute.js';
34
import SpotifyManager from '../../SpotifyManager.js';
5+
import { readFileSync, writeFileSync } from 'node:fs';
46
import type { Request, Response } from 'express';
57

68
class RefreshRoute extends Route {
@@ -11,16 +13,13 @@ class RefreshRoute extends Route {
1113

1214
override async handle(req: Request, res: Response) {
1315
try {
14-
if (!this.spotify.token) {
15-
return res.status(403).json({ success: false, cause: this.spotify.Application.messages.accountNotLoggedIn });
16-
}
17-
16+
const authData = JSON.parse(readFileSync('auth.json', 'utf-8'));
1817
const result = await fetch('https://accounts.spotify.com/api/token', {
1918
method: 'POST',
2019
headers: { 'Content-Type': 'application/x-www-form-urlencoded' },
2120
body: new URLSearchParams({
2221
grant_type: 'refresh_token',
23-
refresh_token: this.spotify.token.refresh,
22+
refresh_token: authData.refresh,
2423
client_id: process.env.SPOTIFY_CLIENT_ID
2524
})
2625
});
@@ -31,14 +30,21 @@ class RefreshRoute extends Route {
3130
return res.status(404).json({ success: false, cause: 'Something went wrong. Please try again' });
3231
}
3332
const tokenData = await result.json();
34-
this.spotify.token = {
35-
key: tokenData.access_token,
36-
refresh: tokenData.refresh_token,
37-
type: tokenData.token_type,
38-
expiresIn: tokenData.expires_in,
39-
expirationTime: Date.now() + tokenData.expires_in * 1000,
40-
scope: tokenData.scope.split(' ')
41-
};
33+
writeFileSync(
34+
'auth.json',
35+
JSON.stringify(
36+
{
37+
key: tokenData.access_token,
38+
refresh: tokenData.refresh_token,
39+
type: tokenData.token_type,
40+
expiresIn: tokenData.expires_in,
41+
expirationTime: Date.now() + tokenData.expires_in * 1000,
42+
scope: tokenData.scope.split(' ')
43+
},
44+
null,
45+
2
46+
)
47+
);
4248
res.status(200).json({ success: true, message: this.spotify.Application.messages.tokenGenerated });
4349
} catch (error) {
4450
if (error instanceof Error) this.spotify.Application.Logger.error(error);

src/Spotify/SpotifyManager.ts

Lines changed: 18 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -2,15 +2,14 @@ import RequestHandler from './Private/RequestHandler.js';
22
import Routes from './Routes/index.js';
33
import express from 'express';
44
import session from 'express-session';
5+
import { existsSync } from 'node:fs';
56
import type Application from '../Application.js';
6-
import type { Token } from '../Types/Spotify.js';
77

88
class SpotifyManager {
99
readonly Application: Application;
1010
declare requestHandler: RequestHandler;
1111
readonly expressServer: express.Application;
12-
scopes: string[];
13-
token: null | Token;
12+
readonly scopes: string[];
1413
declare interval: NodeJS.Timeout;
1514
constructor(app: Application) {
1615
this.Application = app;
@@ -23,17 +22,22 @@ class SpotifyManager {
2322
'user-read-playback-state',
2423
'user-read-private'
2524
];
26-
this.token = null;
27-
this.interval = setInterval(async () => {
28-
if (this.token) {
29-
const res = await fetch(`http://127.0.0.1:${process.env.PORT}/auth/refresh`);
30-
if (res.status !== 200) {
31-
this.Application.Logger.warn('Token refresh failed.');
32-
return;
33-
}
34-
this.Application.Logger.other('Token refreshed successfully.');
35-
}
36-
}, 1000 * 3600);
25+
this.interval = setInterval(async () => await this.refreshAuth(), 1000 * 3600);
26+
this.refreshAuth();
27+
}
28+
29+
private async refreshAuth() {
30+
if (!existsSync('auth.json')) {
31+
return this.Application.Logger.warn(
32+
`Missing Spotify Auth File. Please login to spotify via http://127.0.0.1:${process.env.PORT}/auth/login`
33+
);
34+
}
35+
const res = await fetch(`http://127.0.0.1:${process.env.PORT}/auth/refresh`);
36+
if (res.status !== 200) {
37+
this.Application.Logger.warn('Token refresh failed.');
38+
return;
39+
}
40+
this.Application.Logger.other('Token refreshed successfully.');
3741
}
3842

3943
private startWebServer() {

0 commit comments

Comments
 (0)