From 441778dac0634bc6082717c2c9ec602555e3b75a Mon Sep 17 00:00:00 2001 From: Rauno Tegelmann Date: Thu, 18 Jul 2024 13:42:35 +0300 Subject: [PATCH] fix: plex oauth login client id --- package.json | 2 ++ pnpm-lock.yaml | 17 ++++++++++++++++ src/lib/auth.ts | 46 ++++++++++++++++++++++++------------------ src/utils/constants.ts | 3 +-- 4 files changed, 46 insertions(+), 22 deletions(-) diff --git a/package.json b/package.json index eb753e5b..13363e5d 100644 --- a/package.json +++ b/package.json @@ -34,6 +34,7 @@ "sharp": "^0.33.4", "stories-react": "^1.1.2", "three": "^0.166.1", + "uuid": "^10.0.0", "vanta": "^0.5.24", "xml2js": "^0.6.2", "zod": "^3.23.8" @@ -49,6 +50,7 @@ "@types/qs": "^6.9.15", "@types/react": "^18.3.3", "@types/react-dom": "^18.3.0", + "@types/uuid": "^10.0.0", "@types/xml2js": "^0.4.14", "@typescript-eslint/eslint-plugin": "^7.16.1", "@typescript-eslint/parser": "^7.16.1", diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 8367956d..ac01f5aa 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -59,6 +59,9 @@ importers: three: specifier: ^0.166.1 version: 0.166.1 + uuid: + specifier: ^10.0.0 + version: 10.0.0 vanta: specifier: ^0.5.24 version: 0.5.24 @@ -99,6 +102,9 @@ importers: '@types/react-dom': specifier: ^18.3.0 version: 18.3.0 + '@types/uuid': + specifier: ^10.0.0 + version: 10.0.0 '@types/xml2js': specifier: ^0.4.14 version: 0.4.14 @@ -1437,6 +1443,9 @@ packages: '@types/trusted-types@2.0.7': resolution: {integrity: sha512-ScaPdn1dQczgbl0QFTeTOmVHFULt394XJgOQNoyVhZ6r2vLnMLJfBPd53SB52T/3G36VI1/g2MZaX0cwDuXsfw==} + '@types/uuid@10.0.0': + resolution: {integrity: sha512-7gqG38EyHgyP1S+7+xomFtL+ZNHcKv6DwNaCZmJmo1vgMugyF3TCnXVg4t1uk89mLNwnLtnY3TpOpCOyp1/xHQ==} + '@types/xml2js@0.4.14': resolution: {integrity: sha512-4YnrRemBShWRO2QjvUin8ESA41rH+9nQGLUGZV/1IDhi3SL9OhdpNC/MrulTWuptXKwhx/aDxE7toV0f/ypIXQ==} @@ -4576,6 +4585,10 @@ packages: util-deprecate@1.0.2: resolution: {integrity: sha512-EPD5q1uXyFxJpCrLnCc1nHnq3gOa6DZBocAIiI2TaSCA7VCJ1UJDMagCzIkXNsUYfD1daK//LTEQ8xiIbrHtcw==} + uuid@10.0.0: + resolution: {integrity: sha512-8XkAphELsDnEGrDxUOHB3RGvXz6TeuYSGEZBOjtTtPm2lwhGBjLgOzLHB63IUWfBpNucQjND6d3AOudO+H3RWQ==} + hasBin: true + uuid@8.3.2: resolution: {integrity: sha512-+NYs2QeMWy+GWFOEm9xnn6HCDp0l7QBD7ml8zLUmJ+93Q5NF0NocErnwkTkXVFNiX3/fpC6afS8Dhb/gz7R7eg==} hasBin: true @@ -6484,6 +6497,8 @@ snapshots: '@types/trusted-types@2.0.7': {} + '@types/uuid@10.0.0': {} + '@types/xml2js@0.4.14': dependencies: '@types/node': 20.14.11 @@ -10035,6 +10050,8 @@ snapshots: util-deprecate@1.0.2: {} + uuid@10.0.0: {} + uuid@8.3.2: {} validate-npm-package-license@3.0.4: diff --git a/src/lib/auth.ts b/src/lib/auth.ts index 1193a3af..cedebb9a 100644 --- a/src/lib/auth.ts +++ b/src/lib/auth.ts @@ -1,15 +1,22 @@ import { AuthOptions } from 'next-auth' import CredentialsProvider from 'next-auth/providers/credentials' import qs from 'qs' +import { v4 as uuidv4 } from 'uuid' import { parseStringPromise } from 'xml2js' import { APP_URL, PLEX_API_ENDPOINT, - PLEX_CLIENT_IDENTIFIER, - PLEX_CLIENT_NAME, + PLEX_PRODUCT_NAME, } from '../utils/constants' import fetchTautulli from '../utils/fetchTautulli' +function getClientIdentifier(): string { + const clientId = localStorage.getItem('plexClientId') || uuidv4() + localStorage.setItem('plexClientId', clientId) + + return clientId +} + export const authOptions: AuthOptions = { providers: [ CredentialsProvider({ @@ -109,18 +116,16 @@ type PlexPinResponse = { } async function fetchPlexPins(): Promise { + const clientIdentifier = getClientIdentifier() + try { - const res = await fetch(`${PLEX_API_ENDPOINT}/pins`, { + const res = await fetch(`${PLEX_API_ENDPOINT}/pins?strong=true`, { method: 'POST', headers: { Accept: 'application/json', - 'Content-Type': 'application/x-www-form-urlencoded', + 'X-Plex-Product': PLEX_PRODUCT_NAME, + 'X-Plex-Client-Identifier': clientIdentifier, }, - body: new URLSearchParams({ - strong: 'true', - 'X-Plex-Product': PLEX_CLIENT_NAME, - 'X-Plex-Client-Identifier': PLEX_CLIENT_IDENTIFIER, - }), }) if (!res.ok) { @@ -139,6 +144,7 @@ async function fetchPlexPins(): Promise { export async function createPlexAuthUrl() { const { id, code } = await fetchPlexPins() const forwardUrl = `${APP_URL}?plexPinId=${id}` + const clientIdentifier = getClientIdentifier() if (!forwardUrl) { console.error('Base url is not configured!') @@ -147,12 +153,12 @@ export async function createPlexAuthUrl() { const authAppUrl = 'https://app.plex.tv/auth#?' + qs.stringify({ - clientID: PLEX_CLIENT_IDENTIFIER, + clientID: clientIdentifier, code, forwardUrl, context: { device: { - product: PLEX_CLIENT_NAME, + product: PLEX_PRODUCT_NAME, }, }, }) @@ -161,12 +167,14 @@ export async function createPlexAuthUrl() { } export async function getPlexAuthToken(pinId: string) { + const clientIdentifier = getClientIdentifier() + try { const res = await fetch(`${PLEX_API_ENDPOINT}/pins/${pinId}`, { method: 'GET', headers: { Accept: 'application/json', - 'X-Plex-Client-Identifier': PLEX_CLIENT_IDENTIFIER, + 'X-Plex-Client-Identifier': clientIdentifier, }, }) @@ -185,19 +193,17 @@ export async function getPlexAuthToken(pinId: string) { } export async function verifyPlexAuthToken(authToken: string) { + const clientIdentifier = getClientIdentifier() + try { - const res = await fetch(`${PLEX_API_ENDPOINT}/user`, { + const res = await fetch(`${PLEX_API_ENDPOINT}/user?strong=true`, { method: 'POST', headers: { Accept: 'application/json', - 'Content-Type': 'application/x-www-form-urlencoded', - }, - body: new URLSearchParams({ - strong: 'true', - 'X-Plex-Product': PLEX_CLIENT_NAME, - 'X-Plex-Client-Identifier': PLEX_CLIENT_IDENTIFIER, 'X-Plex-Token': authToken, - }), + 'X-Plex-Product': PLEX_PRODUCT_NAME, + 'X-Plex-Client-Identifier': clientIdentifier, + }, }) if (!res.ok) { diff --git a/src/utils/constants.ts b/src/utils/constants.ts index 6391c5dd..1c15fc43 100644 --- a/src/utils/constants.ts +++ b/src/utils/constants.ts @@ -59,8 +59,7 @@ export const META_TITLE: string = 'Plex Rewind' export const META_TITLE_TEMPLATE: string = '%s | Plex Rewind' export const PLEX_API_ENDPOINT = 'https://plex.tv/api/v2' -export const PLEX_CLIENT_NAME = 'Plex Rewind' -export const PLEX_CLIENT_IDENTIFIER = 'plex-rewind' +export const PLEX_PRODUCT_NAME = 'Plex Rewind' export const APP_URL = env('NEXT_PUBLIC_SITE_URL') || 'http://localhost:8383'