송용우

Fixed remote file

1 +{
2 + "parser": "babel-eslint",
3 + "env": {
4 + "commonjs": true,
5 + "es6": true,
6 + "node": true
7 + },
8 + "extends": "eslint:recommended",
9 + "globals": {
10 + "Atomics": "readonly",
11 + "SharedArrayBuffer": "readonly"
12 + },
13 + "parserOptions": {
14 + "ecmaVersion": 11
15 + },
16 + "rules": {}
17 +}
1 +# See https://help.github.com/articles/ignoring-files/ for more about ignoring files.
2 +
3 +# dotenv
4 +.env
5 +
6 +# dependencies
7 +/node_modules
1 +# Jaksimsamil API Documentation
2 +
3 +## Overview
4 +
5 +- TBA
6 +
7 +## URL
8 +
9 +- TBA
10 +
11 +## Usage
12 +
13 +- TBA
14 +
15 +## Example
16 +
17 +- TBA
18 +
19 +## API Table
20 +
21 +| group | description | method | URL | Detail | Auth |
22 +| ------- | ------------------------ | ------ | -------------------------- | -------- | --------- |
23 +| user | 유저 등록 | POST | api/user | 바로가기 | JWT Token |
24 +| user | 유저 삭제 | DELETE | api/user:id | 바로가기 | JWT Token |
25 +| user | 특정 유저 조회 | GET | api/user:id | 바로가기 | None |
26 +| user | 전체 유저 조회 | GET | api/user | 바로가기 | JWT Token |
27 +| friend | 유저 친구 등록 | POST | api/friend | 바로가기 | JWT Token |
28 +| friend | 유저의 친구 조회 | GET | api/friend:id | 바로가기 | None |
29 +| profile | 유저가 푼 문제 조회 | GET | api/profile/solved:id | 바로가기 | None |
30 +| profile | 유저가 푼 문제 개수 조회 | GET | api/profile/solvednum:id | 바로가기 | None |
31 +| profile | 추천 문제 조회 | GET | api/profile/recommendps:id | 바로가기 | None |
32 +| notify | 슬랙 메시지 전송 요청 | POST | api/notify/slack | 바로가기 | Jwt Token |
33 +| auth | 로그인 | POST | api/auth/login | 바로가기 | None |
34 +| auth | 로그아웃 | GET | api/auth/logout | 바로가기 | JWT Token |
35 +| auth | 회원가입 | POST | api/auth/register | 바로가기 | None |
36 +| auth | 로그인 확인 | GET | api/auth/check | 바로가기 | None |
1 +const express = require("express");
2 +const morgan = require("morgan");
3 +const mongoose = require("mongoose");
4 +const app = express();
5 +const bodyParser = require("body-parser");
6 +const api = require("./src/api");
7 +const jwtMiddleware = require("./src/lib/jwtMiddleware");
8 +require("dotenv").config();
9 +const { SERVER_PORT, MONGO_URL } = process.env;
10 +app.use(morgan("dev"));
11 +app.use(express.json());
12 +app.use(express.urlencoded({ extended: false }));
13 +app.use(bodyParser());
14 +app.use(jwtMiddleware);
15 +
16 +app.use("/api", api);
17 +mongoose
18 + .connect(MONGO_URL, { useNewUrlParser: true, useFindAndModify: false })
19 + .then(() => {
20 + console.log("Connected to MongoDB");
21 + })
22 + .catch((e) => {
23 + console.log(e);
24 + });
25 +app.listen(SERVER_PORT, () => {
26 + console.log("Server is running on port", process.env.SERVER_PORT);
27 +});
1 +{
2 + "name": "jaksimsamil-server",
3 + "version": "1.0.0",
4 + "main": "index.js",
5 + "license": "MIT",
6 + "dependencies": {
7 + "bcrypt": "^4.0.1",
8 + "body-parser": "^1.19.0",
9 + "dotenv": "^8.2.0",
10 + "eslint-config-prettier": "^6.11.0",
11 + "express": "^4.17.1",
12 + "fs": "^0.0.1-security",
13 + "joi": "^14.3.1",
14 + "jsonwebtoken": "^8.5.1",
15 + "mongoose": "^5.9.17",
16 + "morgan": "^1.10.0",
17 + "path": "^0.12.7"
18 + },
19 + "devDependencies": {
20 + "babel-eslint": "^10.1.0",
21 + "eslint": "^7.1.0",
22 + "nodemon": "^2.0.4"
23 + },
24 + "scripts": {
25 + "start": "node src",
26 + "start:dev": "nodemon --watch src/ src/index.js"
27 + }
28 +}
1 +const Joi = require("joi");
2 +const User = require("../../models/user");
3 +/*
4 +POST /api/auth/register
5 +{
6 + username: 'userid'
7 + password: 'userpassword'
8 +}
9 +*/
10 +exports.register = async (ctx) => {
11 + const schema = Joi.object().keys({
12 + username: Joi.string().alphanum().min(3).max(20).required(),
13 + password: Joi.string().required(),
14 + });
15 + const result = Joi.validate(ctx.request.body, schema);
16 + if (result.error) {
17 + ctx.status = 400;
18 + ctx.body = result.error;
19 + return;
20 + }
21 +
22 + const { username, password } = ctx.request.body;
23 + try {
24 + const isNameExist = await User.findByUsername(username);
25 + if (isNameExist) {
26 + ctx.status = 409;
27 + return;
28 + }
29 + const user = new User({
30 + username,
31 + });
32 + await user.setPassword(password);
33 + await user.save();
34 + ctx.body = user.serialize();
35 +
36 + const token = user.generateToekn();
37 + ctx.cookies.set("acces_token", token, {
38 + //3일동안 유효
39 + maxAge: 1000 * 60 * 60 * 24 * 3,
40 + httpOnly: true,
41 + });
42 + } catch (e) {
43 + ctx.throw(500, e);
44 + }
45 +};
46 +/*
47 +POST /api/auth/login
48 +{
49 + username: 'userid'
50 + password: 'userpassword'
51 +}
52 + */
53 +exports.login = async (ctx) => {
54 + const { username, password } = ctx.request.body;
55 + if (!username || !password) {
56 + ctx.status = 401;
57 + return;
58 + }
59 + try {
60 + const user = await User.findByUsername(username);
61 + if (!user) {
62 + ctx.status = 401;
63 + return;
64 + }
65 + const isPasswordValid = await user.checkPassword(password);
66 + if (!isPasswordValid) {
67 + ctx.status = 401;
68 + return;
69 + }
70 + ctx.body = user.serialize();
71 + const token = user.generateToken();
72 + ctx.cookies.set("acces_token", token, {
73 + //7일동안 유효
74 + maxAge: 1000 * 60 * 60 * 24 * 7,
75 + httpOnly: true,
76 + });
77 + } catch (e) {
78 + ctx.throw(500, e);
79 + }
80 +};
81 +/*
82 +GET api/auth/check
83 +*/
84 +exports.check = async (ctx) => {
85 + const { user } = ctx.state;
86 + if (!user) {
87 + ctx.status = 401;
88 + return;
89 + }
90 + ctx.body = user;
91 +};
92 +/*
93 +POST /api/auth/logout
94 +*/
95 +exports.logout = async (ctx) => {
96 + ctx.cookies.set("access_token");
97 + ctx.status = 204;
98 +};
1 +const express = require("express");
2 +const router = express.Router();
3 +
4 +router.post("/login");
5 +router.get("/logout");
6 +router.post("/register");
7 +
8 +
9 +
10 +
11 +module.exports = router;
1 +const express = require("express");
2 +const router = express.Router();
3 +
4 +router.post("/");
5 +router.delete("/:id");
6 +router.get("/:id");
7 +router.get("");
8 +
9 +module.exports = router;
1 +const express = require("express");
2 +const app = express();
3 +
4 +const auth = require("./auth");
5 +const friend = require("./friend");
6 +const notify = require("./profile");
7 +const user = require("./user");
8 +const profile = require("./profile");
9 +
10 +app.use("/auth", auth);
11 +app.use("/friend", friend);
12 +app.use("/notify", notify);
13 +app.use("/user", user);
14 +app.use("/profile", profile);
15 +
16 +module.exports = app;
1 +const express = require("express");
2 +const router = express.Router();
3 +
4 +router.post("/slack");
5 +
6 +module.exports = router;
1 +const express = require("express");
2 +const router = express.Router();
3 +
4 +router.post("/solved:id");
5 +router.get("/solvednum:id");
6 +router.get("recommendps:id");
7 +
8 +module.exports = router;
1 +const express = require("express");
2 +const router = express.Router();
3 +
4 +router.post("/");
5 +router.delete("/:id");
6 +router.get("/:id");
7 +router.get("");
8 +
9 +module.exports = router;
1 +const jwt = require("jsonwebtoken");
2 +const User = require("../models/user");
3 +const jwtMiddleware = async (ctx, next) => {
4 + const token = ctx.cookies.get("access_token");
5 + if (!token) {
6 + //토큰이 없을 때
7 + return next();
8 + }
9 + try {
10 + const decoded = jwt.verify(token, process.env.JWT_TOKEN);
11 + ctx.state.user = {
12 + _id: decoded._id,
13 + username: decoded.username,
14 + };
15 + //토큰의 남은 유효 기간이 2일 이하라면 재발급
16 + if (decoded.exp - Date.now() / 1000 < 60 * 60 * 24 * 2) {
17 + const user = await User.findById(decoded._id);
18 + const token = user.generateToken();
19 + ctx.cookies.set("access_token", token, {
20 + maxAge: 1000 * 60 * 60 * 24 * 7,
21 + httpOnly: true,
22 + });
23 + }
24 + return next();
25 + } catch (e) {
26 + return next();
27 + }
28 +};
29 +
30 +module.exports = jwtMiddleware;
1 +const mongoose = require("mongoose");
2 +const bcrypt = require("bcrypt");
3 +const jwt = require("jsonwebtoken");
4 +const Schema = mongoose.Schema;
5 +
6 +const UserSchema = new Schema({
7 + username: String,
8 + hashedPassword: String,
9 +});
10 +
11 +UserSchema.methods.setPassword = async function (password) {
12 + const hash = await bcrypt.hash(password, 10);
13 + this.hashedPassword = hash;
14 +};
15 +UserSchema.methodss.checkPassword = async function (password) {
16 + const result = await bcrypt.compare(password, this.hashedPassword);
17 + return result;
18 +};
19 +UserSchema.statics.findByUsername = function (username) {
20 + return this.findOne({ username });
21 +};
22 +UserSchema.methods.serialize = function () {
23 + const data = this.toJSON();
24 + delete data.hashedPassword;
25 + return data;
26 +};
27 +UserSchema.methods.generateToken = function () {
28 + const token = jwt.sign(
29 + {
30 + _id: this.id,
31 + username: this.username,
32 + },
33 + process.env.JWT_SECRET,
34 + {
35 + expiresIn: "7d",
36 + }
37 + );
38 + return token;
39 +};
40 +const User = mongoose.model("User", UserSchema);
41 +module.exports = User;
This diff could not be displayed because it is too large.
This diff could not be displayed because it is too large.