From b83b3609f6190d5ea4387f4923c45637bceaeb40 Mon Sep 17 00:00:00 2001 From: kirikirisu Date: Sun, 2 May 2021 10:29:57 +0900 Subject: [PATCH 1/4] add allow list entities --- server/src/entities/AllowList.ts | 29 +++++++++++++++++++++++++++++ server/src/index.ts | 7 ++++--- 2 files changed, 33 insertions(+), 3 deletions(-) create mode 100644 server/src/entities/AllowList.ts diff --git a/server/src/entities/AllowList.ts b/server/src/entities/AllowList.ts new file mode 100644 index 0000000..8eef1ef --- /dev/null +++ b/server/src/entities/AllowList.ts @@ -0,0 +1,29 @@ +import { Field, ObjectType } from 'type-graphql'; +import { + BaseEntity, + Column, + CreateDateColumn, + Entity, + PrimaryGeneratedColumn, + UpdateDateColumn, +} from 'typeorm'; + +@ObjectType() +@Entity() +export class AllowList extends BaseEntity { + @PrimaryGeneratedColumn() + @Field() + id!: number; + + @Field() + @Column({ unique: true }) + email!: string; + + @Field(() => String) + @CreateDateColumn() + createdAt: Date; + + @Field(() => String) + @UpdateDateColumn() + updatedAt: Date; +} diff --git a/server/src/index.ts b/server/src/index.ts index 297ec90..6c3d995 100644 --- a/server/src/index.ts +++ b/server/src/index.ts @@ -21,11 +21,12 @@ import { SharedBook } from './entities/SharedBook'; import { createSubscriberLoader } from './loader/createSubscriberLoader'; import { createAdminLoader } from './loader/createAdminLoader'; import { slack } from './handler/slack'; +import { AllowList } from './entities/AllowList'; const main = async () => { dotenv.config(); - console.log(process.env.NODE_ENV); - console.log(process.env.CONTAINER_DATABASE_URL); + // console.log(process.env.NODE_ENV); + // console.log(process.env.CONTAINER_DATABASE_URL); await createConnection({ type: 'postgres', @@ -35,7 +36,7 @@ const main = async () => { logging: true, synchronize: true, migrations: [path.join(__dirname, './migrations/*')], - entities: [User, Library, Book, SharedBook], + entities: [User, Library, Book, SharedBook, AllowList], }); // await conn.runMigrations(); From 3d2f148674fc10496a9b7b23923e3a8d0385c637 Mon Sep 17 00:00:00 2001 From: kirikirisu Date: Mon, 3 May 2021 14:48:51 +0900 Subject: [PATCH 2/4] add: administor entities --- server/package.json | 4 ++- server/src/constants.ts | 1 + server/src/entities/Administor.ts | 33 ++++++++++++++++++++ server/src/handler/getAdminToken.ts | 47 +++++++++++++++++++++++++++++ server/src/index.ts | 26 +++++++++++++++- server/yarn.lock | 7 ++++- 6 files changed, 115 insertions(+), 3 deletions(-) create mode 100644 server/src/entities/Administor.ts create mode 100644 server/src/handler/getAdminToken.ts diff --git a/server/package.json b/server/package.json index 20c418b..9238750 100644 --- a/server/package.json +++ b/server/package.json @@ -21,6 +21,7 @@ "@types/express-session": "^1.17.3", "@types/ioredis": "^4.22.0", "@types/node": "^14.14.31", + "@types/uuid": "^8.3.0", "@typescript-eslint/eslint-plugin": "^4.19.0", "@typescript-eslint/parser": "^4.19.0", "eslint": "^7.22.0", @@ -47,6 +48,7 @@ "pg": "^8.5.1", "reflect-metadata": "^0.1.13", "type-graphql": "^1.1.1", - "typeorm": "^0.2.31" + "typeorm": "^0.2.31", + "uuid": "^8.3.2" } } diff --git a/server/src/constants.ts b/server/src/constants.ts index 595ed47..334db14 100644 --- a/server/src/constants.ts +++ b/server/src/constants.ts @@ -1,5 +1,6 @@ export const COOKIE_NAME = 'CID'; export const isContainer = () => process.env.NODE_ENV === 'container'; +export const ADMINISTOR_TOKEN_PREFIX = 'administor-token:'; export const SLACK_REQUEST_HEADER = { 'Content-Type': 'application/json', diff --git a/server/src/entities/Administor.ts b/server/src/entities/Administor.ts new file mode 100644 index 0000000..a5724c9 --- /dev/null +++ b/server/src/entities/Administor.ts @@ -0,0 +1,33 @@ +import { Field, ObjectType } from 'type-graphql'; +import { + BaseEntity, + Column, + CreateDateColumn, + Entity, + PrimaryGeneratedColumn, + UpdateDateColumn, +} from 'typeorm'; + +@ObjectType() +@Entity() +export class Administor extends BaseEntity { + @PrimaryGeneratedColumn() + @Field() + id!: number; + + @Field() + @Column({ unique: true }) + username!: string; + + @Field() + @Column() + password!: string; + + @Field(() => String) + @CreateDateColumn() + createdAt: Date; + + @Field(() => String) + @UpdateDateColumn() + updatedAt: Date; +} diff --git a/server/src/handler/getAdminToken.ts b/server/src/handler/getAdminToken.ts new file mode 100644 index 0000000..c08f9ad --- /dev/null +++ b/server/src/handler/getAdminToken.ts @@ -0,0 +1,47 @@ +import express from 'express'; +import argon2 from 'argon2'; +import { Administor } from '../entities/Administor'; +import { v4 } from 'uuid'; +// import { Redis } from 'ioredis'; +// import { ADMINISTOR_TOKEN_PREFIX } from '../constants'; + +export const getAdminToken = async ( + req: express.Request, + res: express.Response + // redis: Redis +) => { + try { + const { username, password: rawPass } = req.body; + + const administor = await Administor.findOne({ where: { username } }); + + if (!administor) { + res.send('administor not found.'); + res.end(); + return; + } + const valid = await argon2.verify(administor.password, rawPass); + if (!valid) { + res.send('incorrect password.'); + res.end(); + return; + } + + const token = v4(); + // const expireMiniutes = 1000 * 60 * 5; + + // await redis.set( + // ADMINISTOR_TOKEN_PREFIX + token, + // administor.username, + // 'ex', + // expireMiniutes + // ); + + res.send( + `success!! you could get token. \n this token has an expiration date of 5 miniutes. \n \n ${token} \n` + ); + res.end(); + } catch (e) { + console.log('async error', e); + } +}; diff --git a/server/src/index.ts b/server/src/index.ts index c88af83..2da9721 100644 --- a/server/src/index.ts +++ b/server/src/index.ts @@ -22,6 +22,8 @@ import { createSubscriberLoader } from './loader/createSubscriberLoader'; import { createUserLoader } from './loader/createUserLoader'; import { slack } from './handler/slack'; import { AllowList } from './entities/AllowList'; +import { Administor } from './entities/Administor'; +import { getAdminToken } from './handler/getAdminToken'; const main = async () => { dotenv.config(); @@ -36,7 +38,7 @@ const main = async () => { logging: true, synchronize: true, migrations: [path.join(__dirname, './migrations/*')], - entities: [User, Library, Book, SharedBook, AllowList], + entities: [User, Library, Book, SharedBook, Administor, AllowList], }); // await conn.runMigrations(); @@ -118,6 +120,28 @@ const main = async () => { console.log('slackHandlerStatus', status); }); + // app.post('/setAdmin', async (_, res) => { + // const username = 'smp'; + // const password = 'hoge'; + + // const hashedPassword = await argon2.hash(password); + + // pgConnection + // .createQueryBuilder() + // .insert() + // .into(Administor) + // .values({ username: username, password: hashedPassword }) + // .execute(); + + // res.end(); + // }); + + app.post('/getAdminToken', (req, res) => getAdminToken(req, res)); + + app.post('/addAllowUser', (_, res) => { + res.send('OK. server working!!'); + }); + app.listen(4000, () => { console.log('server start on port 4000'); }); diff --git a/server/yarn.lock b/server/yarn.lock index 46cefae..5bcf7c0 100644 --- a/server/yarn.lock +++ b/server/yarn.lock @@ -416,6 +416,11 @@ "@types/mime" "^1" "@types/node" "*" +"@types/uuid@^8.3.0": + version "8.3.0" + resolved "https://registry.yarnpkg.com/@types/uuid/-/uuid-8.3.0.tgz#215c231dff736d5ba92410e6d602050cce7e273f" + integrity sha512-eQ9qFW/fhfGJF8WKHGEHZEyVWfZxrT+6CLIJGBcZPfxUh/+BnEj+UCGYMlr9qZuX/2AltsvwrGqp0LhEW8D0zQ== + "@types/ws@^7.0.0": version "7.4.0" resolved "https://registry.yarnpkg.com/@types/ws/-/ws-7.4.0.tgz#499690ea08736e05a8186113dac37769ab251a0e" @@ -3778,7 +3783,7 @@ uuid@^3.1.0: resolved "https://registry.yarnpkg.com/uuid/-/uuid-3.4.0.tgz#b23e4358afa8a202fe7a100af1f5f883f02007ee" integrity sha512-HjSDRw6gZE5JMggctHBcjVak08+KEVhSIiDzFnT9S9aegmp85S/bReBVTb4QTFaRNptJ9kuYaNhnbNEOkbKb/A== -uuid@^8.0.0: +uuid@^8.0.0, uuid@^8.3.2: version "8.3.2" resolved "https://registry.yarnpkg.com/uuid/-/uuid-8.3.2.tgz#80d5b5ced271bb9af6c445f21a1a04c606cefbe2" integrity sha512-+NYs2QeMWy+GWFOEm9xnn6HCDp0l7QBD7ml8zLUmJ+93Q5NF0NocErnwkTkXVFNiX3/fpC6afS8Dhb/gz7R7eg== From f744261ce48d2367f920edd12cf367a7647a837c Mon Sep 17 00:00:00 2001 From: kirikirisu Date: Sat, 8 May 2021 11:50:26 +0900 Subject: [PATCH 3/4] add: expire token generate --- server/src/handler/addAllowUser.ts | 49 +++++++++++++++++++++++++++++ server/src/handler/getAdminToken.ts | 22 ++++++------- server/src/index.ts | 7 ++--- 3 files changed, 63 insertions(+), 15 deletions(-) create mode 100644 server/src/handler/addAllowUser.ts diff --git a/server/src/handler/addAllowUser.ts b/server/src/handler/addAllowUser.ts new file mode 100644 index 0000000..1f0a54d --- /dev/null +++ b/server/src/handler/addAllowUser.ts @@ -0,0 +1,49 @@ +import express from 'express'; +import { Redis } from 'ioredis'; +import { ADMINISTOR_TOKEN_PREFIX } from '../constants'; + +export const addAllowUser = async ( + req: express.Request, + res: express.Response, + redis: Redis +) => { + try { + const { authorization: authToken } = req.headers; + const { email } = req.body; + + if (!authToken) { + res.send('please input token.'); + res.end(); + return; + } + + if (!email || !email.includes('@')) { + res.send('plese input email address'); + res.end(); + return; + } + if (!email.includes('planet.kanazawa-it')) { + res.send('please input KIT mail address.'); + res.end(); + return; + } + + const redisKey = ADMINISTOR_TOKEN_PREFIX + authToken; + const username = await redis.get(redisKey); + + if (username) { + console.log(redisKey, username); + res.send('you can add user'); + res.end(); + return; + } + + res.send( + 'this token is valid. expired or incorrect. \n please get new token' + ); + + res.end(); + } catch (e) { + console.log(e); + } +}; diff --git a/server/src/handler/getAdminToken.ts b/server/src/handler/getAdminToken.ts index c08f9ad..e9a8474 100644 --- a/server/src/handler/getAdminToken.ts +++ b/server/src/handler/getAdminToken.ts @@ -2,13 +2,13 @@ import express from 'express'; import argon2 from 'argon2'; import { Administor } from '../entities/Administor'; import { v4 } from 'uuid'; -// import { Redis } from 'ioredis'; -// import { ADMINISTOR_TOKEN_PREFIX } from '../constants'; +import { Redis } from 'ioredis'; +import { ADMINISTOR_TOKEN_PREFIX } from '../constants'; export const getAdminToken = async ( req: express.Request, - res: express.Response - // redis: Redis + res: express.Response, + redis: Redis ) => { try { const { username, password: rawPass } = req.body; @@ -28,14 +28,14 @@ export const getAdminToken = async ( } const token = v4(); - // const expireMiniutes = 1000 * 60 * 5; + const expireMiniutes = 60 * 5; - // await redis.set( - // ADMINISTOR_TOKEN_PREFIX + token, - // administor.username, - // 'ex', - // expireMiniutes - // ); + await redis.set( + ADMINISTOR_TOKEN_PREFIX + token, + administor.username, + 'EX', + expireMiniutes + ); res.send( `success!! you could get token. \n this token has an expiration date of 5 miniutes. \n \n ${token} \n` diff --git a/server/src/index.ts b/server/src/index.ts index 2da9721..6d9817e 100644 --- a/server/src/index.ts +++ b/server/src/index.ts @@ -24,6 +24,7 @@ import { slack } from './handler/slack'; import { AllowList } from './entities/AllowList'; import { Administor } from './entities/Administor'; import { getAdminToken } from './handler/getAdminToken'; +import { addAllowUser } from './handler/addAllowUser'; const main = async () => { dotenv.config(); @@ -136,11 +137,9 @@ const main = async () => { // res.end(); // }); - app.post('/getAdminToken', (req, res) => getAdminToken(req, res)); + app.post('/getAdminToken', (req, res) => getAdminToken(req, res, redis)); - app.post('/addAllowUser', (_, res) => { - res.send('OK. server working!!'); - }); + app.post('/addAllowUser', (req, res) => addAllowUser(req, res, redis)); app.listen(4000, () => { console.log('server start on port 4000'); From ef3f233160bc3381e05f3b72ae2f5df546d888d3 Mon Sep 17 00:00:00 2001 From: kirikirisu Date: Sat, 8 May 2021 14:32:06 +0900 Subject: [PATCH 4/4] fix: email validation --- server/src/handler/addAllowUser.ts | 6 +++++- server/src/resolvers/user.ts | 2 +- server/src/utils/validateRegister.ts | 25 ++++++++++++++++++++----- 3 files changed, 26 insertions(+), 7 deletions(-) diff --git a/server/src/handler/addAllowUser.ts b/server/src/handler/addAllowUser.ts index 1f0a54d..465aec2 100644 --- a/server/src/handler/addAllowUser.ts +++ b/server/src/handler/addAllowUser.ts @@ -1,5 +1,6 @@ import express from 'express'; import { Redis } from 'ioredis'; +import { AllowList } from '../entities/AllowList'; import { ADMINISTOR_TOKEN_PREFIX } from '../constants'; export const addAllowUser = async ( @@ -33,7 +34,10 @@ export const addAllowUser = async ( if (username) { console.log(redisKey, username); - res.send('you can add user'); + + await AllowList.create({ email }).save(); + + res.send('complete add user email'); res.end(); return; } diff --git a/server/src/resolvers/user.ts b/server/src/resolvers/user.ts index 89c3673..6463045 100644 --- a/server/src/resolvers/user.ts +++ b/server/src/resolvers/user.ts @@ -58,7 +58,7 @@ export class UserResolver { @Arg('options') options: RegisterInput, @Ctx() { req }: MyContext ): Promise { - const errors = validateRejister(options); + const errors = await validateRejister(options); if (errors) { return { errors }; } diff --git a/server/src/utils/validateRegister.ts b/server/src/utils/validateRegister.ts index 08f1e29..ba7bf6e 100644 --- a/server/src/utils/validateRegister.ts +++ b/server/src/utils/validateRegister.ts @@ -1,16 +1,22 @@ +import { AllowList } from '../entities/AllowList'; import { RegisterInput } from '../types'; -export const validateRejister = (options: RegisterInput) => { - if (options.username.length <= 2) { +export const validateRejister = async (options: RegisterInput) => { + const { email } = options; + const allowUser = await AllowList.findOne({ + where: { email: email }, + }); + + if (!allowUser && email.includes('@')) { return [ { - field: 'username', - message: 'length must be greater than 2', + field: 'email', + message: 'このメールアドレスは登録できません', }, ]; } - if (!options.email.includes('@')) { + if (!email.includes('@')) { return [ { field: 'email', @@ -19,6 +25,15 @@ export const validateRejister = (options: RegisterInput) => { ]; } + if (options.username.length <= 2) { + return [ + { + field: 'username', + message: 'length must be greater than 2', + }, + ]; + } + if (options.username.includes('@')) { return [ {