3
3
4
4
import { getLogger } from "../../../log.ts" ;
5
5
import { jsonError , jsonOk } from "../../responses.ts" ;
6
- import { clearCookie , getEncryptedCookie } from "../cookies.ts" ;
6
+ import { clearCookie } from "../cookies.ts" ;
7
7
import type { RouteParams } from "./mod.ts" ;
8
8
import * as z from "zod" ;
9
9
import { sha256 } from "../../../crypto.ts" ;
@@ -19,12 +19,12 @@ const paramSchema = z.union([
19
19
code_verifier : z . string ( ) ,
20
20
client_id : z . string ( ) ,
21
21
redirect_uri : z . string ( ) ,
22
- // scope: z.string().optional(),
22
+ scope : z . string ( ) . optional ( ) ,
23
23
} ) ,
24
24
z . object ( {
25
25
grant_type : z . literal ( "refresh_token" ) ,
26
26
refresh_token : z . string ( ) ,
27
- // scope: z.string().optional(),
27
+ scope : z . string ( ) . optional ( ) ,
28
28
} ) ,
29
29
] ) ;
30
30
@@ -34,6 +34,7 @@ export async function token(params: RouteParams) {
34
34
const url = new URL ( request . url ) ;
35
35
const resHeaders = clearCookie ( url . hostname , engine . name , headers ) ;
36
36
const origin = request . headers . get ( "origin" ) ?? "" ;
37
+ const redis = engine . tg . typegate . redis ;
37
38
38
39
if ( ! paramSchema . safeParse ( body ) . success ) {
39
40
return jsonError ( {
@@ -43,17 +44,24 @@ export async function token(params: RouteParams) {
43
44
} ) ;
44
45
}
45
46
46
- if ( ! engine . tg . typegate . redis ) {
47
+ if ( ! redis ) {
47
48
throw new Error ( "no redis connection" ) ;
48
49
}
49
50
50
51
try {
51
52
if ( body . grant_type === "authorization_code" ) {
52
- const { token, state, code } = await getEncryptedCookie (
53
- request . headers ,
54
- engine . name ,
55
- engine . tg . typegate . cryptoKeys ,
56
- ) ;
53
+ const rawData = await redis . get ( `code:${ body . code } ` ) ;
54
+
55
+ if ( ! rawData ) {
56
+ return jsonError ( {
57
+ status : 400 ,
58
+ message : "invalid code" ,
59
+ headers : resHeaders ,
60
+ } ) ;
61
+ }
62
+
63
+ const { state, profile, provider } = JSON . parse ( rawData ) ;
64
+ const auth = engine . tg . auths . get ( provider ) as OAuth2Auth ;
57
65
const expectedChallenge = await sha256 ( body . code_verifier ) ;
58
66
59
67
if ( ! state . redirectUri . startsWith ( origin ) ) {
@@ -66,7 +74,6 @@ export async function token(params: RouteParams) {
66
74
67
75
if (
68
76
state . codeChallenge !== expectedChallenge ||
69
- code !== body . code ||
70
77
body . client_id !== state . id ||
71
78
body . redirect_uri !== state . redirectUri
72
79
) {
@@ -77,33 +84,25 @@ export async function token(params: RouteParams) {
77
84
} ) ;
78
85
}
79
86
80
- const cachedData = await engine . tg . typegate . redis ?. get (
81
- `code:${ body . code } ` ,
82
- ) ;
83
-
84
- if ( ! cachedData ) {
85
- return jsonError ( {
86
- status : 401 ,
87
- message : "code expired" ,
88
- headers : resHeaders ,
89
- } ) ;
87
+ if ( ! auth ) {
88
+ throw new Error ( `provider not found: ${ provider } ` ) ;
90
89
}
91
90
92
- await engine . tg . typegate . redis . set (
91
+ const token = await auth . createJWT ( request , profile ) ;
92
+
93
+ await redis . set (
93
94
`refresh:${ token . refresh_token } ` ,
94
- cachedData ,
95
+ JSON . stringify ( { profile , provider } ) ,
95
96
{ ex : engine . tg . typegate . config . base . jwt_max_duration_sec } ,
96
97
) ;
97
- await engine . tg . typegate . redis . del ( `code:${ body . code } ` ) ;
98
+ await redis . del ( `code:${ body . code } ` ) ;
98
99
resHeaders . set ( "content-type" , "application/json" ) ;
99
100
100
101
return jsonOk ( { data : { ...token } , headers : resHeaders } ) ;
101
102
}
102
103
103
104
if ( body . grant_type === "refresh_token" ) {
104
- const rawData = await engine . tg . typegate . redis . get (
105
- `refresh:${ body . refresh_token } ` ,
106
- ) ;
105
+ const rawData = await redis . get ( `refresh:${ body . refresh_token } ` ) ;
107
106
108
107
if ( ! rawData ) {
109
108
return jsonError ( {
@@ -113,24 +112,22 @@ export async function token(params: RouteParams) {
113
112
} ) ;
114
113
}
115
114
116
- const cachedData = JSON . parse ( rawData ) as {
115
+ const { provider , profile } = JSON . parse ( rawData ) as {
117
116
profile : Record < string , unknown > ;
118
117
provider : string ;
119
118
} ;
120
- const auth = engine . tg . auths . get ( cachedData . provider ) as OAuth2Auth ;
119
+ const auth = engine . tg . auths . get ( provider ) as OAuth2Auth ;
121
120
122
121
if ( ! auth ) {
123
- throw new Error ( `provider not found: ${ cachedData . provider } ` ) ;
122
+ throw new Error ( `provider not found: ${ provider } ` ) ;
124
123
}
125
124
126
- const newTokens = await auth . createJWT ( request , cachedData . profile ) ;
125
+ const newTokens = await auth . createJWT ( request , profile ) ;
127
126
128
- await engine . tg . typegate . redis . set (
129
- `refresh:${ newTokens . refresh_token } ` ,
130
- rawData ,
131
- { ex : engine . tg . typegate . config . base . jwt_max_duration_sec } ,
132
- ) ;
133
- await engine . tg . typegate . redis . del ( `refresh:${ body . refresh_token } ` ) ;
127
+ await redis . set ( `refresh:${ newTokens . refresh_token } ` , rawData , {
128
+ ex : engine . tg . typegate . config . base . jwt_max_duration_sec ,
129
+ } ) ;
130
+ await redis . del ( `refresh:${ body . refresh_token } ` ) ;
134
131
135
132
return jsonOk ( {
136
133
headers : resHeaders ,
0 commit comments