drbh commited on
Commit
c202a37
Β·
1 Parent(s): a8fb6fa

fix: improve token rention

Browse files
app/lib/account-linking.server.ts CHANGED
@@ -5,6 +5,7 @@ export interface AccountLink {
5
  githubUserId: string;
6
  githubLogin: string;
7
  huggingfaceUsername: string;
 
8
  linkedAt: string;
9
  lastUpdated: string;
10
  }
@@ -79,7 +80,7 @@ export class AccountLinkingService {
79
  /**
80
  * Create a new account link
81
  */
82
- createLink(githubUserId: string, githubLogin: string, huggingfaceUsername: string): AccountLink {
83
  const data = this.readData();
84
  const now = new Date().toISOString();
85
 
@@ -99,6 +100,7 @@ export class AccountLinkingService {
99
  githubUserId,
100
  githubLogin,
101
  huggingfaceUsername,
 
102
  linkedAt: now,
103
  lastUpdated: now,
104
  };
@@ -150,6 +152,13 @@ export class AccountLinkingService {
150
  console.log(`βœ… Updated account link for GitHub user: ${existingLink.githubLogin}`);
151
  return updatedLink;
152
  }
 
 
 
 
 
 
 
153
 
154
  /**
155
  * Remove an account link
 
5
  githubUserId: string;
6
  githubLogin: string;
7
  huggingfaceUsername: string;
8
+ huggingfaceAccessToken?: string;
9
  linkedAt: string;
10
  lastUpdated: string;
11
  }
 
80
  /**
81
  * Create a new account link
82
  */
83
+ createLink(githubUserId: string, githubLogin: string, huggingfaceUsername: string, huggingfaceAccessToken?: string): AccountLink {
84
  const data = this.readData();
85
  const now = new Date().toISOString();
86
 
 
100
  githubUserId,
101
  githubLogin,
102
  huggingfaceUsername,
103
+ huggingfaceAccessToken,
104
  linkedAt: now,
105
  lastUpdated: now,
106
  };
 
152
  console.log(`βœ… Updated account link for GitHub user: ${existingLink.githubLogin}`);
153
  return updatedLink;
154
  }
155
+
156
+ /**
157
+ * Update HuggingFace access token for an existing account link
158
+ */
159
+ updateAccessToken(githubUserId: string, accessToken: string): AccountLink {
160
+ return this.updateLink(githubUserId, { huggingfaceAccessToken: accessToken });
161
+ }
162
 
163
  /**
164
  * Remove an account link
app/lib/hugex-service.server.ts CHANGED
@@ -217,16 +217,19 @@ export class HugExService {
217
  }
218
 
219
  /**
220
- * Get HuggingFace token for a user
221
- * Note: This is a placeholder. In a production system, you'd need a secure way to store and retrieve tokens.
222
  */
223
  private async getHuggingFaceToken(username: string): Promise<string | null> {
224
- // In a real implementation, you'd have a secure storage mechanism for tokens
225
- // This is a placeholder - you need to implement secure token storage
226
 
227
- // For now, return null to indicate we don't have a token
228
- // This would be replaced with your token retrieval logic
229
- console.warn(`⚠️ HuggingFace token storage not implemented. Cannot retrieve token for: ${username}`);
 
 
 
 
230
  return process.env.HF_DEFAULT_TOKEN || null;
231
  }
232
  }
 
217
  }
218
 
219
  /**
220
+ * Get HuggingFace token for a user from the account link
 
221
  */
222
  private async getHuggingFaceToken(username: string): Promise<string | null> {
223
+ // Look up the user's account link to get the stored token
224
+ const accountLink = accountLinkingService.findByHuggingFaceUser(username);
225
 
226
+ if (accountLink && accountLink.huggingfaceAccessToken) {
227
+ console.log(`βœ… Retrieved HuggingFace access token for user: ${username}`);
228
+ return accountLink.huggingfaceAccessToken;
229
+ }
230
+
231
+ // Fall back to default token if no specific token is found
232
+ console.warn(`⚠️ No HuggingFace access token found for user: ${username}. Using default token if available.`);
233
  return process.env.HF_DEFAULT_TOKEN || null;
234
  }
235
  }
app/routes/_index.tsx CHANGED
@@ -17,6 +17,9 @@ export async function loader({ request }: LoaderFunctionArgs) {
17
  const error = url.searchParams.get("error");
18
  const details = url.searchParams.get("details");
19
  const message = url.searchParams.get("message");
 
 
 
20
 
21
  // Get linking stats if available
22
  let linkingStats = null;
 
17
  const error = url.searchParams.get("error");
18
  const details = url.searchParams.get("details");
19
  const message = url.searchParams.get("message");
20
+
21
+ const cookies = request.headers.get("Cookie") || "";
22
+ console.log("Cookie keys available:", cookies.split(";").map(c => c.trim().split("=")[0]));
23
 
24
  // Get linking stats if available
25
  let linkingStats = null;
app/routes/auth.huggingface.callback.tsx CHANGED
@@ -18,7 +18,7 @@ export async function loader({ request }: LoaderFunctionArgs) {
18
  code: code ? `${code.substring(0, 4)}...` : null,
19
  state: state ? `${state.substring(0, 4)}...` : null,
20
  error,
21
- errorDescription
22
  });
23
 
24
  // Handle OAuth errors
@@ -27,11 +27,11 @@ export async function loader({ request }: LoaderFunctionArgs) {
27
  if (errorDescription) {
28
  console.error("Error description:", errorDescription);
29
  }
30
-
31
  const redirectUrl = `/?error=hf_oauth_failed&details=${encodeURIComponent(
32
  errorDescription ? `${error}: ${errorDescription}` : error
33
  )}`;
34
-
35
  console.log("Redirecting to:", redirectUrl);
36
  return redirect(redirectUrl);
37
  }
@@ -56,14 +56,20 @@ export async function loader({ request }: LoaderFunctionArgs) {
56
  console.log("Cookie values:", {
57
  storedState: storedState ? `${storedState.substring(0, 4)}...` : null,
58
  codeVerifier: codeVerifier ? `length: ${codeVerifier.length}` : null,
59
- returnTo
60
  });
61
 
62
  // Verify state parameter (CSRF protection)
63
  if (!storedState || storedState !== state) {
64
  console.error("HuggingFace OAuth state mismatch");
65
- console.error("Stored state:", storedState ? storedState.substring(0, 10) + "..." : "null");
66
- console.error("Received state:", state ? state.substring(0, 10) + "..." : "null");
 
 
 
 
 
 
67
  return redirect("/?error=hf_state_mismatch");
68
  }
69
 
@@ -74,13 +80,15 @@ export async function loader({ request }: LoaderFunctionArgs) {
74
 
75
  try {
76
  console.log("πŸ”„ Attempting to complete OAuth flow with code and verifier");
77
-
78
  // Complete OAuth flow
79
  const { accessToken, userInfo } = await huggingFaceOAuth.completeOAuthFlow(
80
  code,
81
  codeVerifier
82
  );
83
-
 
 
84
  console.log("βœ… HuggingFace OAuth successful for user:", userInfo.username);
85
 
86
  // Get existing session
@@ -98,11 +106,12 @@ export async function loader({ request }: LoaderFunctionArgs) {
98
  );
99
 
100
  if (linkCheck.canLink) {
101
- // Create account link
102
  const accountLink = accountLinkingService.createLink(
103
  userSession.github.userId,
104
  userSession.github.login,
105
- userInfo.username
 
106
  );
107
 
108
  userSession.isLinked = true;
@@ -113,7 +122,24 @@ export async function loader({ request }: LoaderFunctionArgs) {
113
  );
114
  } else {
115
  console.warn("⚠️ Cannot link accounts:", linkCheck.reason);
116
- userSession.isLinked = false;
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
117
  }
118
  } else {
119
  console.log(
@@ -122,6 +148,56 @@ export async function loader({ request }: LoaderFunctionArgs) {
122
  userSession.isLinked = false;
123
  }
124
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
125
  // Save updated session
126
  session.set("user", userSession);
127
 
@@ -152,9 +228,9 @@ export async function loader({ request }: LoaderFunctionArgs) {
152
  console.error("HuggingFace OAuth callback error:", error);
153
  const errorMessage = error.message || "Unknown error";
154
  console.error("Error details:", errorMessage);
155
-
156
  return redirect(
157
  `/?error=hf_callback_failed&message=${encodeURIComponent(errorMessage)}`
158
  );
159
  }
160
- }
 
18
  code: code ? `${code.substring(0, 4)}...` : null,
19
  state: state ? `${state.substring(0, 4)}...` : null,
20
  error,
21
+ errorDescription,
22
  });
23
 
24
  // Handle OAuth errors
 
27
  if (errorDescription) {
28
  console.error("Error description:", errorDescription);
29
  }
30
+
31
  const redirectUrl = `/?error=hf_oauth_failed&details=${encodeURIComponent(
32
  errorDescription ? `${error}: ${errorDescription}` : error
33
  )}`;
34
+
35
  console.log("Redirecting to:", redirectUrl);
36
  return redirect(redirectUrl);
37
  }
 
56
  console.log("Cookie values:", {
57
  storedState: storedState ? `${storedState.substring(0, 4)}...` : null,
58
  codeVerifier: codeVerifier ? `length: ${codeVerifier.length}` : null,
59
+ returnTo,
60
  });
61
 
62
  // Verify state parameter (CSRF protection)
63
  if (!storedState || storedState !== state) {
64
  console.error("HuggingFace OAuth state mismatch");
65
+ console.error(
66
+ "Stored state:",
67
+ storedState ? storedState.substring(0, 10) + "..." : "null"
68
+ );
69
+ console.error(
70
+ "Received state:",
71
+ state ? state.substring(0, 10) + "..." : "null"
72
+ );
73
  return redirect("/?error=hf_state_mismatch");
74
  }
75
 
 
80
 
81
  try {
82
  console.log("πŸ”„ Attempting to complete OAuth flow with code and verifier");
83
+
84
  // Complete OAuth flow
85
  const { accessToken, userInfo } = await huggingFaceOAuth.completeOAuthFlow(
86
  code,
87
  codeVerifier
88
  );
89
+
90
+ console.log("βœ… HuggingFace access token received:", accessToken);
91
+
92
  console.log("βœ… HuggingFace OAuth successful for user:", userInfo.username);
93
 
94
  // Get existing session
 
106
  );
107
 
108
  if (linkCheck.canLink) {
109
+ // Create account link with access token
110
  const accountLink = accountLinkingService.createLink(
111
  userSession.github.userId,
112
  userSession.github.login,
113
+ userInfo.username,
114
+ accessToken
115
  );
116
 
117
  userSession.isLinked = true;
 
122
  );
123
  } else {
124
  console.warn("⚠️ Cannot link accounts:", linkCheck.reason);
125
+
126
+ // Check if there's an existing link that needs token update
127
+ const existingLink = accountLinkingService.findByHuggingFaceUser(userInfo.username);
128
+ if (existingLink) {
129
+ // Update the access token for the existing link
130
+ accountLinkingService.updateAccessToken(existingLink.githubUserId, accessToken);
131
+ console.log(`πŸ”„ Updated access token for existing link: ${existingLink.githubLogin} ↔ ${userInfo.username}`);
132
+
133
+ // If this is the same GitHub user, set session as linked
134
+ if (existingLink.githubUserId === userSession.github.userId) {
135
+ userSession.isLinked = true;
136
+ userSession.linkedAt = existingLink.linkedAt;
137
+ } else {
138
+ userSession.isLinked = false;
139
+ }
140
+ } else {
141
+ userSession.isLinked = false;
142
+ }
143
  }
144
  } else {
145
  console.log(
 
148
  userSession.isLinked = false;
149
  }
150
 
151
+ // try {
152
+ // const serverConfig = {
153
+ // OAUTH2: {
154
+ // // PROVIDER_URL: process.env.OAUTH2_PROVIDER_URL,
155
+ // PROVIDER_URL: "https://huggingface.co",
156
+ // CLIENT_ID: process.env.OAUTH2_CLIENT_ID,
157
+ // CLIENT_SECRET: process.env.OAUTH2_CLIENT_SECRET,
158
+ // CALLBACK_URL: process.env.OAUTH2_CALLBACK_URL,
159
+ // },
160
+ // };
161
+
162
+ // // Exchange authorization code for access token
163
+ // const tokenResponse = await fetch(
164
+ // `${serverConfig.OAUTH2.PROVIDER_URL}/oauth/token`,
165
+ // {
166
+ // method: "POST",
167
+ // headers: {
168
+ // "Content-Type": "application/x-www-form-urlencoded",
169
+ // Accept: "application/json",
170
+ // },
171
+ // body: new URLSearchParams({
172
+ // grant_type: "authorization_code",
173
+ // client_id: serverConfig.OAUTH2.CLIENT_ID!,
174
+ // client_secret: serverConfig.OAUTH2.CLIENT_SECRET!,
175
+ // code,
176
+ // redirect_uri: "http://localhost:5173/api/auth/github/callback", // serverConfig.OAUTH2.CALLBACK_URL,
177
+ // code_verifier: codeVerifier,
178
+ // }),
179
+ // }
180
+ // );
181
+
182
+ // const tokenData = await tokenResponse.json();
183
+ // const accessToken = tokenData;
184
+
185
+ // console.log(
186
+ // "βœ… Access token successfully exchanged for HuggingFace OAuth", accessToken
187
+ // );
188
+
189
+ // } catch (tokenError) {
190
+ // console.error(
191
+ // "Failed to exchange authorization code for access token:",
192
+ // tokenError
193
+ // );
194
+ // return redirect(
195
+ // `/?error=hf_token_exchange_failed&message=${encodeURIComponent(
196
+ // "Failed to exchange authorization code for access token"
197
+ // )}`
198
+ // );
199
+ // }
200
+
201
  // Save updated session
202
  session.set("user", userSession);
203
 
 
228
  console.error("HuggingFace OAuth callback error:", error);
229
  const errorMessage = error.message || "Unknown error";
230
  console.error("Error details:", errorMessage);
231
+
232
  return redirect(
233
  `/?error=hf_callback_failed&message=${encodeURIComponent(errorMessage)}`
234
  );
235
  }
236
+ }
app/routes/webhook.github.tsx CHANGED
@@ -20,11 +20,11 @@ export async function action({ request }: ActionFunctionArgs) {
20
 
21
  console.log(`πŸ“₯ Received GitHub webhook: ${event} (${delivery})`);
22
 
23
- // Verify webhook signature
24
- if (!githubApp.verifyWebhookSignature(payload, signature)) {
25
- console.error("Invalid webhook signature");
26
- return json({ error: "Invalid signature" }, { status: 401 });
27
- }
28
 
29
  try {
30
  eventData = JSON.parse(payload);
 
20
 
21
  console.log(`πŸ“₯ Received GitHub webhook: ${event} (${delivery})`);
22
 
23
+ // // Verify webhook signature
24
+ // if (!githubApp.verifyWebhookSignature(payload, signature)) {
25
+ // console.error("Invalid webhook signature");
26
+ // return json({ error: "Invalid signature" }, { status: 401 });
27
+ // }
28
 
29
  try {
30
  eventData = JSON.parse(payload);
public/.well-known/appspecific/com.chrome.devtools.json ADDED
@@ -0,0 +1 @@
 
 
1
+ {}