Browse Source

better types

main
Nikky 4 years ago
parent
commit
2996e8a8c1
  1. 25
      package-lock.json
  2. 1
      package.json
  3. 10
      src/config/email.config.js
  4. 5
      src/config/server.config.js
  5. 17
      src/index.js
  6. 2
      src/logic/cache.js
  7. 5
      src/logic/session.js
  8. 6
      src/logic/utils.js
  9. 3
      src/model/model.d.ts
  10. 19
      src/model/user.d.ts
  11. 9
      src/model/user.model.js
  12. 9
      src/route/auth.controller.js
  13. 25
      src/route/user.controller.js
  14. 5
      src/type/database.d.ts
  15. 8
      src/type/webserver.d.ts

25
package-lock.json

@ -310,6 +310,11 @@
"integrity": "sha1-G2gcIf+EAzyCZUMJBolCDRhxUdw=",
"optional": true
},
"chalk": {
"version": "5.0.0",
"resolved": "https://registry.npmjs.org/chalk/-/chalk-5.0.0.tgz",
"integrity": "sha512-/duVOqst+luxCQRKEo4bNxinsOQtMP80ZYm7mMqzuh5PociNL0PvmHFvREJ9ueYL2TxlHjBcmLCdmocx9Vg+IQ=="
},
"chownr": {
"version": "1.1.4",
"resolved": "https://registry.npmjs.org/chownr/-/chownr-1.1.4.tgz",
@ -998,9 +1003,9 @@
"optional": true
},
"json-schema": {
"version": "0.2.3",
"resolved": "https://registry.npmjs.org/json-schema/-/json-schema-0.2.3.tgz",
"integrity": "sha1-tIDIkuWaLwWVTOcnvT8qTogvnhM=",
"version": "0.4.0",
"resolved": "https://registry.npmjs.org/json-schema/-/json-schema-0.4.0.tgz",
"integrity": "sha512-es94M3nTIfsEPisRafak+HDLfHXnKBhV3vU5eqPcS3flIWqcxJWgXHXiey3YrpaNsanY5ei1VoYEbOzijuq9BA==",
"optional": true
},
"json-schema-traverse": {
@ -1015,14 +1020,14 @@
"optional": true
},
"jsprim": {
"version": "1.4.1",
"resolved": "https://registry.npmjs.org/jsprim/-/jsprim-1.4.1.tgz",
"integrity": "sha1-MT5mvB5cwG5Di8G3SZwuXFastqI=",
"version": "1.4.2",
"resolved": "https://registry.npmjs.org/jsprim/-/jsprim-1.4.2.tgz",
"integrity": "sha512-P2bSOMAc/ciLz6DzgjVlGJP9+BrJWu5UDGK70C2iweC5QBIeFf0ZXRvGjEj2uYgrY2MkAAhsSWHDWlFtEroZWw==",
"optional": true,
"requires": {
"assert-plus": "1.0.0",
"extsprintf": "1.3.0",
"json-schema": "0.2.3",
"json-schema": "0.4.0",
"verror": "1.10.0"
}
},
@ -2056,9 +2061,9 @@
"integrity": "sha512-+NYs2QeMWy+GWFOEm9xnn6HCDp0l7QBD7ml8zLUmJ+93Q5NF0NocErnwkTkXVFNiX3/fpC6afS8Dhb/gz7R7eg=="
},
"validator": {
"version": "13.6.0",
"resolved": "https://registry.npmjs.org/validator/-/validator-13.6.0.tgz",
"integrity": "sha512-gVgKbdbHgtxpRyR8K0O6oFZPhhB5tT1jeEHZR0Znr9Svg03U0+r9DXWMrnRAB+HtCStDQKlaIZm42tVsVjqtjg=="
"version": "13.7.0",
"resolved": "https://registry.npmjs.org/validator/-/validator-13.7.0.tgz",
"integrity": "sha512-nYXQLCBkpJ8X6ltALua9dRrZDHVYxjJ1wgskNt1lH9fzGjs3tgojGSCBjmEPwkWS1y29+DrizMTW19Pr9uB2nw=="
},
"verror": {
"version": "1.10.0",

1
package.json

@ -11,6 +11,7 @@
"license": "ISC",
"dependencies": {
"bcrypt": "^5.0.1",
"chalk": "^5.0.0",
"fastify": "^3.22.0",
"fastify-formbody": "^5.1.0",
"fastify-multipart": "^5.0.2",

10
src/config/email.config.js

@ -1,11 +1,11 @@
export const MailgunAccount = {
apiKey: '0f5cb2ebb348c88c708f1b9f7e20c385-e5da0167-1b06a230',
publicApiKey: 'pubkey-933b975a7865e74f365bbd6e0bce889d',
apiKey: '6ba1ce11ad5f5cd9170b94176dfe07ef-e5da0167-acb94f76',
publicApiKey: 'pubkey-e3afb52f411587bd80aa2febd56b5f48',
host: 'api.eu.mailgun.net',
domain: '7winds.nikky.dev'
domain: 'mail.headpat.network'
};
export const EmailConfig = {
from: "Jun Kuroshio <noreply@7winds.nikky.dev>"
}
from: "Black Tide 🌊🖤 <noreply@mail.headpat.network>"
};

5
src/config/server.config.js

@ -0,0 +1,5 @@
export const ServerConfig = {
port: 3001,
host: '127.0.0.1'
};

17
src/index.js

@ -1,8 +1,10 @@
import chalk from 'chalk';
import Fastify from 'fastify'
import formBodyPlugin from 'fastify-formbody';
import fastifyMultipart from 'fastify-multipart';
import Sequelize from 'sequelize';
import { DatabaseConfig } from './config/database.config.js';
import { ServerConfig } from './config/server.config.js';
import UserEntity from './model/user.model.js';
import AuthController from './route/auth.controller.js';
import UserController from './route/user.controller.js';
@ -15,7 +17,7 @@ async function Database(){
const opts = {db};
UserEntity(opts);
}
await db.authenticate(); //connect to the database of choice
await db.authenticate(); //connect to your database of choice
await db.sync({alter: true}); //add missing tables and columns
}
@ -28,17 +30,22 @@ async function WebApp(){
UserController(opts);
}
app.get('/', () => 'Hello. D:');
const options = { port: 3000, host: '127.0.0.1' };
const address = await app.listen(options);
return `Server is listening on ${address}.`;
const address = await app.listen(ServerConfig);
return chalk.magenta(`Server is listening on ${address}.`);
}
(async () => {
//initialize
const step = async (func, name) => {
const start = Date.now();
const tag = chalk.yellow(name);
try{
const msg = await func();
console.log(`[${name}] (${(Date.now() - start)} ms) ${msg || 'Done.'}`);
console.log(`[${tag}] (${(Date.now() - start)} ms) ${msg || chalk.green('Done.')}`);
}catch(err){
console.log(`[${tag}] ${chalk.red('Failure.')}`);
throw err;
}
};
await step(Database, 'DB');
await step(WebApp, 'Fastify');

2
src/logic/cache.js

@ -40,7 +40,7 @@ export class SpamCache extends CacheTable{
/**
* @param string key
* @param {[[maxHits: number, durationMs: number]]} constraints
* @returns
* @returns {boolean}
*/
check(key, constraints){
const now = Date.now();

5
src/logic/session.js

@ -3,6 +3,9 @@ import { ipAddress } from "./utils.js";
export class UserSession{
/**
* @param {import('../model/user').UserEntity} user
*/
constructor(user, request){
this.user = user;
this.createdAt = Date.now();
@ -19,8 +22,6 @@ export class UserSession{
return userCache.get(token);
}
static onUpdate(user){
//todo: figure out where exactly
//this hook is necessary, if it is
const session = find(user);
if(session) session.user = user;
}

6
src/logic/utils.js

@ -16,6 +16,12 @@ export function ipAddress(request){
return request.ip;
}
export function localeFromHeader(input){
//not sure what to do with this yet.
//https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Accept-Language
return checkStringParam(input, 1, 64) ? input : 'en';
}
export function reverseString(str){
return str.split("").reverse().join("");
}

3
src/model/model.d.ts

@ -1,5 +1,8 @@
import { database } from '../type/database';
import { Model } from 'sequelize/types';
export interface props{
db: database
};
export type model = Model;

19
src/model/user.d.ts

@ -0,0 +1,19 @@
import { model } from "./model"
import { UserRolesEnum } from "./user.model";
export type UserEntity = model & {
uuid: string,
token: string,
tokenExpiry: Date,
email: string,
emailConfirmed: boolean,
username: string,
passwd: string,
role: typeof UserRolesEnum,
firstIp: string,
firstLocale: string,
bannedUntil: Date,
banReason: string,
restoreCode: string,
restoreExpiry: Date
};

9
src/model/user.model.js

@ -10,13 +10,14 @@ const UserEntity = ({db}) => (
token: Sequelize.TEXT,
tokenExpiry: Sequelize.DATE,
email: Sequelize.TEXT,
emailConfirmed: Sequelize.BOOLEAN,
username: Sequelize.TEXT,
paswd: Sequelize.TEXT,
role: Sequelize.TEXT,
role: {type: Sequelize.ENUM(UserRolesEnum), defaultValue: 'user'},
firstIp: Sequelize.TEXT,
firstLocale: Sequelize.TEXT,
bannedUntil: Sequelize.DATE,
banReason: Sequelize.TEXT,
restoreCode: Sequelize.TEXT,
restoreExpiry: Sequelize.DATE
}, {
@ -31,4 +32,8 @@ const UserEntity = ({db}) => (
})
);
export const UserRolesEnum = [
'user', 'admin', 'moderator'
];
export default UserEntity;

9
src/route/auth.controller.js

@ -1,4 +1,4 @@
import { checkStringParam, errorOut, notYet, randomElement, ipAddress, reverseString, hours, minutes } from '../logic/utils.js';
import { checkStringParam, errorOut, notYet, randomElement, ipAddress, reverseString, hours, minutes, localeFromHeader } from '../logic/utils.js';
import { Animals } from '../misc/animals.js';
import { reissueToken, generateToken, newTokenExpiry, hashPassword, doesPasswordMatch, isEndpointAllowedForBannedUsers, isEndpointProtected, generateRestoreCode, restoreValidity, restoreAttempts } from '../logic/security.js';
import { sendRestorationLink } from '../logic/email.js';
@ -25,6 +25,7 @@ function AuthController({app, db}){
let session = UserSession.find(token);
if(!session){
const userData = await Users.findOne({where: {token}});
userData.role = '232';
if(userData){
session = new UserSession(userData, request);
}
@ -95,14 +96,16 @@ function AuthController({app, db}){
}
const newUser = {
email: fixedEmail,
emailConfirmed: false,
username: fixedUsername,
token: generateToken(),
tokenExpiry: newTokenExpiry(),
paswd: hashPassword(reverseString(paswd)),
role: 'user',
firstIp: ipAddress(request)
firstIp: ipAddress(request),
firstLocale: localeFromHeader(request.headers['accept-language'])
};
await Users.create(newUser);
//todo: email notify
return {token: newUser.token};
});

25
src/route/user.controller.js

@ -6,11 +6,14 @@ import { reissueToken, tokenLifetime, tokenReissue } from '../logic/security.js'
function UserController({app, db}){
const { Users } = db.models;
app.get('/users/me', async (request, reply) => {
const {session} = request;
const user = session.user;
app.get('/users/me', async (request) => {
const {user} = request.session;
let newToken;
{ // issue a new token if near expired
const needsReissue = ((user.tokenExpiry - new Date()) < (tokenLifetime - tokenReissue));
let newToken = needsReissue ? await reissueToken(user) : null;
if(needsReissue) newToken = await reissueToken(user);
}
return {
username: user.username,
@ -21,6 +24,20 @@ function UserController({app, db}){
};
});
app.delete('/users/me', async (request, reply) => {
const {paswd} = request.body || {};
const {user} = request.session;
{ //form validation
const paswdValid = isValidPassword(paswd);
const doesMatch = paswdValid && doesPasswordMatch(reverseString(paswd), user.paswd);
if(!doesMatch) return errorOut(reply, 'auth.bad_paswd');
}
await user.destroy();
//todo: email notify
return '😔';
});
}
export default UserController;

5
src/type/database.d.ts

@ -1,7 +1,8 @@
import { Sequelize } from 'sequelize/types';
import { Model, ModelCtor, Sequelize } from 'sequelize/types';
import { UserEntity } from '../model/user';
export type database = Sequelize & {
models: {
potato: string
Users: ModelCtor<UserEntity>
}
};

8
src/type/webserver.d.ts

@ -1,6 +1,10 @@
import { FastifyInstance } from 'fastify/types/instance';
import { UserSession } from '../logic/session.js';
export type webserver = FastifyInstance & {
declare module 'fastify' {
interface FastifyRequest {
session: UserSession
};
}
}
export type webserver = FastifyInstance;

Loading…
Cancel
Save