Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: 認証機構導入、いくつかでもページ作成 #115

Merged
merged 46 commits into from
Nov 20, 2021
Merged
Show file tree
Hide file tree
Changes from 45 commits
Commits
Show all changes
46 commits
Select commit Hold shift + click to select a range
8925ada
chore(docker): setup firebase docker for development GCIP emulator
LumaKernel Nov 19, 2021
b1afd71
chore: revert missing frourio dev script
LumaKernel Nov 19, 2021
d0f0057
chore: not use js entries, but use ts entries with require
LumaKernel Nov 19, 2021
e6739c1
chore(rule): update hadolint rule for dev ubuntu
LumaKernel Nov 19, 2021
5ac3a8f
chore: tiny dockerfile update
LumaKernel Nov 19, 2021
0f06454
refactor(env): refactor env files
LumaKernel Nov 19, 2021
e80a717
feat(api): create firebase-admin service files
LumaKernel Nov 19, 2021
099313c
feat(api): create routes about authentication with http-only cookie
LumaKernel Nov 19, 2021
ea72f14
refactor: env
LumaKernel Nov 19, 2021
209ddb7
refactor: unnecessary "as any"
LumaKernel Nov 19, 2021
0ba05dd
feat: csrf
LumaKernel Nov 19, 2021
f4c3551
test: new fastify plugins injection
LumaKernel Nov 19, 2021
dd0c033
feat: new route to get csrf token
LumaKernel Nov 19, 2021
851fc3b
refactor: fastify logger library
LumaKernel Nov 19, 2021
ba2b075
feat(def): type definitions for session claims
LumaKernel Nov 19, 2021
fbc1557
chore(lambda-conv2img): fit to env name changes
LumaKernel Nov 19, 2021
ad5faf9
chore(dev): create dev api routes for debug
LumaKernel Nov 19, 2021
73a4294
feat(web): create firebase util
LumaKernel Nov 19, 2021
c630f26
feat(web): csrf support for api client
LumaKernel Nov 19, 2021
d72c8c0
feat(web): create auth context and provider
LumaKernel Nov 19, 2021
79acefb
feat(web): provide api before auth because auth depends on api
LumaKernel Nov 19, 2021
199fda7
refactor(web): modal
LumaKernel Nov 19, 2021
2d9052c
refactor(web): show error to log for debugging
LumaKernel Nov 19, 2021
8e7c20c
feat(web): create signin modal
LumaKernel Nov 19, 2021
5e364f6
refactor(web): ban src/... imports
LumaKernel Nov 19, 2021
19dd9cf
refactor(web): typo "medium"
LumaKernel Nov 19, 2021
5d9786a
chore(eslint): update rule no-unused-vars to ignore underline prefixe…
LumaKernel Nov 19, 2021
2966900
chore(eslint): prevent using firebase/* itself
LumaKernel Nov 19, 2021
bc4436a
refactor(web): inputCompleted -> onComplete
LumaKernel Nov 19, 2021
05c707a
chore: update and create dev demo pages
LumaKernel Nov 19, 2021
087bfc9
chore(tsconfig): remove baseUrl and add downlevelIteration=true
LumaKernel Nov 19, 2021
a140ab9
chore(env): add default development frontend envs
LumaKernel Nov 19, 2021
7109321
chore(env): add ARGs to dockerfile
LumaKernel Nov 19, 2021
1340c4d
chore(deps): add firebase and react-firebaseui
LumaKernel Nov 19, 2021
d98a190
chore(license-notice): add license notice
LumaKernel Nov 19, 2021
1a7017e
docs: update contributing
LumaKernel Nov 19, 2021
5a574ae
chore: update codeowners
LumaKernel Nov 19, 2021
fc43fc4
chore: update lockfile
LumaKernel Nov 19, 2021
253fefa
chore: fit Explorer/index to CardModal
LumaKernel Nov 20, 2021
7eab592
chore: missing re-export
LumaKernel Nov 20, 2021
8e70d3f
chore: missing re-export
LumaKernel Nov 20, 2021
f780a58
chore: lint fix
LumaKernel Nov 20, 2021
ab3426c
chore: fit conv2img dockerfile to new entrypoint
LumaKernel Nov 20, 2021
752b81d
chore: fit env names to new names
LumaKernel Nov 20, 2021
f7c0648
chore: remove unnecessary eslint disable comment
LumaKernel Nov 20, 2021
47b6596
refactor: use swr for auth context
LumaKernel Nov 20, 2021
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions .env.example
Original file line number Diff line number Diff line change
Expand Up @@ -14,4 +14,6 @@ TZ=Asia/Tokyo
MINIO_ROOT_USER=minio
MINIO_ROOT_PASSWORD=password
S3_ENDPOINT=http://localhost:9000
FIREBASE_AUTH_EMULATOR_HOST=localhost:9099
GCIP_PROJECT=emulator
PRETTY_LOGGING=1
10 changes: 10 additions & 0 deletions .eslintrc.js
Original file line number Diff line number Diff line change
Expand Up @@ -48,6 +48,12 @@ module.exports = {
'@typescript-eslint/explicit-module-boundary-types': 'off',
'@typescript-eslint/no-empty-function': 'off',
'@typescript-eslint/consistent-type-imports': 'error',
'@typescript-eslint/no-unused-vars': [
'error',
{
argsIgnorePattern: '^_',
},
],
'object-shorthand': [
'error',
'always',
Expand All @@ -69,6 +75,10 @@ module.exports = {
'error',
{
patterns: [
{
group: ['firebase/*'],
message: `do not directly import firebase/* instead use src/utils/firebase`,
},
{
group: ['.prisma/*'],
message: `do not use .prisma/* instead use @prisma/*`,
Expand Down
28 changes: 19 additions & 9 deletions CODEOWNERS
Validating CODEOWNERS rules …
Original file line number Diff line number Diff line change
Expand Up @@ -13,23 +13,33 @@

# security
/.github/ @violet-ts/security
**/package.json @violet-ts/security
package.json @violet-ts/security
pnpm-lock.yaml @violet-ts/security
ws-credential.ts @violet-ts/security
/pkg/api/api/auth/ @violet-ts/security
/pkg/api/api/csrf/ @violet-ts/security
.env @violet-ts/security
.env.production @violet-ts/security
.env.example @violet-ts/security
pnpm-lock.yaml @violet-ts/security
**/aws-credential.ts @violet-ts/infrastructure

# infrastructure
/.github/ @violet-ts/infrastructure
**/package.json @violet-ts/infrastructure
package.json @violet-ts/infrastructure
/pkg/api/scripts/ @violet-ts/infrastructure
/pkg/api/prisma/ @violet-ts/infrastructure
/pkg/api/api/healthz/ @violet-ts/infrastructure
/pkg/api/.env.example @violet-ts/infrastructure
/pkg/api/src/utils/envValues.ts @violet-ts/infrastructure
/pkg/api/src/utils/envValues.ts @violet-ts/infrastructure
**/s3.ts @violet-ts/infrastructure
**/aws-credential.ts @violet-ts/infrastructure

/pkg/api/api/auth/ @violet-ts/infrastructure
/pkg/api/api/csrf/ @violet-ts/infrastructure
/pkg/api/src/service/firebase-admin/ @violet-ts/infrastructure
.env @violet-ts/infrastructure
.env.production @violet-ts/infrastructure
.env.example @violet-ts/infrastructure
/pkg/def/ @violet-ts/infrastructure
s3.ts @violet-ts/infrastructure
aws-credential.ts @violet-ts/infrastructure
/pkg/web/public/ @violet-ts/infrastructure
/pkg/web/next.config.js @violet-ts/infrastructure
/pkg/web/src/utils/firebase/ @violet-ts/infrastructure
/docker/ @violet-ts/infrastructure
/docker-compose.yml @violet-ts/infrastructure
49 changes: 46 additions & 3 deletions CONTRIBUTING-ja.md
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@ pnpm run dev
- web: [http://localhost:3000](http://localhost:3000)
- api: [http://localhost:8080](http://localhost:8080)
- minio ui: [http://localhost:9001](http://localhost:9001)
- Firebase Auth Suite Auth:[http://localhost:4000/auth](http://localhost:4000/auth)

### チェックアウト後

Expand Down Expand Up @@ -53,12 +54,49 @@ pnpm exec prisma studio
docker-compose exec mysql bash -c "mysql -u root -proot"
```

### Authentication

プロダクションのアイデンティティ管理には [Google Cloud Identity Platform (GCIP)](https://cloud.google.com/identity-platform) を使用します。
ただし、開発中はデフォルトで Firebase emulator を使う用になっています。

#### Firebase エミュレータを使用

特に設定は要りません。以下のユーザ名とパスワードのセットがデフォルトで入った状態で起動します。 noicon1 はアイコンが設定されていないユーザです。
認証方法はメール以外は使用できません。

```
[email protected]
testuserexample1
[email protected]
testuserexample2
[email protected]
noicon1
```

#### GCIP につなぐ

ローカル環境を GCIP 環境に接続することも可能です。以下のように環境変数をセットします。

```
# .env
GOOGLE_APPLICATION_CREDENTIALS=/path/to/dir/gcloud-violet-credential.json
GCLOUD_PROJECT=your-proj
FIREBASE_AUTH_EMULATOR_HOST=
```

```
# pkg/web/.env.local
NEXT_PUBLIC_GCIP_API_KEY=xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
NEXT_PUBLIC_GCIP_AUTH_DOMAIN=your-proj.firebaseapp.com
NEXT_PUBLIC_AUTH_EMULATOR=
```

### Lambda 内のソースコードに変更があった際

Lambda Docker は起動時のコードが使用され続けるので、リビルドしても、再起動が必要です。これは一瞬で終わります。
Lambda Docker は、依存のバージョンアップをしたなど、場合によっては再起動が必要です。これは一瞬で終わります。

- `docker rm -f lambda; docker up -d lambda`
- `docker up lambda` でアタッチされている状態のまま `CTRL-C` (`CTRL-\` で抜けれます)、その後 `docker up lambda`
- `docker-compose rm -f lambda; docker-compose up -d lambda`
- `docker-compose up lambda` でアタッチされている状態のまま `CTRL-C` (`CTRL-\` で抜けれます)、その後 `docker-compose up lambda`


## コーディングルール
Expand All @@ -68,6 +106,11 @@ Lambda Docker は起動時のコードが使用され続けるので、リビル
- `pnpm run lint -w` でチェック
- `pnpm run lint:fix -w` で自動修正

### ルーティング

- api, web ともに `/dev/` 配下は staging 以降はロードバランサで弾きます。 (予定)
- 危険な操作ができるような API は作成を避けてください

### Dockerfile

- `hadolint` を使用します。ルール指定をスクリプト経由でしているので、スクリプトから起動してください
Expand Down
17 changes: 17 additions & 0 deletions NOTICE
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
## googleapis/google-auth-library-nodejs awsclient.ts
Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

awsclient.ts をコピペして改造したのでライセンス明記しています


https://github.com/googleapis/google-auth-library-nodejs/blob/5ed910513451c82e2551777a3e2212964799ef8e/src/auth/awsclient.ts

// Copyright 2021 Google LLC
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
11 changes: 11 additions & 0 deletions docker-compose.yml
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,17 @@ services:
- mysql_data:/var/lib/mysql
- ./docker/dev/mysql/my.cnf:/etc/mysql/conf.d/my.cnf

firebase:
build: ./docker/dev/firebase
restart: always
ports:
- 9099:9099 # Auth
- 4000:4000 # Emulator Suite UI
env_file:
- ./.env
working_dir: /opt/workspace
command: firebase emulators:start --only=auth --project=emulator --import=seeder
Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

起動コマンドが以前と少し違います。ログインは必要ありません。トンネルでも使えると思います

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

詳細理解できてないけど、私がセットアップしたときにはオフライン対応わからなくて諦めたんだよなー
これは非常にありがたい


minio:
image: minio/minio
restart: always
Expand Down
10 changes: 10 additions & 0 deletions docker/dev/firebase/Dockerfile
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
FROM node:14-buster

RUN apt-get update -y
RUN ( \
apt-get install -y --no-install-recommends \
curl \
openjdk-11-jre-headless \
)
RUN npm install -g firebase-tools
COPY . /opt/workspace/
13 changes: 13 additions & 0 deletions docker/dev/firebase/firebase.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
{
"emulators": {
"auth": {
"host": "0.0.0.0",
"port": 9099
},
"ui": {
"enabled": true,
"host": "0.0.0.0",
"port": 4000
}
}
}
74 changes: 74 additions & 0 deletions docker/dev/firebase/seeder/auth_export/accounts.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,74 @@
{
"kind": "identitytoolkit#DownloadAccountResponse",
"users": [
{
"localId": "DPSkoJjj8KsGHcQbxTgrjBvWBvry",
"createdAt": "1637156432583",
"lastLoginAt": "1637156432583",
"displayName": "Test User1",
"photoUrl": "https://github.com/icons8/flat-color-icons/raw/master/svg/businessman.svg",
"emailVerified": false,
"email": "[email protected]",
"salt": "fakeSaltgovA2leAJckPXg5eYKxn",
"passwordHash": "fakeHash:salt=fakeSaltgovA2leAJckPXg5eYKxn:password=testuserexample1",
"passwordUpdatedAt": 1637156432583,
"validSince": "1637156432",
"providerUserInfo": [
{
"providerId": "password",
"email": "[email protected]",
"federatedId": "[email protected]",
"rawId": "[email protected]",
"displayName": "Test User1",
"photoUrl": "https://github.com/icons8/flat-color-icons/raw/master/svg/businessman.svg"
}
]
},
{
"localId": "K9oXOw5p4rYejYmqSUnmOTszIayh",
"createdAt": "1637156463904",
"lastLoginAt": "1637156463903",
"displayName": "No Icon1",
"photoUrl": "",
"emailVerified": false,
"email": "[email protected]",
"salt": "fakeSaltTtKyT0aMQ0ejTo3WMwE2",
"passwordHash": "fakeHash:salt=fakeSaltTtKyT0aMQ0ejTo3WMwE2:password=noicon1",
"passwordUpdatedAt": 1637156463903,
"validSince": "1637156463",
"providerUserInfo": [
{
"providerId": "password",
"email": "[email protected]",
"federatedId": "[email protected]",
"rawId": "[email protected]",
"displayName": "No Icon1",
"photoUrl": ""
}
]
},
{
"localId": "t5lq8rDTp238rIIhJm1se9xniNmR",
"createdAt": "1637156455279",
"lastLoginAt": "1637156455279",
"displayName": "Test User2",
"photoUrl": "https://github.com/icons8/flat-color-icons/raw/master/svg/businesswoman.svg",
"emailVerified": false,
"email": "[email protected]",
"salt": "fakeSaltdbUljyCSmcidArL2dqed",
"passwordHash": "fakeHash:salt=fakeSaltdbUljyCSmcidArL2dqed:password=testuserexample2",
"passwordUpdatedAt": 1637156455279,
"validSince": "1637156455",
"providerUserInfo": [
{
"providerId": "password",
"email": "[email protected]",
"federatedId": "[email protected]",
"rawId": "[email protected]",
"displayName": "Test User2",
"photoUrl": "https://github.com/icons8/flat-color-icons/raw/master/svg/businesswoman.svg"
}
]
}
]
}
1 change: 1 addition & 0 deletions docker/dev/firebase/seeder/auth_export/config.json
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
{ "signIn": { "allowDuplicateEmails": false } }
7 changes: 7 additions & 0 deletions docker/dev/firebase/seeder/firebase-export-metadata.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
{
"version": "9.22.0",
"auth": {
"version": "9.22.0",
"path": "auth_export"
}
}
3 changes: 1 addition & 2 deletions docker/dev/lambda/conv2img/Dockerfile
Original file line number Diff line number Diff line change
Expand Up @@ -7,8 +7,7 @@ RUN yum install -y libreoffice
RUN yum install -y libreoffice-langpack-ja
RUN yum install -y ImageMagick
RUN yum install -y libwebp-tools
RUN yum clean all

ENV NODE_ENV development

CMD ["pkg/lambda/conv2img/bin/index.handler"]
CMD ["pkg/lambda/conv2img/build/index.handler"]
2 changes: 1 addition & 1 deletion docker/prod/api/Dockerfile
Original file line number Diff line number Diff line change
Expand Up @@ -27,4 +27,4 @@ WORKDIR /app/pkg/api
EXPOSE 80

ENTRYPOINT []
CMD ["node", "--require=source-map-support/register", "./build/index.js"]
CMD ["node", "./build/index.js"]
2 changes: 1 addition & 1 deletion docker/prod/lambda/apiexec/Dockerfile
Original file line number Diff line number Diff line change
Expand Up @@ -17,4 +17,4 @@ RUN ( \
&& rm -rf "$HOME/.pnpm-store" \
)

CMD ["pkg/api/bin/lambda.handler"]
CMD ["pkg/api/build/lambda.handler"]
2 changes: 1 addition & 1 deletion docker/prod/lambda/conv2img/Dockerfile
Original file line number Diff line number Diff line change
Expand Up @@ -27,4 +27,4 @@ RUN ( \
&& rm -rf "$HOME/.pnpm-store" \
)

CMD ["pkg/lambda/conv2img/bin/index.handler"]
CMD ["pkg/lambda/conv2img/build/index.handler"]
4 changes: 4 additions & 0 deletions docker/prod/web/Dockerfile
Original file line number Diff line number Diff line change
@@ -1,5 +1,9 @@
FROM node:14-buster
ARG API_ORIGIN
ARG API_BASE_PATH
ARG NEXT_PUBLIC_AUTH_SHOW_EMAIL
ARG NEXT_PUBLIC_GCIP_API_KEY
ARG NEXT_PUBLIC_GCIP_AUTH_DOMAIN
SHELL ["/bin/bash", "-o", "pipefail", "-c"]

RUN ( \
Expand Down
1 change: 1 addition & 0 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -60,6 +60,7 @@
"jest-fetch-mock": "^3.0.3",
"node-dev": "^7.1.0",
"npm-run-all": "^4.1.5",
"onchange": "^7.1.0",
"pathpida": "^0.17.0",
"postcss": "^8.3.6",
"prettier": "^2.3.2",
Expand Down
3 changes: 3 additions & 0 deletions pkg/api/api/auth/controller.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
import { defineController } from './$relay'

export default defineController(() => ({}))
1 change: 1 addition & 0 deletions pkg/api/api/auth/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
export type Methods = Record<string, never>
34 changes: 34 additions & 0 deletions pkg/api/api/auth/session/controller.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
import { getCachedApp } from '@violet/api/src/service/firebase-admin'
import { defineController } from './$relay'

// https://firebase.google.com/docs/auth/admin/manage-cookies
export default defineController(() => ({
post: async ({ body: { idToken }, env, logger, setCookie }) => {
// TODO(security): kick too old tokens
const auth = getCachedApp({ env, logger }).auth()
// 5 days
const expiresIn = 60 * 60 * 24 * 5 * 1000
const sessionCookie = await auth.createSessionCookie(idToken, { expiresIn })
Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

日数は要相談ですが、5 days でもワンクリックでログインできるのでそんなに大変でもないです

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

長期のセッション保存を大手に任せて、自分側では短くするというのは方針としては正しいと思っている
あまり長くすると、GitHub 側で revoke session してもずっと入れてしまうのでこれでも長いくらいか

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

個人的にはサイトを開いている間自動でリフレッシュしてくれればトークンは短命でもいい

setCookie('session', sessionCookie, {
signed: true,
maxAge: expiresIn,
httpOnly: true,
secure: process.env.NODE_ENV === 'production',
path: '/',
})
return {
status: 200,
body: {},
}
},
delete: async ({ setCookie }) => {
setCookie('session', '', {
maxAge: 0,
path: '/',
})
return {
status: 200,
body: {},
}
},
}))
10 changes: 10 additions & 0 deletions pkg/api/api/auth/session/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
export type Methods = {
post: {
reqBody: {
idToken: string
}
}
delete: {
reqBody: Record<string, never>
}
}
8 changes: 8 additions & 0 deletions pkg/api/api/auth/user/controller.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
import { defineController } from './$relay'

export default defineController(() => ({
get: async ({ getUserClaims }) => ({
status: 200,
body: await getUserClaims(),
}),
}))
Loading