More authentication
This commit is contained in:
parent
78c35b2ac3
commit
409b8af6a3
1
sql/users/details.sql
Normal file
1
sql/users/details.sql
Normal file
@ -0,0 +1 @@
|
||||
SELECT email FROM users WHERE id=$1;
|
13
src/api.ts
13
src/api.ts
@ -14,7 +14,7 @@
|
||||
// along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
import { db } from "@kredens/db";
|
||||
import { ApolloServer, gql } from "apollo-server-express";
|
||||
import { ApolloServer, AuthenticationError, gql } from "apollo-server-express";
|
||||
import { Kind } from "graphql/language";
|
||||
import { GraphQLScalarType, GraphQLScalarTypeConfig } from "graphql/type";
|
||||
import { DateTime } from "luxon";
|
||||
@ -67,6 +67,17 @@ const resolvers = {
|
||||
|
||||
export function server() {
|
||||
return new ApolloServer({
|
||||
context: async req => {
|
||||
const user = req.req.user;
|
||||
|
||||
if (!user) {
|
||||
throw new AuthenticationError("you must be logged in");
|
||||
}
|
||||
|
||||
return {
|
||||
user
|
||||
};
|
||||
},
|
||||
resolvers,
|
||||
typeDefs
|
||||
});
|
||||
|
40
src/auth.ts
Normal file
40
src/auth.ts
Normal file
@ -0,0 +1,40 @@
|
||||
// Copyright (C) 2019 ModZero <modzero@modzero.xyz>
|
||||
//
|
||||
// This program is free software: you can redistribute it and/or modify
|
||||
// it under the terms of the GNU Affero General Public License as
|
||||
// published by the Free Software Foundation, either version 3 of the
|
||||
// License, or (at your option) any later version.
|
||||
//
|
||||
// This program is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU Affero General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU Affero General Public License
|
||||
// along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
import { db } from "@kredens/db";
|
||||
import { User } from "@kredens/db/models";
|
||||
import express from "express";
|
||||
import { None } from "monet";
|
||||
|
||||
export const getUser = async (req: express.Request) =>
|
||||
req.session.userID ? db.users.details(req.session.userID) : None<User>();
|
||||
|
||||
export const authMiddleware: () => express.Handler = () => async (
|
||||
req,
|
||||
res,
|
||||
next
|
||||
) => {
|
||||
if (req.session.userID) {
|
||||
const user = await getUser(req);
|
||||
|
||||
if (user.isSome()) {
|
||||
req.user = user.some();
|
||||
} else {
|
||||
delete req.session.userID;
|
||||
}
|
||||
}
|
||||
|
||||
next();
|
||||
};
|
24
src/custom.d.ts
vendored
Normal file
24
src/custom.d.ts
vendored
Normal file
@ -0,0 +1,24 @@
|
||||
// Copyright (C) 2019 ModZero <modzero@modzero.xyz>
|
||||
//
|
||||
// This program is free software: you can redistribute it and/or modify
|
||||
// it under the terms of the GNU Affero General Public License as
|
||||
// published by the Free Software Foundation, either version 3 of the
|
||||
// License, or (at your option) any later version.
|
||||
//
|
||||
// This program is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU Affero General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU Affero General Public License
|
||||
// along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
import { User } from "@kredens/db/models";
|
||||
|
||||
declare global {
|
||||
namespace Express {
|
||||
interface Request {
|
||||
user?: User;
|
||||
}
|
||||
}
|
||||
}
|
@ -18,7 +18,7 @@ import {
|
||||
MigrationRepository,
|
||||
UserRepository
|
||||
} from "@kredens/db/repos";
|
||||
import monitor from "pg-monitor";
|
||||
|
||||
import pgPromise, { IDatabase, IInitOptions } from "pg-promise";
|
||||
|
||||
type ExtendedProtocol = IDatabase<Extensions> & Extensions;
|
||||
@ -31,6 +31,11 @@ const initOptions: IInitOptions<Extensions> = {
|
||||
};
|
||||
|
||||
const pgp: pgPromise.IMain = pgPromise(initOptions);
|
||||
monitor.attach(initOptions);
|
||||
|
||||
if (process.env.NODE_ENV !== "production") {
|
||||
// tslint:disable-next-line:no-implicit-dependencies
|
||||
import("pg-monitor").then(monitor => monitor.attach(initOptions));
|
||||
}
|
||||
|
||||
const db: ExtendedProtocol = pgp(process.env.PG_CONNECTION_STRING);
|
||||
export { db, pgp };
|
||||
|
@ -20,3 +20,8 @@ export interface Migration {
|
||||
name: string;
|
||||
applied_at: DateTime;
|
||||
}
|
||||
|
||||
export interface User {
|
||||
id: number;
|
||||
email: string;
|
||||
}
|
||||
|
@ -17,6 +17,7 @@ import { users as sql } from "@kredens/db/sql";
|
||||
import argon2 from "argon2";
|
||||
import { Maybe, None, Some } from "monet";
|
||||
import { IDatabase, IMain } from "pg-promise";
|
||||
import { User } from "@kredens/db/models";
|
||||
|
||||
export class UserRepository {
|
||||
private db: IDatabase<any>;
|
||||
@ -47,4 +48,12 @@ export class UserRepository {
|
||||
.one(sql.create, [email, encryptedPassword])
|
||||
.then((user: { id: number }) => +user.id);
|
||||
}
|
||||
|
||||
public async details(id: number): Promise<Maybe<User>> {
|
||||
return this.db
|
||||
.oneOrNone(sql.details, [id])
|
||||
.then((user: { email: string }) =>
|
||||
user !== null ? Some({ ...user, id }) : None()
|
||||
);
|
||||
}
|
||||
}
|
||||
|
@ -37,6 +37,7 @@ const migrations = {
|
||||
|
||||
const users = {
|
||||
create: sql("users/create.sql"),
|
||||
details: sql("users/details.sql"),
|
||||
login: sql("users/login.sql")
|
||||
};
|
||||
|
||||
|
@ -1,3 +1,18 @@
|
||||
// Copyright (C) 2019 ModZero <modzero@modzero.xyz>
|
||||
//
|
||||
// This program is free software: you can redistribute it and/or modify
|
||||
// it under the terms of the GNU Affero General Public License as
|
||||
// published by the Free Software Foundation, either version 3 of the
|
||||
// License, or (at your option) any later version.
|
||||
//
|
||||
// This program is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU Affero General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU Affero General Public License
|
||||
// along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
import Vue from "vue";
|
||||
import App from "./App.vue";
|
||||
|
||||
|
15
src/frontend/vue-shim.d.ts
vendored
15
src/frontend/vue-shim.d.ts
vendored
@ -1,3 +1,18 @@
|
||||
// Copyright (C) 2019 ModZero <modzero@modzero.xyz>
|
||||
//
|
||||
// This program is free software: you can redistribute it and/or modify
|
||||
// it under the terms of the GNU Affero General Public License as
|
||||
// published by the Free Software Foundation, either version 3 of the
|
||||
// License, or (at your option) any later version.
|
||||
//
|
||||
// This program is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU Affero General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU Affero General Public License
|
||||
// along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
declare module "*.vue" {
|
||||
import Vue from "vue";
|
||||
export default Vue;
|
||||
|
51
src/index.ts
51
src/index.ts
@ -14,6 +14,7 @@
|
||||
// along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
import { server as graphqlServer } from "@kredens/api";
|
||||
import { authMiddleware } from "@kredens/auth";
|
||||
import { db } from "@kredens/db";
|
||||
import logger from "@kredens/logger";
|
||||
import indexRouter from "@kredens/routes/";
|
||||
@ -25,18 +26,33 @@ import pinoExpress from "express-pino-logger";
|
||||
import session, { SessionOptions } from "express-session";
|
||||
import helmet from "helmet";
|
||||
import createHttpError from "http-errors";
|
||||
|
||||
async function main() {
|
||||
await db.tx(async t => {
|
||||
await t.migrations.create();
|
||||
await t.migrations.apply();
|
||||
});
|
||||
|
||||
const server = graphqlServer();
|
||||
const app = express();
|
||||
const expressPino = pinoExpress({ logger });
|
||||
app.use(helmet());
|
||||
app.use(expressPino);
|
||||
|
||||
if (app.settings.env === "development") {
|
||||
const webpack = await import("webpack").then(p => p.default); // tslint:disable-line:no-implicit-dependencies
|
||||
// tslint:disable-next-line:no-implicit-dependencies
|
||||
const webpackDevMiddleware = await import("webpack-dev-middleware").then(
|
||||
p => p.default
|
||||
);
|
||||
const config = await import("../webpack.config").then(p => p.default);
|
||||
|
||||
const compiler = webpack(config);
|
||||
app.use(
|
||||
webpackDevMiddleware(compiler, {
|
||||
publicPath: "/assets/"
|
||||
})
|
||||
);
|
||||
}
|
||||
|
||||
app.use(express.json());
|
||||
app.use(express.urlencoded({ extended: false }));
|
||||
app.use(cookieParser());
|
||||
@ -52,25 +68,26 @@ async function main() {
|
||||
}
|
||||
app.use(session(sessionOptions));
|
||||
app.use("/bootstrap", bootstrapRouter);
|
||||
|
||||
app.use(authMiddleware());
|
||||
const apiServer = graphqlServer();
|
||||
apiServer.applyMiddleware({
|
||||
app,
|
||||
path: "/graphql"
|
||||
});
|
||||
|
||||
app.use(csrf());
|
||||
|
||||
if (app.settings.env === "development") {
|
||||
const webpack = require("webpack"); // tslint:disable-line:no-implicit-dependencies
|
||||
const webpackDevMiddleware = require("webpack-dev-middleware"); // tslint:disable-line:no-implicit-dependencies
|
||||
const config = require("../webpack.config").default;
|
||||
|
||||
const compiler = webpack(config);
|
||||
app.use(
|
||||
webpackDevMiddleware(compiler, {
|
||||
publicPath: "/assets/"
|
||||
})
|
||||
);
|
||||
}
|
||||
|
||||
app.set("view engine", "pug");
|
||||
|
||||
app.use(async (req, res, next) => {
|
||||
res.locals.csrfToken = req.csrfToken();
|
||||
res.locals.user = req.user;
|
||||
|
||||
next();
|
||||
});
|
||||
|
||||
app.use("/", indexRouter);
|
||||
server.applyMiddleware({ app, path: "/graphql" });
|
||||
|
||||
app.use((req, res, next) => {
|
||||
next(createHttpError(404));
|
||||
@ -79,7 +96,7 @@ async function main() {
|
||||
const port = 3000;
|
||||
app.listen(port, () =>
|
||||
logger.info("Example app listening", {
|
||||
uri: `http://localhost:${port}${server.graphqlPath}`
|
||||
uri: `http://localhost:${port}${apiServer.graphqlPath}`
|
||||
})
|
||||
);
|
||||
}
|
||||
|
@ -19,17 +19,16 @@ import express from "express";
|
||||
const router = express.Router();
|
||||
|
||||
router.get("/", async (req, res, next) => {
|
||||
res.render("login", {
|
||||
csrfToken: req.csrfToken()
|
||||
});
|
||||
res.render("login");
|
||||
});
|
||||
|
||||
router.post("/", async (req, res, next) => {
|
||||
const userID = await db.users.login(req.body.email, req.body.password);
|
||||
if (userID.isSome()) {
|
||||
res.send(`Hi, ${userID.some()}`);
|
||||
req.session.userID = userID.some();
|
||||
res.redirect("/");
|
||||
} else {
|
||||
res.send(`Go away.`);
|
||||
res.redirect("/auth/");
|
||||
}
|
||||
});
|
||||
|
||||
|
@ -1,3 +1,18 @@
|
||||
// Copyright (C) 2019 ModZero <modzero@modzero.xyz>
|
||||
//
|
||||
// This program is free software: you can redistribute it and/or modify
|
||||
// it under the terms of the GNU Affero General Public License as
|
||||
// published by the Free Software Foundation, either version 3 of the
|
||||
// License, or (at your option) any later version.
|
||||
//
|
||||
// This program is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU Affero General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU Affero General Public License
|
||||
// along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
import { box, unbox } from "@kredens/crypto";
|
||||
import { db } from "@kredens/db";
|
||||
import express from "express";
|
||||
|
@ -1,3 +1,18 @@
|
||||
// Copyright (C) 2019 ModZero <modzero@modzero.xyz>
|
||||
//
|
||||
// This program is free software: you can redistribute it and/or modify
|
||||
// it under the terms of the GNU Affero General Public License as
|
||||
// published by the Free Software Foundation, either version 3 of the
|
||||
// License, or (at your option) any later version.
|
||||
//
|
||||
// This program is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU Affero General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU Affero General Public License
|
||||
// along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
import express from "express";
|
||||
import authRouter from "./auth";
|
||||
import homeRouter from "./home";
|
||||
|
@ -11,7 +11,7 @@
|
||||
"*"
|
||||
]
|
||||
},
|
||||
"esModuleInterop": true,
|
||||
"esModuleInterop": true
|
||||
},
|
||||
"include": [
|
||||
"./src/**/*"
|
||||
|
@ -1,8 +1,15 @@
|
||||
html
|
||||
head
|
||||
title= title
|
||||
body
|
||||
h1= message
|
||||
extends layout.pug
|
||||
|
||||
block content
|
||||
if user
|
||||
p.auth Hi, #{ user.email }
|
||||
else
|
||||
p.auth
|
||||
| Who are you?
|
||||
|
|
||||
a(href="/auth") Login you coward.
|
||||
div#body
|
||||
p I am a placeholder
|
||||
|
||||
block scripts
|
||||
script(src="/assets/main.bundle.js")
|
@ -3,3 +3,4 @@ html
|
||||
title Kredens - #{title}
|
||||
body
|
||||
block content
|
||||
block scripts
|
Loading…
x
Reference in New Issue
Block a user