From 924e05f4cdf0759b79c956583b976445bfe4399f Mon Sep 17 00:00:00 2001 From: Samuel LEFEVRE Date: Tue, 14 Nov 2023 17:30:50 +0100 Subject: [PATCH 1/3] add pkce-flow --- src/runtime/server/lib/oauth/battledotnet.ts | 41 +++++++++++++++++--- 1 file changed, 36 insertions(+), 5 deletions(-) diff --git a/src/runtime/server/lib/oauth/battledotnet.ts b/src/runtime/server/lib/oauth/battledotnet.ts index 884d738f..4bfa17b2 100644 --- a/src/runtime/server/lib/oauth/battledotnet.ts +++ b/src/runtime/server/lib/oauth/battledotnet.ts @@ -1,10 +1,10 @@ import type { H3Event, H3Error } from 'h3' import { eventHandler, createError, getQuery, getRequestURL, sendRedirect } from 'h3' import { ofetch } from 'ofetch' -import { withQuery, parsePath } from 'ufo' +import { withQuery, parsePath, getQuery as ufoGetQuery } from 'ufo' import { defu } from 'defu' import { useRuntimeConfig } from '#imports' -import { randomUUID } from 'crypto' +import { randomUUID, createHash } from 'crypto' export interface OAuthBattledotnetConfig { /** @@ -79,7 +79,7 @@ export function battledotnetEventHandler({ config, onSuccess, onError }: OAuthCo if (!onError) throw error return onError(event, error) } - + if (!code) { config.scope = config.scope || ['openid'] config.region = config.region || 'EU' @@ -89,6 +89,13 @@ export function battledotnetEventHandler({ config, onSuccess, onError }: OAuthCo config.tokenURL = 'https://oauth.battlenet.com.cn/token' } + // PKCE flow + const stateGen = randomUUID() + const hash = createHash('sha3-256') + const hashedState = hash.update(stateGen).digest('base64') + + await useStorage().setItem('stateBattledotnet', hashedState) + // Redirect to Battle.net Oauth page const redirectUrl = getRequestURL(event).href return sendRedirect( @@ -97,7 +104,7 @@ export function battledotnetEventHandler({ config, onSuccess, onError }: OAuthCo client_id: config.clientId, redirect_uri: redirectUrl, scope: config.scope.join(' '), - state: randomUUID(), // Todo: handle PKCE flow + state: hashedState, // Todo: handle PKCE flow response_type: 'code', }) ) @@ -109,6 +116,30 @@ export function battledotnetEventHandler({ config, onSuccess, onError }: OAuthCo config.scope.push('openid') } + const { state } = ufoGetQuery(redirectUrl) + + if (!state) { + const error = createError({ + statusCode: 401, + message: 'State is required', + data: query + }) + if (!onError) throw error + return onError(event, error) + } + + const storageState = await useStorage().getItem('stateBattledotnet') + + if (storageState !== (state as string).replace(/\s/g, '+')) { + const error = createError({ + statusCode: 401, + message: 'State is not valid', + data: query + }) + if (!onError) throw error + return onError(event, error) + } + const authCode = Buffer.from(`${config.clientId}:${config.clientSecret}`).toString('base64') const tokens: any = await $fetch( @@ -128,7 +159,7 @@ export function battledotnetEventHandler({ config, onSuccess, onError }: OAuthCo } ).catch((error) => { return { error } - }) + }) if (tokens.error) { const error = createError({ From c8a3c226ae32bf63554f63daf127030b5b2884a1 Mon Sep 17 00:00:00 2001 From: Samuel LEFEVRE Date: Tue, 14 Nov 2023 17:59:56 +0100 Subject: [PATCH 2/3] fix and bettler names --- src/runtime/server/lib/oauth/battledotnet.ts | 17 +++++++++++------ 1 file changed, 11 insertions(+), 6 deletions(-) diff --git a/src/runtime/server/lib/oauth/battledotnet.ts b/src/runtime/server/lib/oauth/battledotnet.ts index 4bfa17b2..82898a8f 100644 --- a/src/runtime/server/lib/oauth/battledotnet.ts +++ b/src/runtime/server/lib/oauth/battledotnet.ts @@ -90,11 +90,11 @@ export function battledotnetEventHandler({ config, onSuccess, onError }: OAuthCo } // PKCE flow - const stateGen = randomUUID() + const codeVerifier = randomUUID() const hash = createHash('sha3-256') - const hashedState = hash.update(stateGen).digest('base64') + const codeChallenge = hash.update(codeVerifier).digest('base64') - await useStorage().setItem('stateBattledotnet', hashedState) + await useStorage().setItem('codeVerifierBattledotnet', codeVerifier) // Redirect to Battle.net Oauth page const redirectUrl = getRequestURL(event).href @@ -104,7 +104,7 @@ export function battledotnetEventHandler({ config, onSuccess, onError }: OAuthCo client_id: config.clientId, redirect_uri: redirectUrl, scope: config.scope.join(' '), - state: hashedState, // Todo: handle PKCE flow + state: codeChallenge, // Todo: handle PKCE flow response_type: 'code', }) ) @@ -128,9 +128,14 @@ export function battledotnetEventHandler({ config, onSuccess, onError }: OAuthCo return onError(event, error) } - const storageState = await useStorage().getItem('stateBattledotnet') + const codeVerifier = await useStorage().getItem('codeVerifierBattledotnet') - if (storageState !== (state as string).replace(/\s/g, '+')) { + console.log('codeVerifier', codeVerifier) + + const hash = createHash('sha3-256') + const codeChallenge = hash.update(codeVerifier as string).digest('base64') + + if (codeChallenge !== (state as string).replace(/\s/g, '+')) { const error = createError({ statusCode: 401, message: 'State is not valid', From 5af1361a2174e68760188812cddca905860004cb Mon Sep 17 00:00:00 2001 From: Samuel LEFEVRE Date: Tue, 14 Nov 2023 18:01:48 +0100 Subject: [PATCH 3/3] rm console.log --- src/runtime/server/lib/oauth/battledotnet.ts | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/src/runtime/server/lib/oauth/battledotnet.ts b/src/runtime/server/lib/oauth/battledotnet.ts index 82898a8f..efc79059 100644 --- a/src/runtime/server/lib/oauth/battledotnet.ts +++ b/src/runtime/server/lib/oauth/battledotnet.ts @@ -128,9 +128,7 @@ export function battledotnetEventHandler({ config, onSuccess, onError }: OAuthCo return onError(event, error) } - const codeVerifier = await useStorage().getItem('codeVerifierBattledotnet') - - console.log('codeVerifier', codeVerifier) + const codeVerifier = await useStorage().getItem('codeVerifierBattledotnet') const hash = createHash('sha3-256') const codeChallenge = hash.update(codeVerifier as string).digest('base64')