-
-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
1 parent
199af01
commit e613b3f
Showing
57 changed files
with
758 additions
and
4,666 deletions.
There are no files selected for viewing
This file was deleted.
Oops, something went wrong.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,3 +1,4 @@ | ||
COOKIE_SECRET= | ||
DISCORD_CLIENT_SECRET= | ||
TWITTER_CLIENT_SECRET= | ||
GITHUB_CLIENT_SECRET= |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -33,3 +33,8 @@ yarn-error.log* | |
# typescript | ||
*.tsbuildinfo | ||
next-env.d.ts | ||
|
||
# Wrangler CLI | ||
.wrangler/ | ||
.dev.vars | ||
|
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,22 @@ | ||
import { z } from "zod"; | ||
|
||
const associationLinksSchema = z.array( | ||
z.object({ | ||
type: z.union([z.literal("github"), z.literal("twitter")]), | ||
id: z.string(), | ||
name: z.string(), | ||
}), | ||
); | ||
export type AssociationLinks = z.infer<typeof associationLinksSchema>; | ||
|
||
export async function getAssociationLinks( | ||
discordId: string, | ||
): Promise<AssociationLinks> { | ||
const associationsRes = await fetch( | ||
`https://members.approvers.dev/members/${discordId}/associations`, | ||
); | ||
const associations = associationLinksSchema.parse( | ||
await associationsRes.json(), | ||
); | ||
return associations; | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,150 @@ | ||
import { | ||
createCookieSessionStorage, | ||
createMemorySessionStorage, | ||
} from "@remix-run/cloudflare"; | ||
import { Authenticator } from "remix-auth"; | ||
import { GitHubStrategy } from "remix-auth-github"; | ||
import { OAuth2Strategy } from "remix-auth-oauth2"; | ||
|
||
import { | ||
DISCORD_CLIENT_ID, | ||
GITHUB_CLIENT_ID, | ||
TWITTER_CLIENT_ID, | ||
} from "./consts"; | ||
|
||
const urlBase = | ||
process.env.NODE_ENV === "production" | ||
? "https://edit.members.approvers.dev" | ||
: "http://localhost:3000"; | ||
|
||
export type Member = { | ||
discordToken: string; | ||
discordId: string; | ||
}; | ||
export const getAuthenticator = ( | ||
cookieSecret: string, | ||
discordClientSecret: string, | ||
) => { | ||
const authenticator = new Authenticator<Member>( | ||
createCookieSessionStorage({ | ||
cookie: { | ||
name: "edit.members.approvers.dev", | ||
sameSite: "lax", | ||
path: "/", | ||
httpOnly: true, | ||
secrets: [cookieSecret], | ||
secure: process.env.NODE_ENV === "production", | ||
}, | ||
}), | ||
); | ||
authenticator.use( | ||
new OAuth2Strategy( | ||
{ | ||
clientId: DISCORD_CLIENT_ID, | ||
clientSecret: discordClientSecret, | ||
authorizationEndpoint: "https://discord.com/oauth2/authorize", | ||
tokenEndpoint: "https://discord.com/api/v10/oauth2/token", | ||
redirectURI: new URL("/redirect", urlBase), | ||
tokenRevocationEndpoint: | ||
"https://discord.com/api/v10/oauth2/token/revoke", | ||
codeChallengeMethod: "S256", | ||
scopes: ["identify", "guilds.members.read"], | ||
authenticateWith: "request_body", | ||
}, | ||
async ({ tokens }) => { | ||
const discordMeRes = await fetch( | ||
"https://discord.com/api/v10/users/@me", | ||
{ | ||
headers: { | ||
Authorization: `Bearer ${tokens.access_token}`, | ||
}, | ||
}, | ||
); | ||
const { id: discordId } = await discordMeRes.json<{ | ||
id: string; | ||
}>(); | ||
return { | ||
discordToken: tokens.access_token, | ||
discordId, | ||
}; | ||
}, | ||
), | ||
"discord-oauth", | ||
); | ||
return authenticator; | ||
}; | ||
|
||
export type GitHubAssociation = { | ||
id: string; | ||
name: string; | ||
}; | ||
export const getGithubAssocAuthenticator = (githubClientSecret: string) => { | ||
const assocAuthenticator = new Authenticator<GitHubAssociation>( | ||
createMemorySessionStorage(), | ||
); | ||
|
||
assocAuthenticator.use( | ||
new GitHubStrategy( | ||
{ | ||
clientId: GITHUB_CLIENT_ID, | ||
clientSecret: githubClientSecret, | ||
redirectURI: new URL("/dashboard/redirect-github", urlBase), | ||
}, | ||
async ({ profile }) => { | ||
return { id: profile.id, name: profile.displayName }; | ||
}, | ||
), | ||
"github-oauth", | ||
); | ||
return assocAuthenticator; | ||
}; | ||
|
||
export type TwitterAssociation = { | ||
id: string; | ||
name: string; | ||
}; | ||
export const getTwitterAssocAuthenticator = (twitterClientSecret: string) => { | ||
const assocAuthenticator = new Authenticator<TwitterAssociation>( | ||
createMemorySessionStorage(), | ||
); | ||
assocAuthenticator.use( | ||
new OAuth2Strategy( | ||
{ | ||
clientId: TWITTER_CLIENT_ID, | ||
clientSecret: twitterClientSecret, | ||
authorizationEndpoint: "https://twitter.com/i/oauth2/authorize", | ||
tokenEndpoint: "https://api.twitter.com/2/oauth2/token", | ||
redirectURI: new URL("/dashboard/redirect-twitter", urlBase), | ||
scopes: ["tweet.read", "users.read"], | ||
codeChallengeMethod: "S256", | ||
authenticateWith: "http_basic_auth", | ||
}, | ||
async ({ tokens }) => { | ||
const params = new URLSearchParams({ | ||
"user.fields": "id,username", | ||
}); | ||
const meRes = await fetch( | ||
"https://api.twitter.com/2/users/me?" + params, | ||
{ | ||
headers: { | ||
Authorization: `Bearer ${tokens.access_token}`, | ||
}, | ||
}, | ||
); | ||
if (!meRes.ok) { | ||
console.log(await meRes.text()); | ||
throw new Error("failed getting twitter account"); | ||
} | ||
const json = await meRes.json<{ | ||
data: { id: string; username: string }; | ||
}>(); | ||
const { | ||
data: { id, username: name }, | ||
} = json; | ||
return { id, name }; | ||
}, | ||
), | ||
"twitter-oauth", | ||
); | ||
return assocAuthenticator; | ||
}; |
File renamed without changes.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,23 @@ | ||
import "./tailwind.css"; | ||
|
||
import { Links, Meta, Outlet, Scripts } from "@remix-run/react"; | ||
|
||
export default function App() { | ||
return ( | ||
<html lang="ja"> | ||
<head> | ||
<meta charSet="utf-8" /> | ||
<meta | ||
name="viewport" | ||
content="width=device-width, initial-scale=1" | ||
/> | ||
<Meta /> | ||
<Links /> | ||
</head> | ||
<body> | ||
<Outlet /> | ||
<Scripts /> | ||
</body> | ||
</html> | ||
); | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,29 @@ | ||
import type { ActionFunctionArgs } from "@remix-run/cloudflare"; | ||
import { Form } from "@remix-run/react"; | ||
|
||
import { getAuthenticator } from "../.server/store/auth.js"; | ||
|
||
export default function Index() { | ||
return ( | ||
<main className="flex min-h-screen flex-col items-center justify-center gap-4"> | ||
<h1 className="text-xl font-bold">Approvers メンバー情報編集</h1> | ||
<Form method="post"> | ||
<button className="bg-indigo-500 text-slate-100 p-4 rounded-2xl"> | ||
Discord でログイン | ||
</button> | ||
</Form> | ||
</main> | ||
); | ||
} | ||
|
||
export async function action({ request, context }: ActionFunctionArgs) { | ||
const { COOKIE_SECRET, DISCORD_CLIENT_SECRET } = context.cloudflare.env; | ||
return getAuthenticator(COOKIE_SECRET, DISCORD_CLIENT_SECRET).authenticate( | ||
"discord-oauth", | ||
request, | ||
{ | ||
successRedirect: "/dashboard", | ||
failureRedirect: "/", | ||
}, | ||
); | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,36 @@ | ||
import { type ActionFunctionArgs, redirect } from "@remix-run/cloudflare"; | ||
|
||
import { | ||
getAuthenticator, | ||
getGithubAssocAuthenticator, | ||
} from "../.server/store/auth"; | ||
|
||
export async function action({ request, context }: ActionFunctionArgs) { | ||
const { COOKIE_SECRET, DISCORD_CLIENT_SECRET, GITHUB_CLIENT_SECRET } = | ||
context.cloudflare.env; | ||
await getAuthenticator( | ||
COOKIE_SECRET, | ||
DISCORD_CLIENT_SECRET, | ||
).isAuthenticated(request, { | ||
failureRedirect: "/", | ||
}); | ||
return getGithubAssocAuthenticator(GITHUB_CLIENT_SECRET).authenticate( | ||
"github-oauth", | ||
request, | ||
{ | ||
failureRedirect: "/dashboard", | ||
}, | ||
); | ||
} | ||
|
||
export async function loader() { | ||
return redirect("/dashboard"); | ||
} | ||
|
||
export default function Redirect(): JSX.Element { | ||
return ( | ||
<main> | ||
<h1>画面遷移中…</h1> | ||
</main> | ||
); | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,36 @@ | ||
import { type ActionFunctionArgs, redirect } from "@remix-run/cloudflare"; | ||
|
||
import { | ||
getAuthenticator, | ||
getTwitterAssocAuthenticator, | ||
} from "../.server/store/auth"; | ||
|
||
export async function action({ request, context }: ActionFunctionArgs) { | ||
const { COOKIE_SECRET, DISCORD_CLIENT_SECRET, TWITTER_CLIENT_SECRET } = | ||
context.cloudflare.env; | ||
await getAuthenticator( | ||
COOKIE_SECRET, | ||
DISCORD_CLIENT_SECRET, | ||
).isAuthenticated(request, { | ||
failureRedirect: "/", | ||
}); | ||
return getTwitterAssocAuthenticator(TWITTER_CLIENT_SECRET).authenticate( | ||
"twitter-oauth", | ||
request, | ||
{ | ||
failureRedirect: "/dashboard", | ||
}, | ||
); | ||
} | ||
|
||
export async function loader() { | ||
return redirect("/dashboard"); | ||
} | ||
|
||
export default function Redirect(): JSX.Element { | ||
return ( | ||
<main> | ||
<h1>画面遷移中…</h1> | ||
</main> | ||
); | ||
} |
Oops, something went wrong.