Skip to content
Snippets Groups Projects
Commit 5211d77d authored by Jussi Mäki-Ikola's avatar Jussi Mäki-Ikola
Browse files

initial

parents
No related branches found
No related tags found
No related merge requests found
# Node.js
node_modules
\ No newline at end of file
# Editor directories and files
.vscode
# Nuxt
.nuxt
# Node.js
node_modules
# Initial readme
# Node.js
node_modules
\ No newline at end of file
module.exports = {
parser: "@typescript-eslint/parser",
extends: [
"plugin:@typescript-eslint/recommended",
"prettier/@typescript-eslint",
"plugin:prettier/recommended"
],
parserOptions: {
ecmaVersion: 2018,
sourceType: "module"
}
};
\ No newline at end of file
# Editor directories and files
.vscode
# Node.js
node_modules
module.exports = {
semi: true,
trailingComma: 'all',
singleQuote: true,
printWidth: 120,
tabWidth: 2,
};
FROM node:10.16.3-alpine
RUN apk add --no-cache bash
RUN apk add nano
WORKDIR /usr/src/app
COPY package.json /usr/src/app/
COPY package-lock.json /usr/src/app/
RUN npm install
COPY . /usr/src/app
EXPOSE 3000
CMD ["npm", "run", "dev"]
\ No newline at end of file
"use strict";
var __importDefault = (this && this.__importDefault) || function (mod) {
return (mod && mod.__esModule) ? mod : { "default": mod };
};
Object.defineProperty(exports, "__esModule", { value: true });
const express_1 = __importDefault(require("express"));
const app = express_1.default();
const port = 3000;
app.get('/', (req, res) => {
res.send('The sedulous hyena ate the antelope!');
});
app.listen(port, err => {
if (err) {
return console.error(err);
}
return console.log(`server is listening on ${port}`);
});
//# sourceMappingURL=app.js.map
\ No newline at end of file
{"version":3,"file":"app.js","sourceRoot":"","sources":["../src/app.ts"],"names":[],"mappings":";;;;;AAAA,sDAA8B;AAE9B,MAAM,GAAG,GAAG,iBAAO,EAAE,CAAC;AACtB,MAAM,IAAI,GAAG,IAAI,CAAC;AAClB,GAAG,CAAC,GAAG,CAAC,GAAG,EAAE,CAAC,GAAG,EAAE,GAAG,EAAE,EAAE;IACxB,GAAG,CAAC,IAAI,CAAC,sCAAsC,CAAC,CAAC;AACnD,CAAC,CAAC,CAAC;AACH,GAAG,CAAC,MAAM,CAAC,IAAI,EAAE,GAAG,CAAC,EAAE;IACrB,IAAI,GAAG,EAAE;QACP,OAAO,OAAO,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC;KAC3B;IACD,OAAO,OAAO,CAAC,GAAG,CAAC,0BAA0B,IAAI,EAAE,CAAC,CAAC;AACvD,CAAC,CAAC,CAAC"}
\ No newline at end of file
This diff is collapsed.
{
"name": "api",
"version": "1.0.0",
"description": "",
"main": "dist/app.js",
"scripts": {
"start": "tsc && node dist/app.js",
"dev": "nodemon -w ./src/*.ts -e ts-node ./src/app.ts",
"test": "echo \"Error: no test specified\" && exit 1"
},
"keywords": [],
"author": "",
"license": "ISC",
"devDependencies": {
"@types/express": "^4.17.3",
"@typescript-eslint/eslint-plugin": "^2.24.0",
"@typescript-eslint/parser": "^2.24.0",
"eslint": "^6.8.0",
"eslint-config-prettier": "^6.10.0",
"eslint-plugin-prettier": "^3.1.2",
"nodemon": "^2.0.2",
"prettier": "^1.19.1",
"ts-node": "^8.7.0",
"typescript": "^3.8.3"
},
"dependencies": {
"express": "^4.17.1",
"postgraphile": "^4.6.0"
}
}
import express from 'express';
import postgraphile from 'postgraphile';
const PORT = process.env.PORT;
const DB_HOST = process.env.DB_HOST;
const JWT_SECRET = 'my_super_secret_secret';
const DB_PORT = '5432';
const DB_NAME = 'testdb';
const DB_USER = 'graph_editor_postgraphile';
const DB_PASS = 'graph_editor_postgraphile_pass';
const DB_SCHEMA = 'graph_editor';
const CONNECTION_STRING = `postgres://${DB_USER}:${DB_PASS}@${DB_HOST}:${DB_PORT}/${DB_NAME}`;
const app = express();
const postgraphileOptions = {
jwtPgTypeIdentifier: `${DB_SCHEMA}.auth_token`,
jwtSecret: JWT_SECRET,
graphqlRoute: '/graphql',
subscriptions: true,
watchPg: false,
dynamicJson: true,
setofFunctionsContainNulls: false,
ignoreRBAC: false,
ignoreIndexes: false,
showErrorStack: "json",
extendedErrors: ["hint", "detail", "errcode"],
// exportGqlSchemaPath: "schema.graphql",
pgDefaultRole: 'graph_editor_anonymous',
graphiql: true,
enhanceGraphiql: true,
allowExplain(req) {
// TODO: customise condition!
return true;
},
enableQueryBatching: true,
legacyRelations: "omit",
// pgSettings(req) {
// /* TODO */
// },
};
app.use(
postgraphile(
CONNECTION_STRING,
DB_SCHEMA,
postgraphileOptions as any,
)
);
app.listen(PORT, err => {
if (err) {
return console.error(err);
}
return console.log(`
-------------------------------
server is listening on ${PORT}
-------------------------------
`);
});
{
"compilerOptions": {
"module": "commonjs",
"esModuleInterop": true,
"target": "es6",
"moduleResolution": "node",
"sourceMap": true,
"outDir": "dist"
},
"lib": ["es2015"]
}
\ No newline at end of file
FROM postgres:12.2-alpine
COPY ./data/100_init.sql /
COPY ./scripts/init.sh /docker-entrypoint-initdb.d
EXPOSE 5432
BEGIN;
CREATE SCHEMA graph_editor;
CREATE SCHEMA graph_editor_private;
CREATE ROLE graph_editor_postgraphile LOGIN PASSWORD 'graph_editor_postgraphile_pass';
CREATE ROLE graph_editor_anonymous;
CREATE ROLE graph_editor_person;
GRANT graph_editor_anonymous TO graph_editor_postgraphile;
GRANT graph_editor_person TO graph_editor_postgraphile;
GRANT graph_editor_postgraphile TO testuser;
GRANT USAGE ON SCHEMA graph_editor TO graph_editor_postgraphile;
GRANT USAGE ON SCHEMA graph_editor TO graph_editor_anonymous;
GRANT USAGE ON SCHEMA graph_editor TO graph_editor_person;
--GRANT ALL PRIVILEGES ON ALL TABLES IN SCHEMA graph_editor TO graph_editor_postgraphile;
ALTER DEFAULT PRIVILEGES REVOKE EXECUTE ON FUNCTIONS FROM PUBLIC;
CREATE OR REPLACE FUNCTION trigger_set_timestamp()
RETURNS TRIGGER AS $$
BEGIN
NEW.updated_at = NOW();
RETURN NEW;
END;
$$ LANGUAGE plpgsql;
CREATE TABLE graph_editor.person (
id serial PRIMARY KEY,
email text NOT NULL UNIQUE CHECK(email ~* '^.+@.+\..+$'),
created_at timestamp DEFAULT NOW() NOT NULL,
updated_at timestamp DEFAULT NOW() NOT NULL
);
ALTER TABLE graph_editor.person ENABLE ROW LEVEL SECURITY;
ALTER SEQUENCE graph_editor.person_id_seq RESTART WITH 111;
CREATE TRIGGER set_timestamp BEFORE UPDATE ON graph_editor.person
FOR EACH ROW EXECUTE PROCEDURE trigger_set_timestamp();
GRANT USAGE, SELECT ON SEQUENCE graph_editor.person_id_seq TO graph_editor_person;
GRANT SELECT, UPDATE(email) ON TABLE graph_editor.person TO graph_editor_person;
CREATE POLICY graph_editor_person_all_access_to_person
ON graph_editor.person
FOR ALL
TO graph_editor_person
USING (id = current_setting('jwt.claims.person_id')::int);
CREATE TABLE graph_editor.graph (
id serial PRIMARY KEY,
person_id integer REFERENCES graph_editor.person(id) ON DELETE CASCADE NOT NULL,
data JSONB DEFAULT '{}' NOT NULL,
updated_at timestamp DEFAULT NOW() NOT NULL,
created_at timestamp DEFAULT NOW() NOT NULL
);
ALTER TABLE graph_editor.graph ENABLE ROW LEVEL SECURITY;
ALTER SEQUENCE graph_editor.graph_id_seq RESTART WITH 111;
CREATE TRIGGER set_timestamp BEFORE UPDATE ON graph_editor.graph
FOR EACH ROW EXECUTE PROCEDURE trigger_set_timestamp();
GRANT USAGE, SELECT ON SEQUENCE graph_editor.graph_id_seq TO graph_editor_person;
GRANT SELECT, INSERT(person_id, data), UPDATE(data), DELETE ON TABLE graph_editor.graph TO graph_editor_person;
CREATE POLICY graph_editor_person_all_access_to_graph
ON graph_editor.graph
FOR ALL
TO graph_editor_person
USING (person_id = current_setting('jwt.claims.person_id')::int);
CREATE TABLE graph_editor_private.person_account (
person_id integer REFERENCES graph_editor.person(id) ON DELETE CASCADE NOT NULL,
password_hash text NOT NULL,
created_at timestamp DEFAULT NOW() NOT NULL,
updated_at timestamp DEFAULT NOW() NOT NULL,
UNIQUE(person_id)
);
ALTER TABLE graph_editor.person ENABLE ROW LEVEL SECURITY;
CREATE TRIGGER set_timestamp BEFORE UPDATE ON graph_editor_private.person_account
FOR EACH ROW EXECUTE PROCEDURE trigger_set_timestamp();
CREATE TYPE graph_editor.auth_token as (
role text,
person_id integer,
exp bigint
);
CREATE FUNCTION graph_editor.authenticate(
email text,
password text
) RETURNS graph_editor.auth_token AS $$
DECLARE
account graph_editor_private.person_account;
BEGIN
SELECT a.* INTO account
FROM graph_editor_private.person_account a, graph_editor.person p
WHERE p.email = $1 AND a.person_id = p.id;
IF account.password_hash = crypt($2, account.password_hash) THEN
RETURN (
'graph_editor_person',
account.person_id,
EXTRACT(epoch FROM (NOW() + interval '2 days'))
)::graph_editor.auth_token;
ELSE
RETURN NULL;
END IF;
END;
$$ language plpgsql strict security definer;
GRANT EXECUTE ON FUNCTION graph_editor.authenticate(text, text) TO graph_editor_anonymous;
CREATE FUNCTION graph_editor.register_person(
email text,
password text
) RETURNS graph_editor.auth_token as $$
DECLARE
person graph_editor.person;
BEGIN
INSERT INTO graph_editor.person(email)
VALUES ($1)
RETURNING * INTO person;
INSERT INTO graph_editor_private.person_account (person_id, password_hash)
VALUES (person.id, crypt(password, gen_salt('bf')));
RETURN (
'graph_editor_person',
person.id,
EXTRACT(epoch FROM (NOW() + interval '2 days'))
)::graph_editor.auth_token;
END;
$$ language plpgsql strict security definer;
GRANT EXECUTE ON FUNCTION graph_editor.register_person(text, text) TO graph_editor_anonymous;
CREATE FUNCTION graph_editor.remove_person(
email text
) RETURNS BOOLEAN AS $$
DECLARE
person_id_from_jwt integer := current_setting('jwt.claims.person_id')::int;
person graph_editor.person;
BEGIN
SELECT p.* INTO person FROM graph_editor.person p WHERE p.email = $1;
IF (person.id != person_id_from_jwt) THEN
RAISE EXCEPTION 'unauthorized';
END IF;
DELETE FROM graph_editor.person WHERE id = person.id;
RETURN true;
END;
$$ language plpgsql strict security definer;
GRANT EXECUTE ON FUNCTION graph_editor.remove_person(text) TO graph_editor_person;
COMMIT;
\ No newline at end of file
#!/bin/bash
set -e
psql -v ON_ERROR_STOP=1 --username "$POSTGRES_USER" --dbname "$POSTGRES_DB" <<-EOSQL
CREATE USER testuser WITH PASSWORD 'testpass' CREATEROLE;
CREATE DATABASE testdb;
GRANT ALL PRIVILEGES ON DATABASE testdb TO testuser;
EOSQL
psql testdb postgres <<-EOSQL
CREATE EXTENSION pgcrypto;
EOSQL
psql testdb testuser -f 100_init.sql
\ No newline at end of file
#!/bin/bash
DIR="$( cd "$( dirname "${BASH_SOURCE[0]}" )" >/dev/null 2>&1 && pwd )"
docker run \
--name graph_editor_postgresql \
-e POSTGRES_PASSWORD=postgres \
-p 5432:5432 \
--rm -d \
-v ${DIR}/../data/100_init.sql:/100_init.sql \
-v ${DIR}/init.sh:/docker-entrypoint-initdb.d/init.sh \
postgres:12.2-alpine
version: "3.7"
services:
postgresql:
container_name: graph_editor_db
build: ./database
ports:
- "5432:5432"
environment:
POSTGRES_PASSWORD: postgres
api:
container_name: graph_editor_api
build: ./api
ports:
- "3000:3000"
environment:
DB_HOST: postgresql
PORT: 3000
volumes:
- ./api:/usr/src/app
ui:
container_name: graph_editor_ui
build: ./ui
ports:
- "4000:4000"
environment:
HOST: 0.0.0.0
PORT: 4000
volumes:
- ./ui:/usr/src/app
\ No newline at end of file
# Node.js
node_modules
# Nuxt
.nuxt
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Please register or to comment