Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
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
4 changes: 3 additions & 1 deletion server/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -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",
Expand All @@ -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"
}
}
1 change: 1 addition & 0 deletions server/src/constants.ts
Original file line number Diff line number Diff line change
@@ -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',
Expand Down
33 changes: 33 additions & 0 deletions server/src/entities/Administor.ts
Original file line number Diff line number Diff line change
@@ -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;
}
29 changes: 29 additions & 0 deletions server/src/entities/AllowList.ts
Original file line number Diff line number Diff line change
@@ -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;
}
53 changes: 53 additions & 0 deletions server/src/handler/addAllowUser.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,53 @@
import express from 'express';
import { Redis } from 'ioredis';
import { AllowList } from '../entities/AllowList';
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);

await AllowList.create({ email }).save();

res.send('complete add user email');
res.end();
return;
}

res.send(
'this token is valid. expired or incorrect. \n please get new token'
);

res.end();
} catch (e) {
console.log(e);
}
};
47 changes: 47 additions & 0 deletions server/src/handler/getAdminToken.ts
Original file line number Diff line number Diff line change
@@ -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 = 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);
}
};
30 changes: 27 additions & 3 deletions server/src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -21,11 +21,15 @@ import { SharedBook } from './entities/SharedBook';
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';
import { addAllowUser } from './handler/addAllowUser';

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',
Expand All @@ -35,7 +39,7 @@ const main = async () => {
logging: true,
synchronize: true,
migrations: [path.join(__dirname, './migrations/*')],
entities: [User, Library, Book, SharedBook],
entities: [User, Library, Book, SharedBook, Administor, AllowList],
});

// await conn.runMigrations();
Expand Down Expand Up @@ -117,6 +121,26 @@ 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, redis));

app.post('/addAllowUser', (req, res) => addAllowUser(req, res, redis));

app.listen(4000, () => {
console.log('server start on port 4000');
});
Expand Down
2 changes: 1 addition & 1 deletion server/src/resolvers/user.ts
Original file line number Diff line number Diff line change
Expand Up @@ -58,7 +58,7 @@ export class UserResolver {
@Arg('options') options: RegisterInput,
@Ctx() { req }: MyContext
): Promise<UserResponse> {
const errors = validateRejister(options);
const errors = await validateRejister(options);
if (errors) {
return { errors };
}
Expand Down
25 changes: 20 additions & 5 deletions server/src/utils/validateRegister.ts
Original file line number Diff line number Diff line change
@@ -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',
Expand All @@ -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 [
{
Expand Down
7 changes: 6 additions & 1 deletion server/yarn.lock
Original file line number Diff line number Diff line change
Expand Up @@ -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"
Expand Down Expand Up @@ -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==
Expand Down