Skip to content

Commit e63f16f

Browse files
authored
Merge branch 'main' into fix/tanstack-start-package
2 parents f379d6c + c4ed837 commit e63f16f

File tree

23 files changed

+269
-128
lines changed

23 files changed

+269
-128
lines changed

app/components/Header/AuthModal.client.vue

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -50,6 +50,14 @@ watch(handleInput, newHandleInput => {
5050
handleInput.value = normalized
5151
}
5252
})
53+
54+
watch(user, async newUser => {
55+
if (newUser?.relogin) {
56+
await authRedirect(newUser.did, {
57+
redirectTo: route.fullPath,
58+
})
59+
}
60+
})
5361
</script>
5462

5563
<template>

app/components/Package/Playgrounds.vue

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,10 @@ const providerIcons: Record<string, string> = {
1616
'nuxt-new': 'i-simple-icons:nuxtdotjs',
1717
'vite-new': 'i-simple-icons:vite',
1818
'jsfiddle': 'i-lucide:code',
19+
'typescript-playground': 'i-simple-icons:typescript',
20+
'solid-playground': 'i-simple-icons:solid',
21+
'svelte-playground': 'i-simple-icons:svelte',
22+
'tailwind-playground': 'i-simple-icons:tailwindcss',
1923
}
2024
2125
// Map provider id to color class
@@ -29,6 +33,10 @@ const providerColors: Record<string, string> = {
2933
'nuxt-new': 'text-provider-nuxt',
3034
'vite-new': 'text-provider-vite',
3135
'jsfiddle': 'text-provider-jsfiddle',
36+
'typescript-playground': 'text-provider-typescript',
37+
'solid-playground': 'text-provider-solid',
38+
'svelte-playground': 'text-provider-svelte',
39+
'tailwind-playground': 'text-provider-tailwind',
3240
}
3341
3442
function getIcon(provider: string): string {

i18n/locales/de-DE.json

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -364,7 +364,9 @@
364364
"downloads": "Downloads",
365365
"likes": "Likes",
366366
"contributors": "Mitwirkende"
367-
}
367+
},
368+
"play_animation": "Animation abspielen",
369+
"pause_animation": "Animation pausieren"
368370
},
369371
"downloads": {
370372
"title": "Wöchentliche Downloads",

lunaria/files/de-DE.json

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -363,7 +363,9 @@
363363
"downloads": "Downloads",
364364
"likes": "Likes",
365365
"contributors": "Mitwirkende"
366-
}
366+
},
367+
"play_animation": "Animation abspielen",
368+
"pause_animation": "Animation pausieren"
367369
},
368370
"downloads": {
369371
"title": "Wöchentliche Downloads",

nuxt.config.ts

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -37,6 +37,7 @@ export default defineNuxtConfig({
3737
github: {
3838
orgToken: '',
3939
},
40+
oauthJwkOne: process.env.OAUTH_JWK_ONE || undefined,
4041
// Upstash Redis for distributed OAuth token refresh locking in production
4142
upstash: {
4243
redisRestUrl: process.env.UPSTASH_KV_REST_API_URL || process.env.KV_REST_API_URL || '',
@@ -122,6 +123,7 @@ export default defineNuxtConfig({
122123
'/_avatar/**': { isr: 3600, proxy: 'https://www.gravatar.com/avatar/**' },
123124
'/opensearch.xml': { isr: true },
124125
'/oauth-client-metadata.json': { prerender: true },
126+
'/.well-known/jwks.json': { prerender: true },
125127
// never cache
126128
'/api/auth/**': { isr: false, cache: false },
127129
'/api/social/**': { isr: false, cache: false },

package.json

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -34,6 +34,7 @@
3434
"generate:sprite": "node scripts/generate-file-tree-sprite.ts",
3535
"generate:fixtures": "node scripts/generate-fixtures.ts",
3636
"generate:lexicons": "lex build --lexicons lexicons --out shared/types/lexicons --clear",
37+
"generate:jwk": "node scripts/gen-jwk.ts",
3738
"test": "vite test",
3839
"test:a11y": "pnpm build:test && LIGHTHOUSE_COLOR_MODE=dark pnpm test:a11y:prebuilt && LIGHTHOUSE_COLOR_MODE=light pnpm test:a11y:prebuilt",
3940
"test:a11y:prebuilt": "./scripts/lighthouse.sh",

scripts/gen-jwk.ts

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
import { JoseKey } from '@atproto/oauth-client-node'
2+
3+
async function run() {
4+
const kid = Date.now().toString()
5+
const key = await JoseKey.generate(['ES256'], kid)
6+
const jwk = key.privateJwk
7+
8+
console.log(JSON.stringify(jwk))
9+
}
10+
11+
await run()

server/api/auth/atproto.get.ts

Lines changed: 8 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -1,19 +1,16 @@
11
import type { OAuthSession } from '@atproto/oauth-client-node'
2-
import { NodeOAuthClient, OAuthCallbackError } from '@atproto/oauth-client-node'
2+
import { OAuthCallbackError } from '@atproto/oauth-client-node'
33
import { createError, getQuery, sendRedirect, setCookie, getCookie, deleteCookie } from 'h3'
44
import type { H3Event } from 'h3'
5-
import { getOAuthLock } from '#server/utils/atproto/lock'
6-
import { useOAuthStorage } from '#server/utils/atproto/storage'
75
import { SLINGSHOT_HOST } from '#shared/utils/constants'
86
import { useServerSession } from '#server/utils/server-session'
9-
import { handleResolver } from '#server/utils/atproto/oauth'
107
import { handleApiError } from '#server/utils/error-handler'
118
import type { DidString } from '@atproto/lex'
129
import { Client } from '@atproto/lex'
1310
import * as com from '#shared/types/lexicons/com'
1411
import * as app from '#shared/types/lexicons/app'
1512
import { isAtIdentifierString } from '@atproto/lex'
16-
import { scope, getOauthClientMetadata } from '#server/utils/atproto/oauth'
13+
import { scope } from '#server/utils/atproto/oauth'
1714
import { UNSET_NUXT_SESSION_PASSWORD } from '#shared/utils/constants'
1815
// @ts-expect-error virtual file from oauth module
1916
import { clientUri } from '#oauth/config'
@@ -28,17 +25,7 @@ export default defineEventHandler(async event => {
2825
}
2926

3027
const query = getQuery(event)
31-
const clientMetadata = getOauthClientMetadata()
3228
const session = await useServerSession(event)
33-
const { stateStore, sessionStore } = useOAuthStorage(session)
34-
35-
const atclient = new NodeOAuthClient({
36-
stateStore,
37-
sessionStore,
38-
clientMetadata,
39-
requestLock: getOAuthLock(),
40-
handleResolver,
41-
})
4229

4330
if (query.handle) {
4431
// Initiate auth flow
@@ -66,10 +53,13 @@ export default defineEventHandler(async event => {
6653
}
6754

6855
try {
69-
const redirectUrl = await atclient.authorize(query.handle, {
56+
const redirectUrl = await event.context.oauthClient.authorize(query.handle, {
7057
scope,
7158
prompt: query.create ? 'create' : undefined,
72-
ui_locales: query.locale?.toString(),
59+
// TODO: I do not beleive this is working as expected on
60+
// a unsupported locale on the PDS. Gives Invalid at body.ui_locales
61+
// Commenting out for now
62+
// ui_locales: query.locale?.toString(),
7363
state: encodeOAuthState(event, { redirectPath }),
7464
})
7565

@@ -87,7 +77,7 @@ export default defineEventHandler(async event => {
8777
// Handle callback
8878
try {
8979
const params = new URLSearchParams(query as Record<string, string>)
90-
const result = await atclient.callback(params)
80+
const result = await event.context.oauthClient.callback(params)
9181
try {
9282
const state = decodeOAuthState(event, result.state)
9383
const profile = await getMiniProfile(result.session)

server/api/auth/session.get.ts

Lines changed: 13 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,23 @@
11
import { PublicUserSessionSchema } from '#shared/schemas/publicUserSession'
22
import { safeParse } from 'valibot'
33

4-
export default defineEventHandler(async event => {
5-
const serverSession = await useServerSession(event)
4+
export default eventHandlerWithOAuthSession(async (event, _, serverSession) => {
65
const result = safeParse(PublicUserSessionSchema, serverSession.data.public)
76
if (!result.success) {
87
return null
98
}
109

10+
// A one time redirect to upgrade the previous sessions.
11+
// Can remove in 2 weeks from merge if we'd like
12+
if (serverSession.data.oauthSession && serverSession.data?.public?.did) {
13+
await serverSession.update({
14+
oauthSession: undefined,
15+
})
16+
return {
17+
...result.output,
18+
relogin: true,
19+
}
20+
}
21+
1122
return result.output
1223
})

server/plugins/oauth-client.ts

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
1+
import type { NodeOAuthClient } from '@atproto/oauth-client-node'
2+
3+
/**
4+
* Creates a long living instance of the NodeOAuthClient.
5+
*/
6+
export default defineNitroPlugin(async nitroApp => {
7+
const oauthClient = await getNodeOAuthClient()
8+
9+
// Attach to event context for access in composables via useRequestEvent()
10+
nitroApp.hooks.hook('request', event => {
11+
event.context.oauthClient = oauthClient
12+
})
13+
})
14+
15+
// Extend the H3EventContext type
16+
declare module 'h3' {
17+
interface H3EventContext {
18+
oauthClient: NodeOAuthClient
19+
}
20+
}

0 commit comments

Comments
 (0)