Download free for 30 days
Sign in
Upload
Language (EN)
Support
Business
Mobile
Social Media
Marketing
Technology
Art & Photos
Career
Design
Education
Presentations & Public Speaking
Government & Nonprofit
Healthcare
Internet
Law
Leadership & Management
Automotive
Engineering
Software
Recruiting & HR
Retail
Sales
Services
Science
Small Business & Entrepreneurship
Food
Environment
Economy & Finance
Data & Analytics
Investor Relations
Sports
Spiritual
News & Politics
Travel
Self Improvement
Real Estate
Entertainment & Humor
Health & Medicine
Devices & Hardware
Lifestyle
Change Language
Language
English
Español
Português
Français
Deutsche
Cancel
Save
Submit search
EN
Uploaded by
虎の穴 開発室
PDF, PPTX
489 views
GitHub APIとfreshで遊ぼう
toranoana.deno#5の発表資料です https://yumenosora.connpass.com/event/238607/
Technology
◦
Read more
0
Save
Share
Embed
Embed presentation
Download
Download as PDF, PPTX
1
/ 22
2
/ 22
3
/ 22
4
/ 22
5
/ 22
6
/ 22
7
/ 22
8
/ 22
9
/ 22
10
/ 22
11
/ 22
12
/ 22
13
/ 22
14
/ 22
15
/ 22
16
/ 22
17
/ 22
18
/ 22
19
/ 22
20
/ 22
21
/ 22
22
/ 22
More Related Content
PDF
ゲームの仕様書を書こう4 仕様書作成で楽をするconfluenceの活用
by
Sugimoto Chizuru
PDF
Unityではじめるオープンワールド制作 エンジニア編
by
Unity Technologies Japan K.K.
PDF
インフラエンジニアの綺麗で優しい手順書の書き方
by
Shohei Koyama
PPTX
DXとかDevOpsとかのなんかいい感じのやつ 富士通TechLive
by
Tokoroten Nakayama
PDF
現場で使えるDynamoDBと冪等デザインパターン
by
cmaraiyusuke
PDF
雑なMySQLパフォーマンスチューニング
by
yoku0825
PPTX
CEDEC2019 大規模モバイルゲーム運用におけるマスタデータ管理事例
by
sairoutine
PDF
C#×LLVM=アセンブラ!? 〜詳説・Burstコンパイラー〜
by
UnityTechnologiesJapan002
ゲームの仕様書を書こう4 仕様書作成で楽をするconfluenceの活用
by
Sugimoto Chizuru
Unityではじめるオープンワールド制作 エンジニア編
by
Unity Technologies Japan K.K.
インフラエンジニアの綺麗で優しい手順書の書き方
by
Shohei Koyama
DXとかDevOpsとかのなんかいい感じのやつ 富士通TechLive
by
Tokoroten Nakayama
現場で使えるDynamoDBと冪等デザインパターン
by
cmaraiyusuke
雑なMySQLパフォーマンスチューニング
by
yoku0825
CEDEC2019 大規模モバイルゲーム運用におけるマスタデータ管理事例
by
sairoutine
C#×LLVM=アセンブラ!? 〜詳説・Burstコンパイラー〜
by
UnityTechnologiesJapan002
What's hot
PDF
入門 シェル実装
by
Yusuke Sangenya
PDF
大規模ソーシャルゲーム開発から学んだPHP&MySQL実践テクニック
by
infinite_loop
PDF
結果的に組織がAgileな状態であること #agile #scrum #leanstartup
by
Itsuki Kuroda
PDF
webエンジニアのためのはじめてのredis
by
nasa9084
PDF
ソーシャルゲームのためのデータベース設計
by
Yoshinori Matsunobu
PDF
正しいものを正しくつくる
by
toshihiro ichitani
PDF
導入から 10 年、PHP の trait は滅びるべきなのか その適切な使いどころと弱点、将来について
by
shinjiigarashi
PDF
マルチテナントのアプリケーション実装〜実践編〜
by
Yoshiki Nakagawa
PDF
シリコンバレーの「何が」凄いのか
by
Atsushi Nakada
PDF
ネットワーク ゲームにおけるTCPとUDPの使い分け
by
モノビット エンジン
PDF
ツール比較しながら語る O/RマッパーとDBマイグレーションの実際のところ
by
Y Watanabe
PDF
SQLアンチパターン 幻の第26章「とりあえず削除フラグ」
by
Takuto Wada
PPTX
Sharding with sql alchemy
by
Akira Matsuzaki
PDF
ドメイン駆動設計 モデリング_実装入門勉強会_2020.3.8
by
Koichiro Matsuoka
PDF
デキるプログラマだけが知っているコードレビュー7つの秘訣
by
Masahiro Nishimi
PDF
Pythonの理解を試みる 〜バイトコードインタプリタを作成する〜
by
Preferred Networks
PPTX
AWS Organizations連携サービスの罠(Security JAWS 第26回 発表資料)
by
NTT DATA Technology & Innovation
PPTX
FINAL FANTASY Record Keeperのマスターデータを支える技術
by
dena_study
PDF
マイクロにしすぎた結果がこれだよ!
by
mosa siru
PPTX
C#とILとネイティブと
by
信之 岩永
入門 シェル実装
by
Yusuke Sangenya
大規模ソーシャルゲーム開発から学んだPHP&MySQL実践テクニック
by
infinite_loop
結果的に組織がAgileな状態であること #agile #scrum #leanstartup
by
Itsuki Kuroda
webエンジニアのためのはじめてのredis
by
nasa9084
ソーシャルゲームのためのデータベース設計
by
Yoshinori Matsunobu
正しいものを正しくつくる
by
toshihiro ichitani
導入から 10 年、PHP の trait は滅びるべきなのか その適切な使いどころと弱点、将来について
by
shinjiigarashi
マルチテナントのアプリケーション実装〜実践編〜
by
Yoshiki Nakagawa
シリコンバレーの「何が」凄いのか
by
Atsushi Nakada
ネットワーク ゲームにおけるTCPとUDPの使い分け
by
モノビット エンジン
ツール比較しながら語る O/RマッパーとDBマイグレーションの実際のところ
by
Y Watanabe
SQLアンチパターン 幻の第26章「とりあえず削除フラグ」
by
Takuto Wada
Sharding with sql alchemy
by
Akira Matsuzaki
ドメイン駆動設計 モデリング_実装入門勉強会_2020.3.8
by
Koichiro Matsuoka
デキるプログラマだけが知っているコードレビュー7つの秘訣
by
Masahiro Nishimi
Pythonの理解を試みる 〜バイトコードインタプリタを作成する〜
by
Preferred Networks
AWS Organizations連携サービスの罠(Security JAWS 第26回 発表資料)
by
NTT DATA Technology & Innovation
FINAL FANTASY Record Keeperのマスターデータを支える技術
by
dena_study
マイクロにしすぎた結果がこれだよ!
by
mosa siru
C#とILとネイティブと
by
信之 岩永
Similar to GitHub APIとfreshで遊ぼう
PDF
これからのネイティブアプリにおけるOpenID Connectの活用
by
Masaru Kurahayashi
PDF
実践 NestJS
by
Ayumi Goto
PPTX
認証サービスへのWebAuthnの導入
by
TakashiTsukamoto4
PDF
React(TypeScript) + Go + Auth0 で実現する管理画面
by
KentaEndoh
PDF
OAuth2.0によるWeb APIの保護
by
Naohiro Fujie
PPTX
DApps のユーザ認証に web3.eth.personal.sign を使おう!
by
Drecom Co., Ltd.
PPTX
はじめてのgithub
by
Yasutaka Hamada
PDF
日々の開発フローにプラスする GitHub Actions ~ セキュリティ対策を取り込む
by
Kazumi OHIRA
KEY
Yapc2012資料
by
matsuo kenji
PDF
Deno 向け WEB 開発用のツールを作ったので 紹介します
by
虎の穴 開発室
PPTX
JavaScriptから利用するFirebase
by
Takuji Shimokawa
PDF
Couchbase MeetUP Tokyo - #11 Omoidenote
by
kitsugi
PDF
Nodejsによるapiサーバ構築事例
by
Hidetoshi Mori
PDF
後期02
by
Takenori Nakagawa
PPTX
ログインの全て
by
DaikiSato10
PDF
20130412 titanium meetupvol7
by
Hiroshi Oyamada
PDF
OpenStack Study#9 JOSUG
by
Hideki Saito
PDF
ruby、sinatraで作るfacebookアプリ
by
Toshiya Kurishima
PPT
PFI Seminar 2012/02/24
by
Preferred Networks
PPTX
Fluxflex meetup 2011 in Tokyo
by
Kyosuke Inoue
これからのネイティブアプリにおけるOpenID Connectの活用
by
Masaru Kurahayashi
実践 NestJS
by
Ayumi Goto
認証サービスへのWebAuthnの導入
by
TakashiTsukamoto4
React(TypeScript) + Go + Auth0 で実現する管理画面
by
KentaEndoh
OAuth2.0によるWeb APIの保護
by
Naohiro Fujie
DApps のユーザ認証に web3.eth.personal.sign を使おう!
by
Drecom Co., Ltd.
はじめてのgithub
by
Yasutaka Hamada
日々の開発フローにプラスする GitHub Actions ~ セキュリティ対策を取り込む
by
Kazumi OHIRA
Yapc2012資料
by
matsuo kenji
Deno 向け WEB 開発用のツールを作ったので 紹介します
by
虎の穴 開発室
JavaScriptから利用するFirebase
by
Takuji Shimokawa
Couchbase MeetUP Tokyo - #11 Omoidenote
by
kitsugi
Nodejsによるapiサーバ構築事例
by
Hidetoshi Mori
後期02
by
Takenori Nakagawa
ログインの全て
by
DaikiSato10
20130412 titanium meetupvol7
by
Hiroshi Oyamada
OpenStack Study#9 JOSUG
by
Hideki Saito
ruby、sinatraで作るfacebookアプリ
by
Toshiya Kurishima
PFI Seminar 2012/02/24
by
Preferred Networks
Fluxflex meetup 2011 in Tokyo
by
Kyosuke Inoue
More from 虎の穴 開発室
PDF
FizzBuzzで学ぶJavaの進化
by
虎の穴 開発室
PDF
Supabase Edge Functions と Netlify Edge Functions を使ってみる – 機能とその比較 –
by
虎の穴 開発室
PDF
Amplify Studioを使ってみた
by
虎の穴 開発室
PDF
虎の穴ラボ エンジニア採用説明資料 .pdf
by
虎の穴 開発室
PDF
【とらのあなラボ Tech Day #3】新規システムにおける技術選定〜GoとgRPCを採用した話〜
by
虎の穴 開発室
PDF
Railsのデバッグ どうやるかを改めて確認する
by
虎の穴 開発室
PDF
Deno Deployと組み合わせるのに Upstashをおすすめしたい.pdf
by
虎の穴 開発室
PDF
セキュリティを強化しよう!CloudArmorの機能解説
by
虎の穴 開発室
PDF
いいテスト会 (スプリントレビュー) をやろう!
by
虎の穴 開発室
PDF
【エンジニアの勉強法ハックLT- vol.7】ゲームから学んだ勉強のこと
by
虎の穴 開発室
PDF
GCPの画像認識APIの紹介
by
虎の穴 開発室
PDF
JavaScript LT会 〜 React.js Node.js歓迎 〜 Deno で やってみるweb開発
by
虎の穴 開発室
PDF
【20220120 toranoana.deno#4】denoでffiの続き
by
虎の穴 開発室
PDF
【20220120 toranoana.deno#4】deno を使って「ログイン」するサービスを作る
by
虎の穴 開発室
PDF
通販開発部の西田さん「通販開発マネジメントの5ルール」
by
虎の穴 開発室
PDF
虎の穴ラボ Tech day#3 チームで戦う!とらのあな通販冬の大感謝祭でのフロント開発について
by
虎の穴 開発室
PDF
【Saitama.js】Denoのすすめ
by
虎の穴 開発室
PDF
社内DX推進!非エンジニア向けにプログラミング講座を実施してみた!
by
虎の穴 開発室
PDF
虎の穴ラボ TechDay#3 フルリモート率100%!リモートワークを可能にするマネージメント
by
虎の穴 開発室
PDF
toranoana.deno #6 アジェンダ 採用説明
by
虎の穴 開発室
FizzBuzzで学ぶJavaの進化
by
虎の穴 開発室
Supabase Edge Functions と Netlify Edge Functions を使ってみる – 機能とその比較 –
by
虎の穴 開発室
Amplify Studioを使ってみた
by
虎の穴 開発室
虎の穴ラボ エンジニア採用説明資料 .pdf
by
虎の穴 開発室
【とらのあなラボ Tech Day #3】新規システムにおける技術選定〜GoとgRPCを採用した話〜
by
虎の穴 開発室
Railsのデバッグ どうやるかを改めて確認する
by
虎の穴 開発室
Deno Deployと組み合わせるのに Upstashをおすすめしたい.pdf
by
虎の穴 開発室
セキュリティを強化しよう!CloudArmorの機能解説
by
虎の穴 開発室
いいテスト会 (スプリントレビュー) をやろう!
by
虎の穴 開発室
【エンジニアの勉強法ハックLT- vol.7】ゲームから学んだ勉強のこと
by
虎の穴 開発室
GCPの画像認識APIの紹介
by
虎の穴 開発室
JavaScript LT会 〜 React.js Node.js歓迎 〜 Deno で やってみるweb開発
by
虎の穴 開発室
【20220120 toranoana.deno#4】denoでffiの続き
by
虎の穴 開発室
【20220120 toranoana.deno#4】deno を使って「ログイン」するサービスを作る
by
虎の穴 開発室
通販開発部の西田さん「通販開発マネジメントの5ルール」
by
虎の穴 開発室
虎の穴ラボ Tech day#3 チームで戦う!とらのあな通販冬の大感謝祭でのフロント開発について
by
虎の穴 開発室
【Saitama.js】Denoのすすめ
by
虎の穴 開発室
社内DX推進!非エンジニア向けにプログラミング講座を実施してみた!
by
虎の穴 開発室
虎の穴ラボ TechDay#3 フルリモート率100%!リモートワークを可能にするマネージメント
by
虎の穴 開発室
toranoana.deno #6 アジェンダ 採用説明
by
虎の穴 開発室
GitHub APIとfreshで遊ぼう
1.
Copyright (C) 2021
Toranoana Inc. All Rights Reserved. GitHub APIとfreshで遊ぼう 虎の穴ラボ 藤原 佳顕 1
2.
Copyright (C) 2021
Toranoana Inc. All Rights Reserved. アジェンダ ● 概要 ● GitHub APIについて ● 構成 ● freshについて ● 実装と作ったもの 2
3.
Copyright (C) 2021
Toranoana Inc. All Rights Reserved. 自己紹介 3 ● 名前 ○ 藤原佳顕 ● 仕事 ○ FantiaとかCreatiaとか社内アプリとか ● 好み ○ Clojure、Rust ● 趣味 ○ 格闘ゲーム ■ Melty Blood、Guilty Gear ○ STG(ダライアスとか)も好き ○ 祝エルデンリング発売
4.
Copyright (C) 2021
Toranoana Inc. All Rights Reserved. 概要 4 ● 諸事情でGitHub APIを叩いてコメントを抜いていくる必要がありました ● DenoでGitHub API叩いてコメント抜いてくることにしました ● せっかくなのでWebアプリにしてみました ○ https://github-comment.deno.dev/ ○ https://github.com/zonuko/deno-github-comment
5.
Copyright (C) 2021
Toranoana Inc. All Rights Reserved. GitHub APIについて 5 ● 何種類かある ○ v3: https://docs.github.com/ja/rest ■ REST API ■ 認証方法に種類がある ● ユーザー個別のトークン利用 ● OAuth ● 今回はどちらも試す ○ v4: https://docs.github.com/ja/graphql ■ GraphQL API ■ 直感的に使うのは面倒そうだったので一旦見送り
6.
Copyright (C) 2021
Toranoana Inc. All Rights Reserved. 構成 6 ● SDKっぽい物があるが今回は使わない(octokit) ○ https://github.com/octokit/octokit.js/ ○ 単にREST API叩くだけなので問題はなさそう ● 使うもの ○ Deno 1.19 ○ dotenv ○ fresh(web用)
7.
Copyright (C) 2021
Toranoana Inc. All Rights Reserved. 実装と作ったもの(freshについて) 7 ● freshについて ○ Denoの中の人Luca Casonato氏が作っている ○ preactベースのWebフレームワーク ○ deno deployで動作する ○ ビルドがない ○ deno.land、lint.deno.landのページなどがこちらに置き換えられている ■ →サンプルが豊富 ○ Next.js、Nuxt.js同様にディレクトリ構造ベースのルーティング ○ まだまだ発展途上感もあり ○ ドキュメント化されていない情報が多々あるので間違っているかもしれません
8.
Copyright (C) 2021
Toranoana Inc. All Rights Reserved. 実装と作ったもの(cli+ユーザートークン) 8 import { config } from "./deps.ts"; const token = config().GITHUB_TOKEN; const user = config().GITHUB_USER; function buildConfig(): RequestInit { return { headers: { Authorization: `token ${token}`, Accept: "application/vnd.github.v3+json", }, }; } async function getRepos(): Promise<any> { const res = await fetch( `https://api.github.com/users/${user}/repos`, buildConfig(), ); return await res.json(); } async function getPulls(repo: string): Promise<any> { const res = await fetch( `https://api.github.com/repos/${user}/${repo}/pulls?state=all`, buildConfig(), ); return await res.json(); } async function getComments(repo: string, id: number): Promise<any> { const res = await fetch( `https://api.github.com/repos/${user}/${repo}/pulls/${id}/comments`, buildConfig(), ); } const repos = await getRepos() as any[]; repos.forEach(async (repo) => { console.log(await getPulls(repo.name)); });
9.
Copyright (C) 2021
Toranoana Inc. All Rights Reserved. 実装と作ったもの(ユーザートークン+cliツール) 9 ● 単にfetch使っているだけなのでここまで余興 ● 実際には次からのWebアプリ化が本題
10.
Copyright (C) 2021
Toranoana Inc. All Rights Reserved. 実装と作ったもの(Webアプリ化) 10 ● 実装方針 ○ トークンはOAuthトークンを使う ■ まずはGitHub Loginを作る ○ ストレージの類は利用しない(RDB、Redisなど) ■ したがってセッション系の情報は暗号化してcookieに保存 ● Rails知っている人はRailsの基本動作を想像してもらえると ○ 作るページはリポジトリ一覧、リポジトリのコメント一覧(、プルリク一覧)
11.
Copyright (C) 2021
Toranoana Inc. All Rights Reserved. 実装と作ったもの(Webアプリ化) 11 ● page/index.tsx→ログインフォームがあるだけ /** @jsx h */ import { Layout } from "../components/Layout.tsx"; import { h, PageConfig, PageProps, useData } from "../deps.ts"; export default function Home(props: PageProps) { const errorQuery = useData("errorQuery", () => { const q = props.url.searchParams.get("error"); if (q === "missing_code") { return "Not found GitHub OAuth code"; } if (q === "invalid_state") { return "Invalid OAuth state"; } if (q === "failed_to_get_token") { return "Failed to get the access token"; } }); return ( <Layout title="Login - GitHub Comments"> <nav class="navbar navbar-light bg-light"> <div class="container-fluid"> <span class="navbar-brand mb-0 h1">Login</span> </div> </nav> {errorQuery && ( <div class="alert alert-danger" role="alert"> {errorQuery} </div> )} <div class="position-relative text-center"> <a type="button" class="btn btn-outline-dark" href="/login/github/auth" > <i class="bi bi-github"></i> {" Login with GitHub"} </a> </div> </Layout> ); } export const config: PageConfig = { runtimeJS: true };
12.
Copyright (C) 2021
Toranoana Inc. All Rights Reserved. 実装と作ったもの(Webアプリ化) 12 ● useData ○ サーバー側でレンダリング前にデータを取得できる ○ エラーでリダイレクトされてきた場合はSSRの時点で表示したい ● PageConfig ○ いわゆるオプションの設定 ○ runtimeJS: クライアント側でもJS実行するかどうか ○ 他routeOverrideやcspなどオプションがある
13.
Copyright (C) 2021
Toranoana Inc. All Rights Reserved. 実装と作ったもの(Webアプリ化) 13 page/login/github/auth.ts import { buildGithubUrl, tokenEncrypt } from "../../../logics/github.ts"; import { HandlerContext } from "../../../server_deps.ts"; export async function handler(_ctx: HandlerContext): Promise<Response> { const oauthUrl = buildGithubUrl(); const githubRedirect = new Response(null, { status: 302, headers: { location: oauthUrl, "set-cookie": `state=${await tokenEncrypt( new URL(oauthUrl).searchParams.get("state") || "" )};HttpOnly;SameSite=Lax;Path=/;`, }, }); return githubRedirect; }
14.
Copyright (C) 2021
Toranoana Inc. All Rights Reserved. 実装と作ったもの(Webアプリ化) 14 ● handler関数 ○ handler関数をexportすることでAPIを生やすことが出来ます ○ 今回は単純で、後の検証のためにstateを暗号化してcookieに書き込み ○ その後GitHubのログイン画面にリダイレクト ○ サーバーサイドの処理なのでcookieやリクエストヘッダーなどある程度は触れる ○ 拡張子をtsx(jsx)にすることで通常のレンダリングも同時に行うことができる ■ 試した限りでは現状handlerとjsx両方がある場合はhandler→ssrといった順番で実行さ れる模様
15.
Copyright (C) 2021
Toranoana Inc. All Rights Reserved. 実装と作ったもの(Webアプリ化) 15 page/login/github/callback.ts export async function handler({req}: HandlerContext): Promise<Response> { const url = new URL(req.url); const code = url.searchParams.get("code"); const state = url.searchParams.get("state"); if (!code) { return Response.redirect(`${url.origin}/?error=missing_code`); } const cookieState = await tokenDecrypt(cookie.getCookies(req.headers)["state"]); if (cookieState !== state) { return Response.redirect(`${url.origin}/?error=invalid_state`); } const apiRes = await fetch("https://github.com/login/oauth/access_token", { method: "POST", headers: { Accept: "application/json", "Content-Type": "application/json", }, body: JSON.stringify({ client_id: githubClientId(), client_secret: githubClientSecret(), code: code, }), }); if (apiRes.status !== 200) { return Response.redirect(`${url.origin}/?error=failed_to_get_token`); } const resJson = await apiRes.json(); if (resJson["error"]) { return Response.redirect(`${url.origin}/?error=failed_to_get_token`); } const successRes = new Response(null, { status: 302, headers: { location: `${url.origin}/mypage/github`, "set-cookie": `oauth_token=${await tokenEncrypt( resJson["access_token"], )};HttpOnly;SameSite=Lax;Path=/;`, }, }); deleteCookie(successRes.headers, "state", {path: "/"}); return successRes; }
16.
Copyright (C) 2021
Toranoana Inc. All Rights Reserved. 実装と作ったもの(Webアプリ化) 16 ● GitHubでのログイン後に帰ってくるパス ○ state及びcodeがつけられて帰ってくるので各々チェック ■ state: cookieの値を復号化して一致するか(CSRF対策) ■ code: アクセストークンを取得するのに必要 ● アクセストークン取得 ○ 本来であればRDBやサーバー側セッションに持つべきだが今回はcookieに ○ 秘匿情報なのでサーバー側でしか復号化出来ないように暗号化して入れる ■ 今回はAES-GCMを採用
17.
Copyright (C) 2021
Toranoana Inc. All Rights Reserved. 実装と作ったもの(Webアプリ化) 17 ● 暗号化について ● 詳細はMDNで https://developer.mozilla.org/ja/docs/Web/API/SubtleCrypto ● まずはsecret.jsonを生成(アプリ起動前) ○ jwkという形式でjsonを作れるのでそのままファイルに保存 ○ Git等に入れないように注意! ■ いわゆる秘密鍵なのでサーバー個別に持つべき async function genKey() { return await crypto.subtle.generateKey( { name: "AES-GCM", length: 256 }, true, ["encrypt", "decrypt"], ); } async function exportKey() { const key = await crypto.subtle.exportKey( "jwk", await genKey(), ); await Deno.writeTextFile("./secret.json", JSON.stringify(key)); console.log("generate secret.json. add to .gitignore"); } await exportKey();
18.
Copyright (C) 2021
Toranoana Inc. All Rights Reserved. 実装と作ったもの(Webアプリ化) 18 ● 暗号化処理 async function loadSecret() { const text = JSON.parse(await Deno.readTextFile("secret.json")); return await crypto.subtle.importKey( "jwk", text, { name: "AES-GCM" }, false, ["encrypt", "decrypt"], ); } export async function tokenEncrypt(val: string): Promise<string> { const ivBytes = iv(); const c = await crypto.subtle.encrypt( { name: "AES-GCM", iv: ivBytes }, await loadSecret(), new TextEncoder().encode(val), ); ● iv ○ 暗号化のために必要なランダムな値 ○ 秘密である必要はないが、一意である必要がある ○ GCMでは12byteが推奨なので注意 ● loadSecret ○ 先程のsecret.jsonを読み込む ○ 本来ならば起動時に一度のみ読み込みたい ■ もしくはキャッシュ ● tokenEncrypt ○ 上記を合わせて引数の文字列を暗号化する ○ 後にcookieに書き込みたいのでちゃんと文字として値を返 す return `${btoa(String.fromCharCode(...new Uint8Array(ivBytes)))}--${ btoa(String.fromCharCode(...new Uint8Array(c))) }`; }
19.
Copyright (C) 2021
Toranoana Inc. All Rights Reserved. 実装と作ったもの(Webアプリ化) 19 ● 復号処理 export async function tokenDecrypt(val: string): Promise<string> { const [ivVal, token] = val.split("--"); const encryptedBytes = atob(token); const ivBytes = atob(ivVal); const encryptedData = Uint8Array.from( encryptedBytes.split(""), (char) => char.charCodeAt(0), ); const ivData = Uint8Array.from( ivBytes.split(""), (char) => char.charCodeAt(0), ); ● 基本的には暗号化の逆を行う ○ iv及びsecretを使って復号化する ● 最終的にはトークンがほしいのでこちらも文字列に ● 基本的にはサーバー側でしか実行されない ○ Denoに生えているAPIも使える(はず) const decryptedArrayBuffer = await crypto.subtle.decrypt( { name: "AES-GCM", iv: ivData }, await loadSecret(), encryptedData, ); return new TextDecoder().decode(new Uint8Array(decryptedArrayBuffer)); }
20.
Copyright (C) 2021
Toranoana Inc. All Rights Reserved. 実装と作ったもの(Webアプリ化) 20 トークンを使って情報取得(pages/api/github/repos.ts) export async function handler(ctx: HandlerContext): Promise<Response> { const cookieValue = getCookies(ctx.req.headers)["oauth_token"]; const url = new URL(ctx.req.url); const page = url.searchParams.get("page") || "1"; const perPage = url.searchParams.get("per_page") || "30"; const res = await fetch( `https://api.github.com/user/repos?page=${page}&per_page=${perPage}`, { headers: { Authorization: `token ${await tokenDecrypt(cookieValue)}`, }, }, ); const resJson = await res.json(); const link = res.headers.get("link") || ""; const pagenation = buildPagenation(link); return new Response(JSON.stringify({ link: pagenation, repos: resJson, })); } ● tokenの復号化などの処理がはいるので直接GitHub API を叩くのではなく、サーバーを経由する ● 先程と同様にhandlerのみでルーティングする ● apiディレクトリに置くことでよりAPIらしく使える ○ fresh initしたときにも生成されるのでそちらも参 照
21.
Copyright (C) 2021
Toranoana Inc. All Rights Reserved. 実装と作ったもの(Webアプリ化) 21 API使う側(mypage/github.tsx) 普通のReactアプリなので特筆することはなし →cookie等の都合でssr時のAPIコールがうまく行かない const PER_PAGE = 30; export default function Github(props: PageProps) { const [repos, setRepos] = useState({ repos: [], }); const initUrl = useData("repoInitUrl", () => props.url); const pageParams = useData( "repoInitPageNo", () => { const p = parseInt(props.url.searchParams.get("page") || "1"); if (p <= 0) return 1; return p; }, ); const [url, setUrl] = useState(initUrl); const [page, setPage] = useState(pageParams); const [link, setLink] = useState<{ link: Pagenation }>({ link: { hasNext: false, hasPrev: false }, }); useEffect(() => { const call = async () => { const res = await fetch( `/api/github/repos?page=${page}&per_page=${PER_PAGE}`, ); const json = await res.json(); if (json.repos) { setRepos({ repos: json.repos }); } if (json.link) { setLink({ link: json.link }); } }; call(); const newUrl = new URL(url); newUrl.searchParams.set("page", page.toString()); window.history.pushState(null, "", newUrl); setUrl(newUrl); }, [page]); const onPrevPage = () => { if (link.link.hasPrev && link.link.prev) { setPage(link.link.prev); } }; const onNextPage = () => { if (link.link.hasNext && link.link.next) { setPage(link.link.next); } };
22.
Copyright (C) 2021
Toranoana Inc. All Rights Reserved. まとめ ● denoでGitHubにログイン〜APIコールを行ってみました ● 付随して暗号化なども実施しました ● freshを使ってWebアプリにしました ● freshは全く枯れてないのでご利用にはご注意を ● フィルタなどの実装は今後 ○ handlerとjsx組み合わせればできる(気がする) 22
Download