diff --git a/api/check-user.ts b/api/check-user.ts index d2d7932..b9a46ee 100644 --- a/api/check-user.ts +++ b/api/check-user.ts @@ -1,21 +1,15 @@ import { NowRequest, NowResponse } from '@vercel/node'; -import { connect, connection } from 'mongoose'; +import { connection } from 'mongoose'; -import { verifyToken } from '../utils/auth'; - -const { - MONGO_USER, - MONGO_PASSWORD, -} = process.env; +import { connectDB } from '../utils/db'; +connectDB(); -connect(`mongodb+srv://${MONGO_USER}:${MONGO_PASSWORD}@cluster0.oj6kf.mongodb.net/proactive?retryWrites=true&w=majority`, { - useNewUrlParser: true, - useUnifiedTopology: true, -}); +import { verifyToken } from '../utils/auth'; export default async function (req: NowRequest, res: NowResponse) { try { let user = await verifyToken(req); + connection.close(); return res.send(user); } catch (error) { diff --git a/api/get-item.ts b/api/get-item.ts deleted file mode 100644 index e78942b..0000000 --- a/api/get-item.ts +++ /dev/null @@ -1,31 +0,0 @@ -import { NowRequest, NowResponse } from '@vercel/node'; -import { connect } from 'mongoose'; - -import * as models from '../models/index.js'; -import { verifyToken } from '../utils/auth.js'; - -const User = models.default.User.default; -const Item = models.default.Item.default; - -const { - MONGO_USER, - MONGO_PASSWORD, -} = process.env; - -connect(`mongodb+srv://${MONGO_USER}:${MONGO_PASSWORD}@cluster0.oj6kf.mongodb.net/proactive?retryWrites=true&w=majority`, { - useNewUrlParser: true, - useUnifiedTopology: true, -}); - -export default async function (req: NowRequest, res: NowResponse) { - const user = await verifyToken(req); - - const exampleItem = await Item.findById(req.query.id); - console.log(exampleItem); - - const item = await Item.findOne({ - _id: req.query.id, - user: user, - }); - return res.status(200).send(item); -} \ No newline at end of file diff --git a/api/get-items.ts b/api/get-items.ts index 3f82c49..0ad641d 100644 --- a/api/get-items.ts +++ b/api/get-items.ts @@ -1,16 +1,19 @@ import { NowRequest, NowResponse } from '@vercel/node'; -import { connect } from 'mongoose'; +import { connection } from 'mongoose'; -const { - MONGO_USER, - MONGO_PASSWORD, -} = process.env; +import { connectDB } from '../utils/db'; +connectDB(); -connect(`mongodb+srv://${MONGO_USER}:${MONGO_PASSWORD}@cluster0.oj6kf.mongodb.net/proactive?retryWrites=true&w=majority`, { - useNewUrlParser: true, - useUnifiedTopology: true, -}); +import { Item } from '../models'; +import { verifyToken } from '../utils/auth'; export default async function (req: NowRequest, res: NowResponse) { - return res.status(200).send('Hello'); + let user = await verifyToken(req); + + let items = await Item.find({ + user, + }); + + connection.close(); + return res.status(200).send(items); } \ No newline at end of file diff --git a/api/login.ts b/api/login.ts index a91d376..2cf11d4 100644 --- a/api/login.ts +++ b/api/login.ts @@ -1,25 +1,16 @@ import { NowRequest, NowResponse } from '@vercel/node'; -import { connect, connection } from 'mongoose'; +import { connection } from 'mongoose'; -import * as models from '../models/index.js'; -import { login } from '../utils/auth.js'; +import { connectDB } from '../utils/db'; +connectDB(); -const User = models.default.User.default; - -const { - MONGO_USER, - MONGO_PASSWORD, -} = process.env; - -connect(`mongodb+srv://${MONGO_USER}:${MONGO_PASSWORD}@cluster0.oj6kf.mongodb.net/proactive?retryWrites=true&w=majority`, { - useNewUrlParser: true, - useUnifiedTopology: true, -}); +import { User } from '../models'; +import { login } from '../utils/auth'; export default async function (req: NowRequest, res: NowResponse) { try { const existingUser = await User.findOne({ - username: req.body.username + username: req.body.username, }); if (!existingUser || !await existingUser.comparePassword(req.body.password)) { diff --git a/api/register.ts b/api/register.ts new file mode 100644 index 0000000..c66343c --- /dev/null +++ b/api/register.ts @@ -0,0 +1,32 @@ +import { NowRequest, NowResponse } from '@vercel/node'; +import { connection } from 'mongoose'; + +import { connectDB } from '../utils/db'; +connectDB(); + +import { User } from '../models'; +import { register } from '../utils/auth'; + +export default async function (req: NowRequest, res: NowResponse) { + try { + const existingUser = await User.findOne({ + username: req.body.username + }); + + if (existingUser) { + return res.status(400).send('Username taken'); + } + + let user = new User({ + username: req.body.username, + password: req.body.password, + }); + + await user.save(); + + return await register(user, res, connection); + } catch (error) { + connection.close(); + return res.status(502).send(error); + } +} \ No newline at end of file diff --git a/api/sign-up.ts b/api/sign-up.ts deleted file mode 100644 index 1e0438e..0000000 --- a/api/sign-up.ts +++ /dev/null @@ -1,41 +0,0 @@ -import { NowRequest, NowResponse } from '@vercel/node'; -import { connect, connection } from 'mongoose'; - -import * as models from '../models/index.js'; -import { login } from '../utils/auth.js'; - -const User = models.default.User.default; - -const { - MONGO_USER, - MONGO_PASSWORD, -} = process.env; - -connect(`mongodb+srv://${MONGO_USER}:${MONGO_PASSWORD}@cluster0.oj6kf.mongodb.net/proactive?retryWrites=true&w=majority`, { - useNewUrlParser: true, - useUnifiedTopology: true, -}); - -export default async function (req: NowRequest, res: NowResponse) { - try { - const existingUser = await User.findOne({ - username: req.body.username - }); - - if (existingUser) { - return res.status(400).send('Username taken...'); - } - - const user = new User({ - username: req.body.username, - password: req.body.password, - name: req.body.name, - }); - await user.save(); - - return await login(user, res, connection); - } catch (error) { - connection.close(); - return res.status(502).send(error); - } -} \ No newline at end of file diff --git a/models/Item.js b/models/Item.js index fdc124c..c3203ff 100644 --- a/models/Item.js +++ b/models/Item.js @@ -46,5 +46,4 @@ const schema = new mongoose.Schema({ }, }); -const Item = mongoose.model('Item', schema); -export default Item; \ No newline at end of file +export const Item = mongoose.model('Item', schema); diff --git a/models/User.js b/models/User.js index 98001db..2fbadb5 100644 --- a/models/User.js +++ b/models/User.js @@ -4,7 +4,7 @@ const bcrypt = require('bcrypt'); const { removeOldTokens } = require('../utils/auth'); const { - SERVER_SECRET + SALT_ROUNDS, } = process.env; const schema = new mongoose.Schema({ @@ -16,10 +16,6 @@ const schema = new mongoose.Schema({ type: String, required: true, }, - name: { - type: String, - required: true, - }, tokens: [], }); @@ -29,8 +25,7 @@ schema.pre('save', async function(next) { } try { - const salt = await bcrypt.genSalt(SERVER_SECRET); - const hash = await bcrypt.hash(this.password, salt); + const hash = await bcrypt.hashSync(this.password, parseInt(SALT_ROUNDS)); this.password = hash; next(); @@ -68,21 +63,4 @@ schema.methods.removeOldTokens = function() { this.tokens = removeOldTokens(this.tokens); } -// // middleware to validate user account -// schema.statics.verify = async function(req, res, next) { -// // look up user account -// const user = await User.findOne({ -// _id: req.user_id -// }); -// if (!user || !user.tokens.includes(req.token)) -// return res.clearCookie('token').status(403).send({ -// error: "Invalid user account." -// }); - -// req.user = user; - -// next(); -// } - -const User = mongoose.model('User', schema); -export default User; \ No newline at end of file +export const User = mongoose.model('User', schema); diff --git a/models/index.js b/models/index.js deleted file mode 100644 index 9667908..0000000 --- a/models/index.js +++ /dev/null @@ -1,7 +0,0 @@ -const User = require('./User'); -const Item = require('./Item'); - -export default { - User: User, - Item: Item, -}; diff --git a/models/index.ts b/models/index.ts new file mode 100644 index 0000000..664f0e9 --- /dev/null +++ b/models/index.ts @@ -0,0 +1,2 @@ +export { User } from './User'; +export { Item } from './Item'; diff --git a/public/favicon.ico b/public/favicon.ico index df36fcf..98c2535 100644 Binary files a/public/favicon.ico and b/public/favicon.ico differ diff --git a/public/index.html b/public/index.html index bc51465..da8324f 100644 --- a/public/index.html +++ b/public/index.html @@ -5,13 +5,13 @@ - <%= htmlWebpackPlugin.options.title %> + Proactive
diff --git a/src/App.vue b/src/App.vue index fdb03eb..7e20ba7 100644 --- a/src/App.vue +++ b/src/App.vue @@ -1,9 +1,13 @@ + + \ No newline at end of file diff --git a/src/components/Login.vue b/src/components/Login.vue index 2ccca29..04d1292 100644 --- a/src/components/Login.vue +++ b/src/components/Login.vue @@ -1,11 +1,76 @@ \ No newline at end of file + + + \ No newline at end of file diff --git a/src/components/NavButton.vue b/src/components/NavButton.vue new file mode 100644 index 0000000..da85748 --- /dev/null +++ b/src/components/NavButton.vue @@ -0,0 +1,42 @@ + + + + + \ No newline at end of file diff --git a/src/components/Register.vue b/src/components/Register.vue index ea38eb5..a06ae6e 100644 --- a/src/components/Register.vue +++ b/src/components/Register.vue @@ -1,11 +1,76 @@ \ No newline at end of file + + + \ No newline at end of file diff --git a/src/main.js b/src/main.js index 6b9c034..a62e523 100644 --- a/src/main.js +++ b/src/main.js @@ -1,14 +1,16 @@ -import Vue from 'vue' -import App from './App.vue' -import router from './router' -import store from './store' +import Vue from 'vue'; + +import router from './router'; +import store from './store'; import vuetify from './plugins/vuetify'; -Vue.config.productionTip = false +import App from './App.vue'; + +Vue.config.productionTip = false; new Vue({ router, store, vuetify, render: h => h(App) -}).$mount('#app') +}).$mount('#app'); diff --git a/src/plugins/vuetify.js b/src/plugins/vuetify.js index ec46adb..bc411ef 100644 --- a/src/plugins/vuetify.js +++ b/src/plugins/vuetify.js @@ -4,4 +4,21 @@ import Vuetify from 'vuetify/lib'; Vue.use(Vuetify); export default new Vuetify({ + theme: { + dark: false, + themes: { + light: { + primary: '#186FC0', + secondary: '#b0bec5', + accent: '#8c9eff', + error: '#b71c1c', + }, + dark: { + primary: '#186FC0', + secondary: '#b0bec5', + accent: '#8c9eff', + error: '#b71c1c', + }, + }, + }, }); diff --git a/src/store/modules/items.js b/src/store/modules/items.js index 4e49f0d..246f607 100644 --- a/src/store/modules/items.js +++ b/src/store/modules/items.js @@ -1,23 +1,25 @@ const state = { items: [], - item: null, - deleted: false, + id: null, }; const getters = { - + item: (state) => { + for (let i = 0; i < state.items.length; i += 1) { + if (state.items[i]._id === state.id) { + return state.items[i]; + } + } + return null; + } }; const mutations = { setItems(state, items) { - for (var i = 0; i < items.length; i++) - { - items[i].menu = false; - } state.items = items; }, - setItem(state, item) { - state.item = item; + setID(state, id) { + state.id = id; }, setDeleted(state, deleted) { state.deleted = deleted; diff --git a/src/store/modules/user.js b/src/store/modules/user.js index a2462c2..21de53f 100644 --- a/src/store/modules/user.js +++ b/src/store/modules/user.js @@ -1,25 +1,38 @@ +import api from '@/api'; + const state = { user: null, - loginRegister: -1, }; const getters = { - + user: (state) => state.user, }; const mutations = { setUser(state, user) { state.user = user; }, - setLoginOrRegister(state) { - if (state.loginRegister == -1) {state.loginRegister = 1;} - else if (state.loginRegister == 1) {state.loginRegister = 0;} - else {state.loginRegister = 1;} - }, }; const actions = { + async getUser() { + + }, + async login({ commit }, payload) { + let user = await api.auth.login(payload); + if (user) { + commit('setUser', user); + } + }, + async register({ commit }, payload) { + let user = await api.auth.register(payload); + if (user) { + commit('setUser', user); + } + }, + async logout() { + }, }; const module = { diff --git a/src/views/Home.vue b/src/views/Home.vue index 8814fa7..f1ffff4 100644 --- a/src/views/Home.vue +++ b/src/views/Home.vue @@ -1,33 +1,31 @@ \ No newline at end of file diff --git a/utils/auth.ts b/utils/auth.ts index ddd27c1..d590f8a 100644 --- a/utils/auth.ts +++ b/utils/auth.ts @@ -1,14 +1,11 @@ import { NowRequest } from '@vercel/node'; -import * as jwt from 'jsonwebtoken'; +import * as jsonwebtoken from 'jsonwebtoken'; -import * as models from '../models/index.js'; +import { User } from '../models'; -const User = models.default.User.default; - -// Generate a token export const generateToken = (data: object, expires: any) => { - return jwt.sign(data, process.env.SERVER_SECRET, { - expiresIn: expires + return jsonwebtoken.sign(data, process.env.SERVER_SECRET, { + expiresIn: expires, }); }; @@ -18,7 +15,7 @@ export const verifyToken = async (req: NowRequest) => { return null; } try { - const decoded = jwt.verify(token, process.env.SERVER_SECRET); + const decoded = jsonwebtoken.verify(token, process.env.SERVER_SECRET); if ('id' in decoded) { let existingUser = await User.findOne({ _id: decoded.id, @@ -35,7 +32,7 @@ export const verifyToken = async (req: NowRequest) => { export const removeOldTokens = (tokens: Array) => { return tokens.filter(token => { try { - jwt.verify(token, process.env.SERVER_SECRET); + jsonwebtoken.verify(token, process.env.SERVER_SECRET); return true; } catch (error) { return false; @@ -56,3 +53,16 @@ export const login = async (user, res, connection) => { connection.close(); return res.status(200).send(user); } + +export const register = async (user, res, connection) => { + let token = generateToken({ + id: user._id, + }, "24h"); + + user.addToken(token); + await user.save(); + + res.setHeader('Set-Cookie', [`proactive-token=${token}; SameSite=Strict`]); + connection.close(); + return res.status(200).send(user); +} diff --git a/utils/db.ts b/utils/db.ts new file mode 100644 index 0000000..831b326 --- /dev/null +++ b/utils/db.ts @@ -0,0 +1,13 @@ +import { connect } from 'mongoose'; + +const { + MONGO_USER, + MONGO_PASSWORD, +} = process.env; + +export const connectDB = () => { + connect(`mongodb+srv://${MONGO_USER}:${MONGO_PASSWORD}@cluster0.oj6kf.mongodb.net/proactive?retryWrites=true&w=majority`, { + useNewUrlParser: true, + useUnifiedTopology: true, + }); +};