import Knex from "knex"; import { IntegrationImpl } from "../../client/src/api/api"; const { createProxyMiddleware } = require('http-proxy-middleware'); let axios = require('axios') let qs = require('querystring') async function getSpotifyCCAuthToken(clientId: string, clientSecret: string) { console.log("Details: ", clientId, clientSecret); let buf = Buffer.from(clientId + ':' + clientSecret) let encoded = buf.toString('base64'); let response = await axios.post( 'https://accounts.spotify.com/api/token', qs.stringify({ 'grant_type': 'client_credentials' }), { 'headers': { 'Authorization': 'Basic ' + encoded, 'Content-Type': 'application/x-www-form-urlencoded' } } ); if (response.status != 200) { throw new Error("Unable to get a Spotify auth token.") } return (await response).data.access_token; } export function createIntegrations(knex: Knex, apiBaseUrl: string) { // This will enable the app to redirect requests like: // /integrations/5/v1/search?q=query // To the external API represented by integration 5, e.g. for spotify: // https://api.spotify.com/v1/search?q=query // Requests need to already have a .user.id set. let proxySpotifyCC = createProxyMiddleware({ target: 'https://api.spotify.com/', changeOrigin: true, logLevel: 'debug', pathRewrite: (path: string, req: any) => { // Remove e.g. "/api/integrations/5" let replaced = path.replace(new RegExp(`${apiBaseUrl}/integrations/[0-9]+/`), ''); console.log("Rewrite URL:", path, replaced); return replaced; } }); let proxyYoutubeMusic = createProxyMiddleware({ target: 'https://music.youtube.com/', changeOrigin: true, logLevel: 'debug', pathRewrite: (path: string, req: any) => { // Remove e.g. "/api/integrations/5" let replaced = path.replace(new RegExp(`${apiBaseUrl}/integrations/[0-9]+/`), ''); console.log("Rewrite URL:", path, replaced); return replaced; } }) // In the first layer, retrieve integration details and save details // in the request. return async (req: any, res: any, next: any) => { // Determine the integration to use. req._integrationId = parseInt(req.url.match(/^\/([0-9]+)/)[1]); console.log("URL:", req.url, 'match:', req._integrationId) if (!req._integrationId) { res.status(400).send({ reason: "An integration ID should be provided in the URL." }); return; } req._integration = (await knex.select(['id', 'name', 'type', 'details', 'secretDetails']) .from('integrations') .where({ 'user': req.user.id, 'id': req._integrationId }))[0]; if (!req._integration) { res.status(404).send(); return; } req._integration.details = JSON.parse(req._integration.details); req._integration.secretDetails = JSON.parse(req._integration.secretDetails); switch (req._integration.type) { case IntegrationImpl.SpotifyClientCredentials: { console.log("Integration: ", req._integration) // FIXME: persist the token req._access_token = await getSpotifyCCAuthToken( req._integration.details.clientId, req._integration.secretDetails.clientSecret, ) if (!req._access_token) { res.status(500).send({ reason: "Unable to get Spotify auth token." }) } req.headers["Authorization"] = "Bearer " + req._access_token; return proxySpotifyCC(req, res, next); } case IntegrationImpl.YoutubeWebScraper: { console.log("Integration: ", req._integration) return proxyYoutubeMusic(req, res, next); } default: { res.status(500).send({ reason: "Unsupported integration type " + req._integration.type }) } } }; // // First add a layer which creates a token and saves it in the request. // app.use((req: any, res: any, next: any) => { // updateToken('c3e5e605e7814cdf94cd86eeba6f4c4f', '5d870c84a3c34aa3a4cf803aa95cb96a') // .then(() => { // req._access_token = authToken; // next(); // }) // }) // app.use( // '/spotifycc', // createProxyMiddleware({ // target: 'https://api.spotify.com/', // changeOrigin: true, // onProxyReq: onProxyReq, // logLevel: 'debug', // pathRewrite: { '^/spotifycc': '' }, // }) // ) }