data endpoint for entity 90008 (aka. a website)
0
fork

Configure Feed

Select the types of activity you want to include in your feed.

refactor: better auth code

dusk ff7cf961 76a058a3

+128 -76
+114 -56
src/lib/guestbookAuth.ts
··· 12 12 scope: string, 13 13 } 14 14 15 - export const discord = { 16 - name: 'discord', 17 - getAuthUrl: (state: string, scopes: string[] = []) => { 18 - const client_id = env.DISCORD_CLIENT_ID 19 - const redir_uri = encodeURIComponent(callbackUrl) 20 - const scope = scopes.join("+") 21 - return `https://discord.com/oauth2/authorize?client_id=${client_id}&response_type=code&redirect_uri=${redir_uri}&scope=${scope}&state=${state}` 22 - }, 23 - getToken: async (code: string): Promise<TokenResponse> => { 24 - const api = `https://discord.com/api/oauth2/token` 25 - const body = new URLSearchParams({ 26 - client_id: env.DISCORD_CLIENT_ID, 27 - client_secret: env.DISCORD_CLIENT_SECRET, 28 - grant_type: 'authorization_code', 29 - redirect_uri: callbackUrl, 30 - code, 31 - }) 32 - const resp = await fetch(api, { method: 'POST', body }) 33 - if (resp.status !== 200) { 34 - throw new Error("woopsies, couldnt get oauth token") 35 - } 36 - const tokenResp: any = await resp.json() 15 + class OauthConfig { 16 + clientId: string; 17 + clientSecret: string; 18 + 19 + authUrl: URL; 20 + tokenUrl: URL; 21 + 22 + joinScopes: (scopes: string[]) => string = (scopes) => scopes.join("+"); 23 + getAuthParams: (params: Record<string, string>, config: OauthConfig) => Record<string, string> = (params) => { return params }; 24 + getTokenParams: (params: Record<string, string>, config: OauthConfig) => Record<string, string> = (params) => { return params }; 25 + extractTokenResponse: (tokenResp: any) => TokenResponse = (tokenResp) => { 37 26 return { 38 27 accessToken: tokenResp.access_token, 39 28 tokenType: tokenResp.token_type, 40 29 scope: tokenResp.scope, 41 30 } 42 - }, 31 + }; 32 + 33 + tokenReqHeaders: Record<string, string> = {}; 34 + 35 + constructor(clientId: string, clientSecret: string, authUrl: URL | string, tokenUrl: URL | string) { 36 + this.clientId = clientId; 37 + this.clientSecret = clientSecret; 38 + this.authUrl = typeof authUrl === 'string' ? new URL(authUrl) : authUrl 39 + this.tokenUrl = typeof tokenUrl === 'string' ? new URL(tokenUrl) : tokenUrl 40 + } 41 + 42 + withJoinScopes(f: typeof this.joinScopes) { 43 + this.joinScopes = f 44 + return this 45 + } 46 + withGetAuthParams(f: typeof this.getAuthParams) { 47 + this.getAuthParams = f 48 + return this 49 + } 50 + withGetTokenParams(f: typeof this.getTokenParams) { 51 + this.getTokenParams = f 52 + return this 53 + } 54 + withExtractTokenResponse(f: typeof this.extractTokenResponse) { 55 + this.extractTokenResponse = f 56 + return this 57 + } 58 + withTokenRequestHeaders(f: typeof this.tokenReqHeaders) { 59 + this.tokenReqHeaders = f 60 + return this 61 + } 62 + } 63 + 64 + const genericOauthClient = (oauthConfig: OauthConfig) => { 65 + return { 66 + getAuthUrl: (state: string, scopes: string[] = []) => { 67 + const redirect_uri = callbackUrl 68 + const scope = oauthConfig.joinScopes(scopes) 69 + const baseParams = { 70 + client_id: oauthConfig.clientId, 71 + redirect_uri, 72 + scope, 73 + state, 74 + } 75 + const params = oauthConfig.getAuthParams(baseParams, oauthConfig) 76 + const urlParams = new URLSearchParams(params) 77 + const urlRaw = `${oauthConfig.authUrl}?${urlParams.toString()}` 78 + return new URL(urlRaw) 79 + }, 80 + getToken: async (code: string): Promise<TokenResponse> => { 81 + const api = oauthConfig.tokenUrl 82 + const baseParams = { 83 + client_id: oauthConfig.clientId, 84 + client_secret: oauthConfig.clientSecret, 85 + redirect_uri: callbackUrl, 86 + code, 87 + } 88 + const body = new URLSearchParams(oauthConfig.getTokenParams(baseParams, oauthConfig)) 89 + const resp = await fetch(api, { method: 'POST', body, headers: oauthConfig.tokenReqHeaders }) 90 + if (resp.status !== 200) { 91 + throw new Error("woopsies, couldnt get oauth token") 92 + } 93 + const tokenResp: any = await resp.json() 94 + return oauthConfig.extractTokenResponse(tokenResp) 95 + } 96 + } 97 + } 98 + 99 + export const discord = { 100 + name: 'discord', 101 + ...genericOauthClient( 102 + new OauthConfig( 103 + env.DISCORD_CLIENT_ID, 104 + env.DISCORD_CLIENT_SECRET, 105 + 'https://discord.com/oauth2/authorize', 106 + 'https://discord.com/api/oauth2/token', 107 + ) 108 + .withGetAuthParams((params) => { return { ...params, response_type: 'code', prompt: 'none' } }) 109 + .withGetTokenParams((params) => { return { ...params, grant_type: 'authorization_code' } }) 110 + ), 43 111 identifyToken: async (tokenResp: TokenResponse): Promise<string> => { 44 112 const api = `https://discord.com/api/users/@me` 45 - const resp = await fetch(api, {headers: { 46 - 'Authorization': `${tokenResp.tokenType} ${tokenResp.accessToken}` 47 - }}) 113 + const resp = await fetch(api, { 114 + headers: { 115 + 'Authorization': `${tokenResp.tokenType} ${tokenResp.accessToken}` 116 + } 117 + }) 48 118 if (resp.status !== 200) { 49 119 throw new Error("woopsies, couldnt validate access token") 50 120 } ··· 52 122 return body.username 53 123 } 54 124 } 125 + 55 126 export const github = { 56 127 name: 'github', 57 - getAuthUrl: (state: string, scopes: string[] = []) => { 58 - const client_id = env.GITHUB_CLIENT_ID 59 - const redir_uri = encodeURIComponent(callbackUrl) 60 - const scope = encodeURIComponent(scopes.join(" ")) 61 - return `https://github.com/login/oauth/authorize?client_id=${client_id}&redirect_uri=${redir_uri}&scope=${scope}&state=${state}` 62 - }, 63 - getToken: async (code: string): Promise<TokenResponse> => { 64 - const api = `https://github.com/login/oauth/access_token` 65 - const body = new URLSearchParams({ 66 - client_id: env.GITHUB_CLIENT_ID, 67 - client_secret: env.GITHUB_CLIENT_SECRET, 68 - redirect_uri: callbackUrl, 69 - code, 70 - }) 71 - const resp = await fetch(api, { method: 'POST', body, headers: { 'Accept': 'application/json' } }) 72 - if (resp.status !== 200) { 73 - throw new Error("woopsies, couldnt get oauth token") 74 - } 75 - const tokenResp: any = await resp.json() 76 - return { 77 - accessToken: tokenResp.access_token, 78 - tokenType: tokenResp.token_type, 79 - scope: tokenResp.scope, 80 - } 81 - }, 128 + ...genericOauthClient( 129 + new OauthConfig( 130 + env.GITHUB_CLIENT_ID, 131 + env.GITHUB_CLIENT_SECRET, 132 + 'https://github.com/login/oauth/authorize', 133 + 'https://github.com/login/oauth/access_token', 134 + ) 135 + .withJoinScopes((s) => { return s.join(" ") }) 136 + .withTokenRequestHeaders({ 'Accept': 'application/json' }) 137 + ), 82 138 identifyToken: async (tokenResp: TokenResponse): Promise<string> => { 83 139 const api = `https://api.github.com/user` 84 - const resp = await fetch(api, {headers: { 85 - 'Authorization': `${tokenResp.tokenType} ${tokenResp.accessToken}` 86 - }}) 140 + const resp = await fetch(api, { 141 + headers: { 142 + 'Authorization': `${tokenResp.tokenType} ${tokenResp.accessToken}` 143 + } 144 + }) 87 145 if (resp.status !== 200) { 88 146 throw new Error("woopsies, couldnt validate access token") 89 147 } ··· 130 188 switch (name) { 131 189 case "discord": 132 190 return discord 133 - 191 + 134 192 case "github": 135 193 return github 136 - 194 + 137 195 default: 138 196 return null 139 197 }
+14 -20
src/routes/+layout.svelte
··· 40 40 } 41 41 42 42 const title = getTitle(data.route); 43 + 44 + const svgSquiggles = [ 45 + [2], 46 + [3], 47 + [2], 48 + [3], 49 + [1], 50 + ] 43 51 </script> 44 52 45 53 <svelte:head> ··· 65 73 66 74 <svg xmlns="http://www.w3.org/2000/svg" version="1.1" class="absolute -z-50"> 67 75 <defs> 68 - <filter id="squiggly-0"> 69 - <feTurbulence id="turbulence" baseFrequency="0.02" numOctaves="3" result="noise" seed="0" /> 70 - <feDisplacementMap id="displacement" in="SourceGraphic" in2="noise" scale="2" /> 71 - </filter> 72 - <filter id="squiggly-1"> 73 - <feTurbulence id="turbulence" baseFrequency="0.02" numOctaves="3" result="noise" seed="1" /> 74 - <feDisplacementMap in="SourceGraphic" in2="noise" scale="3" /> 75 - </filter> 76 - <filter id="squiggly-2"> 77 - <feTurbulence id="turbulence" baseFrequency="0.02" numOctaves="3" result="noise" seed="2" /> 78 - <feDisplacementMap in="SourceGraphic" in2="noise" scale="2" /> 76 + {#each svgSquiggles as [scale], index} 77 + <filter id="squiggly-{index}"> 78 + <feTurbulence id="turbulence" baseFrequency="0.02" numOctaves="3" result="noise" seed={index} /> 79 + <feDisplacementMap in="SourceGraphic" in2="noise" {scale} /> 79 80 </filter> 80 - <filter id="squiggly-3"> 81 - <feTurbulence id="turbulence" baseFrequency="0.02" numOctaves="3" result="noise" seed="3" /> 82 - <feDisplacementMap in="SourceGraphic" in2="noise" scale="3" /> 83 - </filter> 84 - <filter id="squiggly-4"> 85 - <feTurbulence id="turbulence" baseFrequency="0.02" numOctaves="3" result="noise" seed="4" /> 86 - <feDisplacementMap in="SourceGraphic" in2="noise" scale="1" /> 87 - </filter> 81 + {/each} 88 82 </defs> 89 83 </svg> 90 84 ··· 92 86 <slot /> 93 87 </div> 94 88 95 - <nav class="w-full max-h-[6vh] fixed bottom-0 z-10 bg-ralsei-black"> 89 + <nav class="w-full min-h-[5vh] max-h-[6vh] fixed bottom-0 z-10 bg-ralsei-black"> 96 90 <div 97 91 class=" 98 92 max-w-full max-h-fit p-1 overflow-auto