mirror of
https://github.com/ragestudio/comty.git
synced 2025-06-09 10:34:17 +00:00
added SyncController
This commit is contained in:
parent
b87f4276b1
commit
ca8fcc9353
@ -1,5 +1,6 @@
|
|||||||
import path from "path"
|
import path from "path"
|
||||||
import { Server as LinebridgeServer } from "linebridge/dist/server"
|
import { Server as LinebridgeServer } from "linebridge/dist/server"
|
||||||
|
|
||||||
import express from "express"
|
import express from "express"
|
||||||
import bcrypt from "bcrypt"
|
import bcrypt from "bcrypt"
|
||||||
import passport from "passport"
|
import passport from "passport"
|
||||||
@ -45,11 +46,12 @@ export default class Server {
|
|||||||
controllers.FeaturedEventsController,
|
controllers.FeaturedEventsController,
|
||||||
controllers.PlaylistsController,
|
controllers.PlaylistsController,
|
||||||
controllers.FeedController,
|
controllers.FeedController,
|
||||||
|
controllers.SyncController,
|
||||||
]
|
]
|
||||||
|
|
||||||
middlewares = middlewares
|
middlewares = middlewares
|
||||||
|
|
||||||
server = new LinebridgeServer({
|
server = global.server = new LinebridgeServer({
|
||||||
port: process.env.MAIN_LISTEN_PORT || 3000,
|
port: process.env.MAIN_LISTEN_PORT || 3000,
|
||||||
headers: {
|
headers: {
|
||||||
"Access-Control-Expose-Headers": "regenerated_token",
|
"Access-Control-Expose-Headers": "regenerated_token",
|
||||||
|
@ -0,0 +1,114 @@
|
|||||||
|
import { SyncEntry } from "../../../models"
|
||||||
|
|
||||||
|
import crypto from "crypto"
|
||||||
|
|
||||||
|
export default class SecureSyncEntry {
|
||||||
|
static get encrytionAlgorithm() {
|
||||||
|
return "aes-256-cbc"
|
||||||
|
}
|
||||||
|
|
||||||
|
static async set(user_id, key, value) {
|
||||||
|
if (!user_id) {
|
||||||
|
throw new Error("Missing user_id")
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!key) {
|
||||||
|
throw new Error("Missing key")
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!value) {
|
||||||
|
throw new Error("Missing value")
|
||||||
|
}
|
||||||
|
|
||||||
|
let entry = await SyncEntry.findOne({ key }).catch(() => null)
|
||||||
|
|
||||||
|
const encryptionKey = Buffer.from(process.env.SYNC_ENCRIPT_SECRET, "hex")
|
||||||
|
const iv = crypto.randomBytes(16)
|
||||||
|
|
||||||
|
const cipher = crypto.createCipheriv(SecureSyncEntry.encrytionAlgorithm, encryptionKey, iv)
|
||||||
|
|
||||||
|
let encrypted
|
||||||
|
|
||||||
|
try {
|
||||||
|
encrypted = cipher.update(value)
|
||||||
|
}
|
||||||
|
catch (error) {
|
||||||
|
console.error(error)
|
||||||
|
}
|
||||||
|
|
||||||
|
encrypted = Buffer.concat([encrypted, cipher.final()])
|
||||||
|
|
||||||
|
if (entry) {
|
||||||
|
entry.value = iv.toString("hex") + ":" + encrypted.toString("hex")
|
||||||
|
|
||||||
|
await entry.save()
|
||||||
|
|
||||||
|
return entry
|
||||||
|
}
|
||||||
|
|
||||||
|
entry = new SyncEntry({
|
||||||
|
user_id,
|
||||||
|
key,
|
||||||
|
value: iv.toString("hex") + ":" + encrypted.toString("hex"),
|
||||||
|
})
|
||||||
|
|
||||||
|
await entry.save()
|
||||||
|
|
||||||
|
return entry
|
||||||
|
}
|
||||||
|
|
||||||
|
static async get(user_id, key) {
|
||||||
|
if (!user_id) {
|
||||||
|
throw new Error("Missing user_id")
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!key) {
|
||||||
|
throw new Error("Missing key")
|
||||||
|
}
|
||||||
|
|
||||||
|
const entry = await SyncEntry.findOne({
|
||||||
|
user_id,
|
||||||
|
key,
|
||||||
|
}).catch(() => null)
|
||||||
|
|
||||||
|
if (!entry) {
|
||||||
|
return null
|
||||||
|
}
|
||||||
|
|
||||||
|
const encryptionKey = Buffer.from(process.env.SYNC_ENCRIPT_SECRET, "hex")
|
||||||
|
|
||||||
|
const iv = Buffer.from(entry.value.split(":")[0], "hex")
|
||||||
|
const encryptedText = Buffer.from(entry.value.split(":")[1], "hex")
|
||||||
|
|
||||||
|
const decipher = crypto.createDecipheriv(SecureSyncEntry.encrytionAlgorithm, encryptionKey, iv)
|
||||||
|
|
||||||
|
let decrypted = decipher.update(encryptedText)
|
||||||
|
|
||||||
|
decrypted = Buffer.concat([decrypted, decipher.final()])
|
||||||
|
|
||||||
|
return decrypted.toString()
|
||||||
|
}
|
||||||
|
|
||||||
|
static async delete(user_id, key) {
|
||||||
|
if (!user_id) {
|
||||||
|
throw new Error("Missing user_id")
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!key) {
|
||||||
|
throw new Error("Missing key")
|
||||||
|
}
|
||||||
|
|
||||||
|
const entry = await SyncEntry.findOne({
|
||||||
|
user_id,
|
||||||
|
key,
|
||||||
|
}).catch(() => null)
|
||||||
|
|
||||||
|
if (!entry) {
|
||||||
|
return null
|
||||||
|
}
|
||||||
|
|
||||||
|
await entry.delete()
|
||||||
|
|
||||||
|
return entry
|
||||||
|
}
|
||||||
|
}
|
149
packages/server/src/controllers/SyncController/index.js
Normal file
149
packages/server/src/controllers/SyncController/index.js
Normal file
@ -0,0 +1,149 @@
|
|||||||
|
import { Controller } from "linebridge/dist/server"
|
||||||
|
import SecureSyncEntry from "./classes/secureSyncEntry"
|
||||||
|
|
||||||
|
import axios from "axios"
|
||||||
|
|
||||||
|
export default class SyncController extends Controller {
|
||||||
|
static useRoute = "/sync"
|
||||||
|
|
||||||
|
post = {
|
||||||
|
"/spotify/auth": {
|
||||||
|
middlewares: ["withAuthentication"],
|
||||||
|
fn: async (req, res) => {
|
||||||
|
const { code, redirect_uri } = req.body
|
||||||
|
|
||||||
|
if (!code) {
|
||||||
|
return res.status(400).json({
|
||||||
|
message: "Missing code",
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!redirect_uri) {
|
||||||
|
return res.status(400).json({
|
||||||
|
message: "Missing redirect_uri",
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
const response = await axios({
|
||||||
|
url: "https://accounts.spotify.com/api/token",
|
||||||
|
method: "post",
|
||||||
|
params: {
|
||||||
|
grant_type: "authorization_code",
|
||||||
|
code: code,
|
||||||
|
redirect_uri: redirect_uri
|
||||||
|
},
|
||||||
|
headers: {
|
||||||
|
'Authorization': `Basic ${(Buffer.from(process.env.SPOTIFY_CLIENT_ID + ":" + process.env.SPOTIFY_CLIENT_SECRET).toString("base64"))}`,
|
||||||
|
'Content-Type': 'application/x-www-form-urlencoded'
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
|
if (!response) {
|
||||||
|
return res.status(400).json({
|
||||||
|
message: "Missing data",
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
await SecureSyncEntry.set(req.user._id.toString(), "spotify_access_token", response.data.access_token)
|
||||||
|
await SecureSyncEntry.set(req.user._id.toString(), "spotify_refresh_token", response.data.refresh_token)
|
||||||
|
|
||||||
|
return res.json({
|
||||||
|
message: "ok"
|
||||||
|
})
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"/spotify/unlink": {
|
||||||
|
middlewares: ["withAuthentication"],
|
||||||
|
fn: async (req, res) => {
|
||||||
|
await SecureSyncEntry.delete(req.user._id.toString(), "spotify_access_token", "")
|
||||||
|
await SecureSyncEntry.delete(req.user._id.toString(), "spotify_refresh_token", "")
|
||||||
|
|
||||||
|
return res.json({
|
||||||
|
message: "ok"
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
get = {
|
||||||
|
"/spotify/client_id": async (req, res) => {
|
||||||
|
return res.json({
|
||||||
|
client_id: process.env.SPOTIFY_CLIENT_ID,
|
||||||
|
})
|
||||||
|
},
|
||||||
|
"/spotify/is_authorized": {
|
||||||
|
middlewares: ["withAuthentication"],
|
||||||
|
fn: async (req, res) => {
|
||||||
|
const user_id = req.user._id.toString()
|
||||||
|
const authToken = await SecureSyncEntry.get(user_id, "spotify_access_token")
|
||||||
|
|
||||||
|
if (!authToken) {
|
||||||
|
return res.json({
|
||||||
|
is_authorized: false,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
return res.json({
|
||||||
|
is_authorized: true,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"/spotify/data": {
|
||||||
|
middlewares: ["withAuthentication"],
|
||||||
|
fn: async (req, res) => {
|
||||||
|
const user_id = req.user._id.toString()
|
||||||
|
const authToken = await SecureSyncEntry.get(user_id, "spotify_access_token")
|
||||||
|
|
||||||
|
if (!authToken) {
|
||||||
|
return res.status(400).json({
|
||||||
|
message: "Missing auth token",
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
const { data } = await axios.get("https://api.spotify.com/v1/me", {
|
||||||
|
headers: {
|
||||||
|
"Authorization": `Bearer ${authToken}`
|
||||||
|
},
|
||||||
|
}).catch((error) => {
|
||||||
|
console.error(error.response.data)
|
||||||
|
|
||||||
|
res.status(error.response.status).json(error.response.data)
|
||||||
|
|
||||||
|
return null
|
||||||
|
})
|
||||||
|
|
||||||
|
|
||||||
|
return res.json(data)
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"/spotify/currently_playing": {
|
||||||
|
middlewares: ["withAuthentication"],
|
||||||
|
fn: async (req, res) => {
|
||||||
|
const user_id = req.user._id.toString()
|
||||||
|
const authToken = await SecureSyncEntry.get(user_id, "spotify_access_token")
|
||||||
|
|
||||||
|
if (!authToken) {
|
||||||
|
return res.status(400).json({
|
||||||
|
message: "Missing auth token",
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
const response = await axios.get("https://api.spotify.com/v1/me/player", {
|
||||||
|
headers: {
|
||||||
|
"Authorization": `Bearer ${authToken}`
|
||||||
|
},
|
||||||
|
}).catch((error) => {
|
||||||
|
console.error(error.response.data)
|
||||||
|
|
||||||
|
res.status(error.response.status).json(error.response.data)
|
||||||
|
|
||||||
|
return null
|
||||||
|
})
|
||||||
|
|
||||||
|
if (response) {
|
||||||
|
return res.json(response.data)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -12,4 +12,5 @@ export { default as CommentsController } from "./CommentsController"
|
|||||||
export { default as SearchController } from "./SearchController"
|
export { default as SearchController } from "./SearchController"
|
||||||
export { default as FeaturedEventsController } from "./FeaturedEventsController"
|
export { default as FeaturedEventsController } from "./FeaturedEventsController"
|
||||||
export { default as PlaylistsController } from "./PlaylistsController"
|
export { default as PlaylistsController } from "./PlaylistsController"
|
||||||
export { default as FeedController } from "./FeedController"
|
export { default as FeedController } from "./FeedController"
|
||||||
|
export { default as SyncController } from "./SyncController"
|
Loading…
x
Reference in New Issue
Block a user