release/0.1.0
HerrHase 2 years ago
parent 1158bbc1a1
commit 78f2399c8e

2
.gitignore vendored

@ -118,3 +118,5 @@ dist
.yarn/install-state.gz
.pnp.*
#
node_modules

@ -0,0 +1,10 @@
{
"private": true,
"name": "super-hog",
"workspaces": [
"packages/*"
],
"scripts": {
"start": "yarn workspace runner run start"
}
}

File diff suppressed because it is too large Load Diff

@ -0,0 +1,15 @@
{
"name": "frontend",
"version": "0.1.0",
"dependencies": {
"@tiny-components/plain-ui": "^0.5.0",
"@tiny-components/validator": "^0.1.0",
"riot": "^6.1.2"
},
"devDependencies": {
"@riotjs/webpack-loader": "^6.0.0",
"laravel-mix": "^6.0.43",
"laravel-mix-purgecss": "^6.0.0",
"svg-spritemap-webpack-plugin": "^4.4.0"
}
}

@ -0,0 +1,15 @@
{% layout 'layout.liquid' %}
{% block app_main %}
<div class="container">
<div class="grid justify-center">
<div class="col-12 col-md-8">
<app-view></app-view>
</div>
</div>
</div>
{% endblock %}
{% block script %}
<script async src="/js/app.js"></script>
{% endblock %}

@ -0,0 +1,59 @@
<!doctype html>
<html lang="en_EN">
<head>
<meta charset="utf-8">
<title></title>
<meta name="description" content="">
<meta name="viewport" content="width=device-width, initial-scale=1">
<link href="/css/styles.css" rel="stylesheet" type="text/css">
{% block head %}{% endblock %}
</head>
<body>
<header>
{% block app_header %}
<div class="bar">
<div class="bar__start">
<h1 class="m-top-4 m-bottom-4 h4">
Super Hog
</h1>
</div>
</div>
{% endblock %}
</header>
<main>
{% block app_main %}{% endblock %}
</main>
<footer>
<div class="container">
<div class="grid justify-center">
<div class="col-12 col-md-8">
<hr / class="m-top-8">
<div class="group">
<div class="group__item">
Published under
<strong>
MIT License
</strong>
</div>
</div>
</div>
</div>
</div>
</footer>
<noscript>
<p>Only works with Javascript!</p>
</noscript>
<script>
const csrfToken = '{{ csrfToken }}'
</script>
{% block script %}{% endblock %}
</body>
</html>

@ -0,0 +1,30 @@
import Interface from 'es6-interface'
import https from 'https'
import ActionInterface from './actionInterface.js'
/**
*
*
*
*
*/
class Action extends Interface(ActionInterface)
{
/**
*
* @param {[type]} data
* @param {[type]} source
*/
constructor(source, data, options)
{
super()
this.source = source
this.data = data
this.options = options
}
}
export default Action

@ -0,0 +1,15 @@
/**
*
*
*
*
*/
const ActionInterface = {
run: function()
{
}
}
export default ActionInterface

@ -0,0 +1,58 @@
import got from 'got'
import url from 'url'
import path from 'path'
import { createWriteStream } from 'fs'
import Action from './action.js'
/**
*
*
* @extends Action
*
*/
class DownloadPodcast extends Action
{
async run()
{
// count of files
let files = 0
// errors
let errors = []
for (let item of this.data.rss.channel.item)
{
// gettin
const pubDate = new Date(item.pubDate)
// check for new entries
if (pubDate >= new Date(this.source.last_run_at))
{
const parsedUrl = url.parse(item.link)
const filename = decodeURIComponent(path.basename(parsedUrl.pathname))
const downloadStream = got.stream(item.link)
const fileWriterStream = createWriteStream(this.options.destination + '/' + filename)
downloadStream
.on('error', (error) => {
console.error(`Download failed: ${error.message}`)
})
fileWriterStream
.on('error', (error) => {
console.error(`Could not write file to system: ${error.message}`)
})
.on('finish', () => {
files++
})
await downloadStream.pipe(fileWriterStream)
}
}
}
}
export default DownloadPodcast

@ -0,0 +1,14 @@
import Interface from 'es6-interface'
import Action from './../../actions/action.js'
class MoveFile extends Action
{
run()
{
for (const item of this.data.rss.channel.item) {
console.log(item)
}
}
}
export default MoveFile

@ -0,0 +1,72 @@
import path from 'path'
import fs from 'fs'
/**
*
*
*
*/
class ResolverClass
{
/**
*
* @param {String} prefix
*
*/
constructor(prefix)
{
this.prefix = prefix
}
/**
*
*
* @param {String} className
* @param {Boolean} [isCustom=false]
* @return {String}
*
*/
lookupPath(className, isCustom = false)
{
let custom = ''
if (isCustom) {
custom = '/custom/'
}
return path.join(path.resolve(), custom + this.prefix + '/' + className + '.js')
}
/**
*
* @param {[type]} className
* @return {[type]} [description]
*/
find(className)
{
// getting
let classPath = this.lookupPath(className, true)
// results
let result = false
if (fs.existsSync(classPath)) {
result = classPath
} else {
classPath = this.lookupPath(className)
if (fs.existsSync(classPath)) {
result = classPath
}
}
if (!result) {
throw new Error('Class ' + className + ' not found!')
}
return result
}
}
export default ResolverClass

@ -0,0 +1,29 @@
import cron from 'node-cron'
const tasks = []
// uuid, schedule, source, requestHandler, actions, state
// start main cron to check for updates while running
//const main = cron.schedule('* * * * *', () => {
//})
//main.start()
import RssHandler from './requestHandlers/rssHandler.js'
const source = {
'name': 'Insert Moin',
'url': 'https://steadyhq.com/rss/insertmoin?auth=d37bffc9-9a84-4eed-95f6-3b6cb77c2406',
'actions': [{
'className': 'downloadPodcast',
'options': {
'destination': '/home/herrhase/Downloads'
}
}],
'last_run_at': '2022-01-16T23:01:00.000Z'
}
const rssHandler = new RssHandler(source)
rssHandler.send()

@ -0,0 +1,13 @@
/**
*
*
*
*/
class Notiication
{
webhook(url)
{
}
}

File diff suppressed because it is too large Load Diff

@ -0,0 +1,20 @@
{
"name": "runner",
"version": "0.1.0",
"scripts": {
"start": "node index.js"
},
"type": "module",
"dependencies": {
"date-format-parse": "^0.2.7",
"dotenv": "^10.0.0",
"es6-interface": "^3.2.1",
"fast-xml-parser": "^4.0.1",
"got": "^12.0.1",
"isomorphic-dompurify": "^0.16.0",
"node-cron": "^3.0.0",
"pouchdb": "^7.2.2",
"pouchdb-find": "^7.2.2",
"slugify": "^1.6.5"
}
}

@ -0,0 +1,34 @@
import got from 'got'
import { XMLParser } from 'fast-xml-parser'
import RequestHandler from './requestHandler.js'
/**
*
*
*
*
*/
class JsonHandler extends RequestHandler
{
/**
* getting rss feed from url
*
*
*/
async send()
{
const buffer = await got(this.source.url, {
responseType: 'buffer',
resolveBodyOnly: true
})
const parser = new XMLParser()
const feed = parser.parse(buffer.toString())
this.processActions(feed)
}
}
export default RssHandler

@ -0,0 +1,64 @@
import Interface from 'es6-interface'
import RequestHandlerInterface from './requestHandlerInterface.js'
import ResolverClass from './../helpers/resolverClass.js'
/**
*
*
*
*
*/
class RequestHandler extends Interface(RequestHandlerInterface)
{
/**
*
* @param {[type]} source
*
*/
constructor(source)
{
super()
this.source = source
}
/**
* process actions that are saved in a source
*
*
* @param {object} data
*
*/
async processActions(data)
{
let errors = false
this.source.actions.forEach(async (actions) =>
{
const resolverClass = new ResolverClass('actions')
const classPath = resolverClass.find(actions.className)
// import class from action
const Action = await import(classPath)
// create action an call run
const action = new Action.default(this.source, data, actions.options)
//
if (!await action.run())
{
errors = true
}
})
// if errors
if (errors && this.source.errors < 5) {
this.source.errors++
} else {
this.source.last_run_at = new Date()
}
}
}
export default RequestHandler

@ -0,0 +1,19 @@
/**
*
*
*
*/
const RequestHandlerInterface = {
/**
*
*
*/
send: function() {
}
}
export default RequestHandlerInterface

@ -0,0 +1,34 @@
import got from 'got'
import { XMLParser } from 'fast-xml-parser'
import RequestHandler from './requestHandler.js'
/**
*
*
*
*
*/
class RssHandler extends RequestHandler
{
/**
* getting rss feed from url
*
*
*/
async send()
{
const buffer = await got(this.source.url, {
responseType: 'buffer',
resolveBodyOnly: true
})
const parser = new XMLParser()
const feed = parser.parse(buffer.toString())
this.processActions(feed)
}
}
export default RssHandler

@ -0,0 +1,35 @@
import fastify from 'fastify'
import dotenv from 'dotenv'
import path from 'path'
// getting .env
dotenv.config({ path: path.join(path.resolve(), '/../../.env') })
// create server
const server = fastify()
/**
* add plugins
*
*/
import liquid from './plugins/liquid.js'
server.register(liquid)
/**
* add routes
*
*/
import authHttp from './http/api/auth.js'
import indexHttp from './http/index.js'
import staticHttp from './http/static.js'
server
.register(authHttp, {
'prefix': '/api'
})
.register(indexHttp)
.register(staticHttp)
export default server

@ -0,0 +1,65 @@
import DOMPurify from 'isomorphic-dompurify'
import bcrypt from 'bcrypt'
import UserRepository from './../../repositories/userRepository.js'
import loginSchema from './../../schemas/auth/login.js'
/**
* handle auth
*
* @author Björn Hase, Tentakelfabrik
* @license http://opensource.org/licenses/MIT The MIT License
* @link https://github.com/tentakelfabrik/fastify-lowdb-riotjs-lessons-learned
*
*/
export default async function(fastify, opts)
{
/**
* auth
*
* @param {object} request
* @param {object} response
*
*/
fastify.post('/auth', loginSchema, async function (request, reply)
{
let { username, password } = request.body
// strip crap from strings
username = DOMPurify.sanitize(username)
password = DOMPurify.sanitize(password)
const userRepository = new UserRepository()
const user = await userRepository.findOneByUsername(username)
// add header for json
reply.header('Content-Type', 'application/json; charset=utf-8')
// user not found
if (!user) {
return reply
.code(404)
.send()
}
// password wrong
if (!bcrypt.compareSync(password, user.password)) {
return reply
.code(401)
.send()
}
// setting session to store and set cookie
request.sessionStore.set(request.session.sessionId, request.session, async function() {
user.sessionId = request.session.sessionId
await userRepository.update(user)
// send 200 and send set-token
reply
.code(200)
.send()
})
})
}

@ -0,0 +1,43 @@
import token from '@fastify/csrf'
/**
* index
*
* - home view
* - logout user
*
*
* @author Björn Hase, Tentakelfabrik
* @license http://opensource.org/licenses/MIT The MIT License
* @link https://github.com/tentakelfabrik/fastify-lowdb-riotjs-lessons-learned
*
*/
export default async function(fastify, opts)
{
/**
* home
*
* @param {object} request
* @param {object} response
*
*/
fastify.get('/', async function(request, response)
{
response.view('./views/index.liquid')
})
/**
* logout
*
* @param {object} request
* @param {object} response
*
*/
fastify.get('/logout', async function(request, response)
{
request.destroySession(() => {
response.redirect('/')
})
})
}

@ -0,0 +1,24 @@
import fastifyStatic from 'fastify-static'
import path from 'path'
/**
* handle static
*
* @author Björn Hase, Tentakelfabrik
* @license http://opensource.org/licenses/MIT The MIT License
* @link https://github.com/tentakelfabrik/fastify-lowdb-riotjs-lessons-learned
*
*/
export default async function(fastify, opts)
{
/**
*
*
*/
fastify.register(fastifyStatic, {
root: path.join(path.resolve(), '/../../public'),
prefix: '/',
preCompressed: true
})
}

@ -0,0 +1,14 @@
import server from './bootstrap.js'
// let it rain
const start = async () => {
try {
await server.listen(process.env.APP_PORT)
console.log('Server is running on port ' + process.env.APP_PORT)
} catch (error) {
console.log(error)
process.exit(1)
}
}
start()

@ -0,0 +1,689 @@
{
"name": "server",
"version": "0.1.0",
"lockfileVersion": 1,
"requires": true,
"dependencies": {
"@fastify/ajv-compiler": {
"version": "1.1.0",
"resolved": "https://registry.npmjs.org/@fastify/ajv-compiler/-/ajv-compiler-1.1.0.tgz",
"integrity": "sha512-gvCOUNpXsWrIQ3A4aXCLIdblL0tDq42BG/2Xw7oxbil9h11uow10ztS2GuFazNBfjbrsZ5nl+nPl5jDSjj5TSg==",
"requires": {
"ajv": "^6.12.6"
}
},
"abstract-logging": {
"version": "2.0.1",
"resolved": "https://registry.npmjs.org/abstract-logging/-/abstract-logging-2.0.1.tgz",
"integrity": "sha512-2BjRTZxTPvheOvGbBslFSYOUkr+SjPtOnrLP33f+VIWLzezQpZcqVg7ja3L4dBXmzzgwT+a029jRx5PCi3JuiA=="
},
"ajv": {
"version": "6.12.6",
"resolved": "https://registry.npmjs.org/ajv/-/ajv-6.12.6.tgz",
"integrity": "sha512-j3fVLgvTo527anyYyJOGTYJbG+vnnQYvE0m5mmkc1TK+nxAppkCLMIL0aZ4dblVCNoGShhm+kzE4ZUykBoMg4g==",
"requires": {
"fast-deep-equal": "^3.1.1",
"fast-json-stable-stringify": "^2.0.0",
"json-schema-traverse": "^0.4.1",
"uri-js": "^4.2.2"
}
},
"archy": {
"version": "1.0.0",
"resolved": "https://registry.npmjs.org/archy/-/archy-1.0.0.tgz",
"integrity": "sha1-+cjBN1fMHde8N5rHeyxipcKGjEA="
},
"atomic-sleep": {
"version": "1.0.0",
"resolved": "https://registry.npmjs.org/atomic-sleep/-/atomic-sleep-1.0.0.tgz",
"integrity": "sha512-kNOjDqAh7px0XWNI+4QbzoiR/nTkHAWNud2uvnJquD1/x5a7EQZMJT0AczqK0Qn67oY/TTQ1LbUKajZpp3I9tQ=="
},
"avvio": {
"version": "7.2.2",
"resolved": "https://registry.npmjs.org/avvio/-/avvio-7.2.2.tgz",
"integrity": "sha512-XW2CMCmZaCmCCsIaJaLKxAzPwF37fXi1KGxNOvedOpeisLdmxZnblGc3hpHWYnlP+KOUxZsazh43WXNHgXpbqw==",
"requires": {
"archy": "^1.0.0",
"debug": "^4.0.0",
"fastq": "^1.6.1",
"queue-microtask": "^1.1.2"
}
},
"balanced-match": {
"version": "1.0.2",
"resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.2.tgz",
"integrity": "sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw=="
},
"basic-auth": {
"version": "2.0.1",
"resolved": "https://registry.npmjs.org/basic-auth/-/basic-auth-2.0.1.tgz",
"integrity": "sha512-NF+epuEdnUYVlGuhaxbbq+dvJttwLnGY+YixlXlME5KpQ5W3CnXA5cVTneY3SPbPDRkcjMbifrwmFYcClgOZeg==",
"requires": {
"safe-buffer": "5.1.2"
},
"dependencies": {
"safe-buffer": {
"version": "5.1.2",
"resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.2.tgz",
"integrity": "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g=="
}
}
},
"brace-expansion": {
"version": "1.1.11",
"resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz",
"integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==",
"requires": {
"balanced-match": "^1.0.0",
"concat-map": "0.0.1"
}
},
"concat-map": {
"version": "0.0.1",
"resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz",
"integrity": "sha1-2Klr13/Wjfd5OnMDajug1UBdR3s="
},
"content-disposition": {
"version": "0.5.4",
"resolved": "https://registry.npmjs.org/content-disposition/-/content-disposition-0.5.4.tgz",
"integrity": "sha512-FveZTNuGw04cxlAiWbzi6zTAL/lhehaWbTtgluJh4/E95DqMwTmha3KZN1aAWA8cFIhHzMZUvLevkw5Rqk+tSQ==",
"requires": {
"safe-buffer": "5.2.1"
}
},
"cookie": {
"version": "0.4.1",
"resolved": "https://registry.npmjs.org/cookie/-/cookie-0.4.1.tgz",
"integrity": "sha512-ZwrFkGJxUR3EIoXtO+yVE69Eb7KlixbaeAWfBQB9vVsNn/o+Yw69gBWSSDK825hQNdN+wF8zELf3dFNl/kxkUA=="
},
"debug": {
"version": "4.3.3",
"resolved": "https://registry.npmjs.org/debug/-/debug-4.3.3.tgz",
"integrity": "sha512-/zxw5+vh1Tfv+4Qn7a5nsbcJKPaSvCDhojn6FEl9vupwK2VCSDtEiEtqr8DFtzYFOdz63LBkxec7DYuc2jon6Q==",
"requires": {
"ms": "2.1.2"
}
},
"deepmerge": {
"version": "4.2.2",
"resolved": "https://registry.npmjs.org/deepmerge/-/deepmerge-4.2.2.tgz",
"integrity": "sha512-FJ3UgI4gIl+PHZm53knsuSFpE+nESMr7M4v9QcgB7S63Kj/6WqMiFQJpBBYz1Pt+66bZpP3Q7Lye0Oo9MPKEdg=="
},
"depd": {
"version": "1.1.2",
"resolved": "https://registry.npmjs.org/depd/-/depd-1.1.2.tgz",
"integrity": "sha1-m81S4UwJd2PnSbJ0xDRu0uVgtak="
},
"destroy": {
"version": "1.0.4",
"resolved": "https://registry.npmjs.org/destroy/-/destroy-1.0.4.tgz",
"integrity": "sha1-l4hXRCxEdJ5CBmE+N5RiBYJqvYA="
},
"dotenv": {
"version": "10.0.0",
"resolved": "https://registry.npmjs.org/dotenv/-/dotenv-10.0.0.tgz",
"integrity": "sha512-rlBi9d8jpv9Sf1klPjNfFAuWDjKLwTIJJ/VxtoTwIR6hnZxcEOQCZg2oIL3MWBYw5GpUDKOEnND7LXTbIpQ03Q=="
},
"ee-first": {
"version": "1.1.1",
"resolved": "https://registry.npmjs.org/ee-first/-/ee-first-1.1.1.tgz",
"integrity": "sha1-WQxhFWsK4vTwJVcyoViyZrxWsh0="
},
"encodeurl": {
"version": "1.0.2",
"resolved": "https://registry.npmjs.org/encodeurl/-/encodeurl-1.0.2.tgz",
"integrity": "sha1-rT/0yG7C0CkyL1oCw6mmBslbP1k="
},
"encoding-negotiator": {
"version": "2.0.1",
"resolved": "https://registry.npmjs.org/encoding-negotiator/-/encoding-negotiator-2.0.1.tgz",
"integrity": "sha512-GSK7qphNR4iPcejfAlZxKDoz3xMhnspwImK+Af5WhePS9jUpK/Oh7rUdyENWu+9rgDflOCTmAojBsgsvM8neAQ=="
},
"escape-html": {
"version": "1.0.3",
"resolved": "https://registry.npmjs.org/escape-html/-/escape-html-1.0.3.tgz",
"integrity": "sha1-Aljq5NPQwJdN4cFpGI7wBR0dGYg="
},
"etag": {
"version": "1.8.1",
"resolved": "https://registry.npmjs.org/etag/-/etag-1.8.1.tgz",
"integrity": "sha1-Qa4u62XvpiJorr/qg6x9eSmbCIc="
},
"fast-decode-uri-component": {
"version": "1.0.1",
"resolved": "https://registry.npmjs.org/fast-decode-uri-component/-/fast-decode-uri-component-1.0.1.tgz",
"integrity": "sha512-WKgKWg5eUxvRZGwW8FvfbaH7AXSh2cL+3j5fMGzUMCxWBJ3dV3a7Wz8y2f/uQ0e3B6WmodD3oS54jTQ9HVTIIg=="
},
"fast-deep-equal": {
"version": "3.1.3",
"resolved": "https://registry.npmjs.org/fast-deep-equal/-/fast-deep-equal-3.1.3.tgz",
"integrity": "sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q=="
},
"fast-json-stable-stringify": {
"version": "2.1.0",
"resolved": "https://registry.npmjs.org/fast-json-stable-stringify/-/fast-json-stable-stringify-2.1.0.tgz",
"integrity": "sha512-lhd/wF+Lk98HZoTCtlVraHtfh5XYijIjalXck7saUtuanSDyLMxnHhSXEDJqHxD7msR8D0uCmqlkwjCV8xvwHw=="
},
"fast-json-stringify": {
"version": "2.7.13",
"resolved": "https://registry.npmjs.org/fast-json-stringify/-/fast-json-stringify-2.7.13.tgz",
"integrity": "sha512-ar+hQ4+OIurUGjSJD1anvYSDcUflywhKjfxnsW4TBTD7+u0tJufv6DKRWoQk3vI6YBOWMoz0TQtfbe7dxbQmvA==",
"requires": {
"ajv": "^6.11.0",
"deepmerge": "^4.2.2",
"rfdc": "^1.2.0",
"string-similarity": "^4.0.1"
}
},
"fast-redact": {
"version": "3.1.0",
"resolved": "https://registry.npmjs.org/fast-redact/-/fast-redact-3.1.0.tgz",
"integrity": "sha512-dir8LOnvialLxiXDPESMDHGp82CHi6ZEYTVkcvdn5d7psdv9ZkkButXrOeXST4aqreIRR+N7CYlsrwFuorurVg=="
},
"fast-safe-stringify": {
"version": "2.1.1",
"resolved": "https://registry.npmjs.org/fast-safe-stringify/-/fast-safe-stringify-2.1.1.tgz",
"integrity": "sha512-W+KJc2dmILlPplD/H4K9l9LcAHAfPtP6BY84uVLXQ6Evcz9Lcg33Y2z1IVblT6xdY54PXYVHEv+0Wpq8Io6zkA=="
},
"fastify": {
"version": "3.27.0",
"resolved": "https://registry.npmjs.org/fastify/-/fastify-3.27.0.tgz",
"integrity": "sha512-p99Fd7xt4DFew39U5Wnp/Soy7jkpxpaqToekwQ3XWv+ECUPXd6bSF9l79EiwkutWALtEU/JiRlzS9qjP2gLHFg==",
"requires": {
"@fastify/ajv-compiler": "^1.0.0",
"abstract-logging": "^2.0.0",
"avvio": "^7.1.2",
"fast-json-stringify": "^2.5.2",
"fastify-error": "^0.3.0",
"find-my-way": "^4.5.0",
"flatstr": "^1.0.12",
"light-my-request": "^4.2.0",
"pino": "^6.13.0",
"process-warning": "^1.0.0",
"proxy-addr": "^2.0.7",
"rfdc": "^1.1.4",
"secure-json-parse": "^2.0.0",
"semver": "^7.3.2",
"tiny-lru": "^7.0.0"
}
},
"fastify-auth": {
"version": "1.1.0",
"resolved": "https://registry.npmjs.org/fastify-auth/-/fastify-auth-1.1.0.tgz",
"integrity": "sha512-8IajmAZB3QJ3wTP0q8Z3TG9DkxrIcAlS85TdPCBEfJi3mMKQd/sCYxtZ0dYv11v5hZaJ9z8XmNzhK3AH6/JpNw==",
"requires": {
"fastify-plugin": "^3.0.0",
"reusify": "^1.0.4"
}
},
"fastify-basic-auth": {
"version": "2.2.0",
"resolved": "https://registry.npmjs.org/fastify-basic-auth/-/fastify-basic-auth-2.2.0.tgz",
"integrity": "sha512-xXeNhyhONlQNoWIzy9rhms0td6PFL1KCRqu0lkEpd54Ju4dHLbB/woPwtK0Vutuqy0sDav77If6UtdfDajx44Q==",
"requires": {
"basic-auth": "^2.0.1",
"fastify-plugin": "^3.0.0",
"http-errors": "^1.7.3"
}
},
"fastify-error": {
"version": "0.3.1",
"resolved": "https://registry.npmjs.org/fastify-error/-/fastify-error-0.3.1.tgz",
"integrity": "sha512-oCfpcsDndgnDVgiI7bwFKAun2dO+4h84vBlkWsWnz/OUK9Reff5UFoFl241xTiLeHWX/vU9zkDVXqYUxjOwHcQ=="
},
"fastify-formbody": {
"version": "5.2.0",
"resolved": "https://registry.npmjs.org/fastify-formbody/-/fastify-formbody-5.2.0.tgz",
"integrity": "sha512-d8Y5hCL82akPyoFiXh2wYOm3es0pV9jqoPo3pO9OV2cNF0cQx39J5WAVXzCh4MSt9Z2qF4Fy5gHlvlyESwjtvg==",
"requires": {
"fastify-plugin": "^3.0.0"
}
},
"fastify-plugin": {
"version": "3.0.0",
"resolved": "https://registry.npmjs.org/fastify-plugin/-/fastify-plugin-3.0.0.tgz",
"integrity": "sha512-ZdCvKEEd92DNLps5n0v231Bha8bkz1DjnPP/aEz37rz/q42Z5JVLmgnqR4DYuNn3NXAO3IDCPyRvgvxtJ4Ym4w=="
},
"fastify-static": {
"version": "4.5.0",
"resolved": "https://registry.npmjs.org/fastify-static/-/fastify-static-4.5.0.tgz",
"integrity": "sha512-Q7Tgl55AjsmBwiO4hKYib2BUCt+XTWLJ6Xp8YPPHU3EsrKNpevJ4cz8pjf1Ey1QhHw9O8Y2FDKdu+IC74oHvqw==",
"requires": {
"content-disposition": "^0.5.3",
"encoding-negotiator": "^2.0.1",
"fastify-plugin": "^3.0.0",
"glob": "^7.1.4",
"p-limit": "^3.1.0",
"readable-stream": "^3.4.0",
"send": "^0.17.1"
}
},
"fastify-warning": {
"version": "0.2.0",
"resolved": "https://registry.npmjs.org/fastify-warning/-/fastify-warning-0.2.0.tgz",
"integrity": "sha512-s1EQguBw/9qtc1p/WTY4eq9WMRIACkj+HTcOIK1in4MV5aFaQC9ZCIt0dJ7pr5bIf4lPpHvAtP2ywpTNgs7hqw=="
},
"fastq": {
"version": "1.13.0",
"resolved": "https://registry.npmjs.org/fastq/-/fastq-1.13.0.tgz",
"integrity": "sha512-YpkpUnK8od0o1hmeSc7UUs/eB/vIPWJYjKck2QKIzAf71Vm1AAQ3EbuZB3g2JIy+pg+ERD0vqI79KyZiB2e2Nw==",
"requires": {
"reusify": "^1.0.4"
}
},
"find-my-way": {
"version": "4.5.1",
"resolved": "https://registry.npmjs.org/find-my-way/-/find-my-way-4.5.1.tgz",
"integrity": "sha512-kE0u7sGoUFbMXcOG/xpkmz4sRLCklERnBcg7Ftuu1iAxsfEt2S46RLJ3Sq7vshsEy2wJT2hZxE58XZK27qa8kg==",
"requires": {
"fast-decode-uri-component": "^1.0.1",
"fast-deep-equal": "^3.1.3",
"safe-regex2": "^2.0.0",
"semver-store": "^0.3.0"
}
},
"flatstr": {
"version": "1.0.12",
"resolved": "https://registry.npmjs.org/flatstr/-/flatstr-1.0.12.tgz",
"integrity": "sha512-4zPxDyhCyiN2wIAtSLI6gc82/EjqZc1onI4Mz/l0pWrAlsSfYH/2ZIcU+e3oA2wDwbzIWNKwa23F8rh6+DRWkw=="
},
"forwarded": {
"version": "0.2.0",
"resolved": "https://registry.npmjs.org/forwarded/-/forwarded-0.2.0.tgz",
"integrity": "sha512-buRG0fpBtRHSTCOASe6hD258tEubFoRLb4ZNA6NxMVHNw2gOcwHo9wyablzMzOA5z9xA9L1KNjk/Nt6MT9aYow=="
},
"fresh": {
"version": "0.5.2",
"resolved": "https://registry.npmjs.org/fresh/-/fresh-0.5.2.tgz",
"integrity": "sha1-PYyt2Q2XZWn6g1qx+OSyOhBWBac="
},
"fs.realpath": {
"version": "1.0.0",
"resolved": "https://registry.npmjs.org/fs.realpath/-/fs.realpath-1.0.0.tgz",
"integrity": "sha1-FQStJSMVjKpA20onh8sBQRmU6k8="
},
"glob": {
"version": "7.2.0",
"resolved": "https://registry.npmjs.org/glob/-/glob-7.2.0.tgz",
"integrity": "sha512-lmLf6gtyrPq8tTjSmrO94wBeQbFR3HbLHbuyD69wuyQkImp2hWqMGB47OX65FBkPffO641IP9jWa1z4ivqG26Q==",
"requires": {
"fs.realpath": "^1.0.0",
"inflight": "^1.0.4",
"inherits": "2",
"minimatch": "^3.0.4",
"once": "^1.3.0",
"path-is-absolute": "^1.0.0"
}
},
"hashlru": {
"version": "2.3.0",
"resolved": "https://registry.npmjs.org/hashlru/-/hashlru-2.3.0.tgz",
"integrity": "sha512-0cMsjjIC8I+D3M44pOQdsy0OHXGLVz6Z0beRuufhKa0KfaD2wGwAev6jILzXsd3/vpnNQJmWyZtIILqM1N+n5A=="
},
"http-errors": {
"version": "1.8.1",
"resolved": "https://registry.npmjs.org/http-errors/-/http-errors-1.8.1.tgz",
"integrity": "sha512-Kpk9Sm7NmI+RHhnj6OIWDI1d6fIoFAtFt9RLaTMRlg/8w49juAStsrBgp0Dp4OdxdVbRIeKhtCUvoi/RuAhO4g==",
"requires": {
"depd": "~1.1.2",
"inherits": "2.0.4",
"setprototypeof": "1.2.0",
"statuses": ">= 1.5.0 < 2",
"toidentifier": "1.0.1"
}
},
"inflight": {
"version": "1.0.6",
"resolved": "https://registry.npmjs.org/inflight/-/inflight-1.0.6.tgz",
"integrity": "sha1-Sb1jMdfQLQwJvJEKEHW6gWW1bfk=",
"requires": {
"once": "^1.3.0",
"wrappy": "1"
}
},
"inherits": {
"version": "2.0.4",
"resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.4.tgz",
"integrity": "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ=="
},
"ipaddr.js": {
"version": "1.9.1",
"resolved": "https://registry.npmjs.org/ipaddr.js/-/ipaddr.js-1.9.1.tgz",
"integrity": "sha512-0KI/607xoxSToH7GjN1FfSbLoU0+btTicjsQSWQlh/hZykN8KpmMf7uYwPW3R+akZ6R/w18ZlXSHBYXiYUPO3g=="
},
"json-schema-traverse": {
"version": "0.4.1",
"resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-0.4.1.tgz",
"integrity": "sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg=="
},
"light-my-request": {
"version": "4.7.0",
"resolved": "https://registry.npmjs.org/light-my-request/-/light-my-request-4.7.0.tgz",
"integrity": "sha512-LTa8YZp3K2AUpqUnwwKajoIHcsKOBnzwJNQSrk7unziPwo6CjOYjyO0F9wfkxFvP+nBsCGe3eMPnedVgIIgdAw==",
"requires": {
"ajv": "^8.1.0",
"cookie": "^0.4.0",
"fastify-warning": "^0.2.0",
"set-cookie-parser": "^2.4.1"
},
"dependencies": {
"ajv": {
"version": "8.9.0",
"resolved": "https://registry.npmjs.org/ajv/-/ajv-8.9.0.tgz",
"integrity": "sha512-qOKJyNj/h+OWx7s5DePL6Zu1KeM9jPZhwBqs+7DzP6bGOvqzVCSf0xueYmVuaC/oQ/VtS2zLMLHdQFbkka+XDQ==",
"requires": {
"fast-deep-equal": "^3.1.1",
"json-schema-traverse": "^1.0.0",
"require-from-string": "^2.0.2",
"uri-js": "^4.2.2"
}
},
"json-schema-traverse": {
"version": "1.0.0",
"resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-1.0.0.tgz",
"integrity": "sha512-NM8/P9n3XjXhIZn1lLhkFaACTOURQXjWhV4BA/RnOv8xvgqtqpAX9IO4mRQxSx1Rlo4tqzeqb0sOlruaOy3dug=="
}
}
},
"liquidjs": {
"version": "9.33.1",
"resolved": "https://registry.npmjs.org/liquidjs/-/liquidjs-9.33.1.tgz",
"integrity": "sha512-qIMSXkUMFG5VZmBp1qxcOEFeGzmA2A8Fy818rMTAWKyy2ftUwOEoVtvXFdqm3iSeQEoj8pzTOmC6KQOP0SipUA=="
},
"lru-cache": {
"version": "6.0.0",
"resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-6.0.0.tgz",
"integrity": "sha512-Jo6dJ04CmSjuznwJSS3pUeWmd/H0ffTlkXXgwZi+eq1UCmqQwCh+eLsYOYCwY991i2Fah4h1BEMCx4qThGbsiA==",
"requires": {
"yallist": "^4.0.0"
}
},
"mime": {
"version": "1.6.0",
"resolved": "https://registry.npmjs.org/mime/-/mime-1.6.0.tgz",
"integrity": "sha512-x0Vn8spI+wuJ1O6S7gnbaQg8Pxh4NNHb7KSINmEWKiPE4RKOplvijn+NkmYmmRgP68mc70j2EbeTFRsrswaQeg=="
},
"minimatch": {
"version": "3.0.4",
"resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.0.4.tgz",
"integrity": "sha512-yJHVQEhyqPLUTgt9B83PXu6W3rx4MvvHvSUvToogpwoGDOUQ+yDrR0HRot+yOCdCO7u4hX3pWft6kWBBcqh0UA==",
"requires": {
"brace-expansion": "^1.1.7"
}
},
"ms": {
"version": "2.1.2",
"resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz",
"integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w=="
},
"on-finished": {
"version": "2.3.0",
"resolved": "https://registry.npmjs.org/on-finished/-/on-finished-2.3.0.tgz",
"integrity": "sha1-IPEzZIGwg811M3mSoWlxqi2QaUc=",
"requires": {
"ee-first": "1.1.1"
}
},
"once": {
"version": "1.4.0",
"resolved": "https://registry.npmjs.org/once/-/once-1.4.0.tgz",
"integrity": "sha1-WDsap3WWHUsROsF9nFC6753Xa9E=",
"requires": {
"wrappy": "1"
}
},
"p-limit": {
"version": "3.1.0",
"resolved": "https://registry.npmjs.org/p-limit/-/p-limit-3.1.0.tgz",
"integrity": "sha512-TYOanM3wGwNGsZN2cVTYPArw454xnXj5qmWF1bEoAc4+cU/ol7GVh7odevjp1FNHduHc3KZMcFduxU5Xc6uJRQ==",
"requires": {
"yocto-queue": "^0.1.0"
}
},
"path-is-absolute": {
"version": "1.0.1",
"resolved": "https://registry.npmjs.org/path-is-absolute/-/path-is-absolute-1.0.1.tgz",
"integrity": "sha1-F0uSaHNVNP+8es5r9TpanhtcX18="
},
"pino": {
"version": "6.13.4",
"resolved": "https://registry.npmjs.org/pino/-/pino-6.13.4.tgz",
"integrity": "sha512-g4tHSISmQJYUEKEMVdaZ+ZokWwFnTwZL5JPn+lnBVZ1BuBbrSchrXwQINknkM5+Q4fF6U9NjiI8PWwwMDHt9zA==",
"requires": {
"fast-redact": "^3.0.0",
"fast-safe-stringify": "^2.0.8",
"flatstr": "^1.0.12",
"pino-std-serializers": "^3.1.0",
"process-warning": "^1.0.0",
"quick-format-unescaped": "^4.0.3",
"sonic-boom": "^1.0.2"
}
},
"pino-std-serializers": {
"version": "3.2.0",
"resolved": "https://registry.npmjs.org/pino-std-serializers/-/pino-std-serializers-3.2.0.tgz",
"integrity": "sha512-EqX4pwDPrt3MuOAAUBMU0Tk5kR/YcCM5fNPEzgCO2zJ5HfX0vbiH9HbJglnyeQsN96Kznae6MWD47pZB5avTrg=="
},
"point-of-view": {
"version": "5.0.0",
"resolved": "https://registry.npmjs.org/point-of-view/-/point-of-view-5.0.0.tgz",
"integrity": "sha512-JY12G3+jVFYccKTexe2OHG9WHrEUb3eLKPtLM/YEnaJf2i2OuzIun/v6SBzjHFm5sOuNXyKKo47HIe/YkGtEMA==",
"requires": {
"fastify-plugin": "^3.0.0",
"hashlru": "^2.3.0"
}
},
"process-warning": {
"version": "1.0.0",
"resolved": "https://registry.npmjs.org/process-warning/-/process-warning-1.0.0.tgz",
"integrity": "sha512-du4wfLyj4yCZq1VupnVSZmRsPJsNuxoDQFdCFHLaYiEbFBD7QE0a+I4D7hOxrVnh78QE/YipFAj9lXHiXocV+Q=="
},
"proxy-addr": {
"version": "2.0.7",
"resolved": "https://registry.npmjs.org/proxy-addr/-/proxy-addr-2.0.7.tgz",
"integrity": "sha512-llQsMLSUDUPT44jdrU/O37qlnifitDP+ZwrmmZcoSKyLKvtZxpyV0n2/bD/N4tBAAZ/gJEdZU7KMraoK1+XYAg==",
"requires": {
"forwarded": "0.2.0",
"ipaddr.js": "1.9.1"
}
},
"punycode": {
"version": "2.1.1",
"resolved": "https://registry.npmjs.org/punycode/-/punycode-2.1.1.tgz",
"integrity": "sha512-XRsRjdf+j5ml+y/6GKHPZbrF/8p2Yga0JPtdqTIY2Xe5ohJPD9saDJJLPvp9+NSBprVvevdXZybnj2cv8OEd0A=="
},
"queue-microtask": {
"version": "1.2.3",
"resolved": "https://registry.npmjs.org/queue-microtask/-/queue-microtask-1.2.3.tgz",
"integrity": "sha512-NuaNSa6flKT5JaSYQzJok04JzTL1CA6aGhv5rfLW3PgqA+M2ChpZQnAC8h8i4ZFkBS8X5RqkDBHA7r4hej3K9A=="
},
"quick-format-unescaped": {
"version": "4.0.4",
"resolved": "https://registry.npmjs.org/quick-format-unescaped/-/quick-format-unescaped-4.0.4.tgz",
"integrity": "sha512-tYC1Q1hgyRuHgloV/YXs2w15unPVh8qfu/qCTfhTYamaw7fyhumKa2yGpdSo87vY32rIclj+4fWYQXUMs9EHvg=="
},
"range-parser": {
"version": "1.2.1",
"resolved": "https://registry.npmjs.org/range-parser/-/range-parser-1.2.1.tgz",
"integrity": "sha512-Hrgsx+orqoygnmhFbKaHE6c296J+HTAQXoxEF6gNupROmmGJRoyzfG3ccAveqCBrwr/2yxQ5BVd/GTl5agOwSg=="
},
"readable-stream": {
"version": "3.6.0",
"resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-3.6.0.tgz",
"integrity": "sha512-BViHy7LKeTz4oNnkcLJ+lVSL6vpiFeX6/d3oSH8zCW7UxP2onchk+vTGB143xuFjHS3deTgkKoXXymXqymiIdA==",
"requires": {
"inherits": "^2.0.3",
"string_decoder": "^1.1.1",
"util-deprecate": "^1.0.1"
}
},
"require-from-string": {
"version": "2.0.2",
"resolved": "https://registry.npmjs.org/require-from-string/-/require-from-string-2.0.2.tgz",
"integrity": "sha512-Xf0nWe6RseziFMu+Ap9biiUbmplq6S9/p+7w7YXP/JBHhrUDDUhwa+vANyubuqfZWTveU//DYVGsDG7RKL/vEw=="
},
"ret": {
"version": "0.2.2",
"resolved": "https://registry.npmjs.org/ret/-/ret-0.2.2.tgz",
"integrity": "sha512-M0b3YWQs7R3Z917WRQy1HHA7Ba7D8hvZg6UE5mLykJxQVE2ju0IXbGlaHPPlkY+WN7wFP+wUMXmBFA0aV6vYGQ=="
},
"reusify": {
"version": "1.0.4",
"resolved": "https://registry.npmjs.org/reusify/-/reusify-1.0.4.tgz",
"integrity": "sha512-U9nH88a3fc/ekCF1l0/UP1IosiuIjyTh7hBvXVMHYgVcfGvt897Xguj2UOLDeI5BG2m7/uwyaLVT6fbtCwTyzw=="
},
"rfdc": {
"version": "1.3.0",
"resolved": "https://registry.npmjs.org/rfdc/-/rfdc-1.3.0.tgz",
"integrity": "sha512-V2hovdzFbOi77/WajaSMXk2OLm+xNIeQdMMuB7icj7bk6zi2F8GGAxigcnDFpJHbNyNcgyJDiP+8nOrY5cZGrA=="
},
"safe-buffer": {
"version": "5.2.1",
"resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.2.1.tgz",
"integrity": "sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ=="
},
"safe-regex2": {
"version": "2.0.0",
"resolved": "https://registry.npmjs.org/safe-regex2/-/safe-regex2-2.0.0.tgz",
"integrity": "sha512-PaUSFsUaNNuKwkBijoAPHAK6/eM6VirvyPWlZ7BAQy4D+hCvh4B6lIG+nPdhbFfIbP+gTGBcrdsOaUs0F+ZBOQ==",
"requires": {
"ret": "~0.2.0"
}
},
"secure-json-parse": {
"version": "2.4.0",
"resolved": "https://registry.npmjs.org/secure-json-parse/-/secure-json-parse-2.4.0.tgz",
"integrity": "sha512-Q5Z/97nbON5t/L/sH6mY2EacfjVGwrCcSi5D3btRO2GZ8pf1K1UN7Z9H5J57hjVU2Qzxr1xO+FmBhOvEkzCMmg=="
},
"semver": {
"version": "7.3.5",
"resolved": "https://registry.npmjs.org/semver/-/semver-7.3.5.tgz",
"integrity": "sha512-PoeGJYh8HK4BTO/a9Tf6ZG3veo/A7ZVsYrSA6J8ny9nb3B1VrpkuN+z9OE5wfE5p6H4LchYZsegiQgbJD94ZFQ==",
"requires": {
"lru-cache": "^6.0.0"
}
},
"semver-store": {
"version": "0.3.0",
"resolved": "https://registry.npmjs.org/semver-store/-/semver-store-0.3.0.tgz",
"integrity": "sha512-TcZvGMMy9vodEFSse30lWinkj+JgOBvPn8wRItpQRSayhc+4ssDs335uklkfvQQJgL/WvmHLVj4Ycv2s7QCQMg=="
},
"send": {
"version": "0.17.2",
"resolved": "https://registry.npmjs.org/send/-/send-0.17.2.tgz",
"integrity": "sha512-UJYB6wFSJE3G00nEivR5rgWp8c2xXvJ3OPWPhmuteU0IKj8nKbG3DrjiOmLwpnHGYWAVwA69zmTm++YG0Hmwww==",
"requires": {
"debug": "2.6.9",
"depd": "~1.1.2",
"destroy": "~1.0.4",
"encodeurl": "~1.0.2",
"escape-html": "~1.0.3",
"etag": "~1.8.1",
"fresh": "0.5.2",
"http-errors": "1.8.1",
"mime": "1.6.0",
"ms": "2.1.3",
"on-finished": "~2.3.0",
"range-parser": "~1.2.1",
"statuses": "~1.5.0"
},
"dependencies": {
"debug": {
"version": "2.6.9",
"resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz",
"integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==",
"requires": {
"ms": "2.0.0"
},
"dependencies": {
"ms": {
"version": "2.0.0",
"resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz",
"integrity": "sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g="
}
}
},
"ms": {
"version": "2.1.3",
"resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz",
"integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA=="
}
}
},
"set-cookie-parser": {
"version": "2.4.8",
"resolved": "https://registry.npmjs.org/set-cookie-parser/-/set-cookie-parser-2.4.8.tgz",
"integrity": "sha512-edRH8mBKEWNVIVMKejNnuJxleqYE/ZSdcT8/Nem9/mmosx12pctd80s2Oy00KNZzrogMZS5mauK2/ymL1bvlvg=="
},
"setprototypeof": {
"version": "1.2.0",
"resolved": "https://registry.npmjs.org/setprototypeof/-/setprototypeof-1.2.0.tgz",
"integrity": "sha512-E5LDX7Wrp85Kil5bhZv46j8jOeboKq5JMmYM3gVGdGH8xFpPWXUMsNrlODCrkoxMEeNi/XZIwuRvY4XNwYMJpw=="
},
"sonic-boom": {
"version": "1.4.1",
"resolved": "https://registry.npmjs.org/sonic-boom/-/sonic-boom-1.4.1.tgz",
"integrity": "sha512-LRHh/A8tpW7ru89lrlkU4AszXt1dbwSjVWguGrmlxE7tawVmDBlI1PILMkXAxJTwqhgsEeTHzj36D5CmHgQmNg==",
"requires": {
"atomic-sleep": "^1.0.0",
"flatstr": "^1.0.12"
}
},
"statuses": {
"version": "1.5.0",
"resolved": "https://registry.npmjs.org/statuses/-/statuses-1.5.0.tgz",
"integrity": "sha1-Fhx9rBd2Wf2YEfQ3cfqZOBR4Yow="
},
"string-similarity": {
"version": "4.0.4",
"resolved": "https://registry.npmjs.org/string-similarity/-/string-similarity-4.0.4.tgz",
"integrity": "sha512-/q/8Q4Bl4ZKAPjj8WerIBJWALKkaPRfrvhfF8k/B23i4nzrlRj2/go1m90In7nG/3XDSbOo0+pu6RvCTM9RGMQ=="
},
"string_decoder": {
"version": "1.3.0",
"resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.3.0.tgz",
"integrity": "sha512-hkRX8U1WjJFd8LsDJ2yQ/wWWxaopEsABU1XfkM8A+j0+85JAGppt16cr1Whg6KIbb4okU6Mql6BOj+uup/wKeA==",
"requires": {
"safe-buffer": "~5.2.0"
}
},
"tiny-lru": {
"version": "7.0.6",
"resolved": "https://registry.npmjs.org/tiny-lru/-/tiny-lru-7.0.6.tgz",
"integrity": "sha512-zNYO0Kvgn5rXzWpL0y3RS09sMK67eGaQj9805jlK9G6pSadfriTczzLHFXa/xcW4mIRfmlB9HyQ/+SgL0V1uow=="
},
"toidentifier": {
"version": "1.0.1",
"resolved": "https://registry.npmjs.org/toidentifier/-/toidentifier-1.0.1.tgz",
"integrity": "sha512-o5sSPKEkg/DIQNmH43V0/uerLrpzVedkUh8tGNvaeXpfpuwjKenlSox/2O/BTlZUtEe+JG7s5YhEz608PlAHRA=="
},
"uri-js": {
"version": "4.4.1",
"resolved": "https://registry.npmjs.org/uri-js/-/uri-js-4.4.1.tgz",
"integrity": "sha512-7rKUyy33Q1yc98pQ1DAmLtwX109F7TIfWlW1Ydo8Wl1ii1SeHieeh0HHfPeL2fMXK6z0s8ecKs9frCuLJvndBg==",
"requires": {
"punycode": "^2.1.0"
}
},
"util-deprecate": {
"version": "1.0.2",
"resolved": "https://registry.npmjs.org/util-deprecate/-/util-deprecate-1.0.2.tgz",
"integrity": "sha1-RQ1Nyfpw3nMnYvvS1KKJgUGaDM8="
},
"wrappy": {
"version": "1.0.2",
"resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz",
"integrity": "sha1-tSQ9jz7BqjXxNkYFvA0QNuMKtp8="
},
"yallist": {
"version": "4.0.0",
"resolved": "https://registry.npmjs.org/yallist/-/yallist-4.0.0.tgz",
"integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A=="
},
"yocto-queue": {
"version": "0.1.0",
"resolved": "https://registry.npmjs.org/yocto-queue/-/yocto-queue-0.1.0.tgz",
"integrity": "sha512-rVksvsnNCdJ/ohGc6xgPwyN8eheCxsiLM8mxuE/t/mOVqJewPuO1miLpTHQiRgTKCLexL4MeAFVagts7HmNZ2Q=="
}
}
}

@ -0,0 +1,20 @@
{
"name": "server",
"version": "0.1.0",
"scripts": {
"start": "node index.js"
},
"type": "module",
"dependencies": {
"dotenv": "^10.0.0",
"fastify": "^3.27.0",
"fastify-auth": "^1.1.0",
"fastify-basic-auth": "^2.2.0",
"fastify-formbody": "^5.2.0",
"fastify-static": "^4.5.0",
"liquidjs": "^9.33.1",
"point-of-view": "^5.0.0",
"pouchdb": "^7.2.2",
"pouchdb-find": "^7.2.2"
}
}

@ -0,0 +1,25 @@
import { Liquid } from 'liquidjs'
import pov from 'point-of-view'
import path from 'path'
/**
* plugin: usindg render engine liquidjs
*
*
*/
function plugin(fastify, options, next) {
{
const engine = new Liquid({
root: path.join(path.resolve(), '/views'),
extname: '.liquid',
})
fastify.register(pov, {
engine: {
liquid: engine
}
})
}
module.exports = plugin

@ -0,0 +1,212 @@
import fastifySession from '@fastify/session'
import fastifyCookie from 'fastify-cookie'
import PouchDB from 'pouchdb'
import PouchDBfind from 'pouchdb-find'
/**
* pouchdb storage
*
*
* @extends Store
*
*/
class PouchdbStore extends Store
{
/**
*
*
* @param {Object}
*
*/
constructor()
{
super()
PouchDB.plugin(PouchDBfind)
// create db if not already exists
this.db = new PouchDB('./../../storage/session', {
revs_limit: 0
})
}
/**
*
* @param {[type]} sessionId [description]
* @param {Function} callback [description]
*/
async set(sessionId, session, callback)
{
const result = await this.db.find({
'selector': {
'_id': sessionId
}
})
if (result.docs.length === 0) {
session._id = sessionId
await this.db.post(session)
}
callback()
}
/**
*
* @param {[type]} sessionId [description]
* @param {Function} callback [description]
* @return {[type]} [description]
*/
async get(sessionId, callback)
{
const result = await this.db.find({
'selector': {
'_id': sessionId
}
})
let session = null
if (result.docs.length > 0) {
session = result.docs[0]
}
callback(null, session)
}
/**
*
* @param {[type]} sessionId [description]
* @param {Function} callback [description]
* @return {[type]} [description]
*/
async destroy(sessionId, callback)
{
const result = await this.db.find({
'selector': {
'_id': sessionId
}
})
if (result.docs.length > 0) {
await this.db.remove(result.docs[0])
}
callback()
}
}
/**
*
*
*
*/
const loginSchema = {
schema: {
body: {
username: { type: 'string' },
password: { type: 'string' }
},
response: {
200: {
type: 'object',
properties: {
token: { type: 'string' }
}
}
}
}
}
/**
* create Plugin
*
*
*/
function plugin(fastify, options, next) {
{
// create cookie
fastify
.register(fastifyCookie)
.register(fastifySession, {
secret: options.secret,
cookieName: 'session',
cookie: {
path: '/',
maxAge: options.secret,
secure: true,
httpOnly: true,
sameSite: 'Strict'
},
store: new PouchdbStore()
})
/**
* route: logout user and destroy session
*
*
*/
fastify.get('/logout', async function(request, response)
{
request.destroySession(() => {
response.redirect('/')
})
})
/**
* route: auth
*
* @param {object} request
* @param {object} response
*
*/
fastify.post('/auth', loginSchema, async function (request, reply)
{
let { username, password } = request.body
// strip crap from strings
username = DOMPurify.sanitize(username)
password = DOMPurify.sanitize(password)
const userRepository = new UserRepository()
const user = await userRepository.findOneByUsername(username)
// add header for json
reply.header('Content-Type', 'application/json; charset=utf-8')
// user not found
if (!user) {
return reply
.code(404)
.send()
}
// password wrong
if (!bcrypt.compareSync(password, user.password)) {
return reply
.code(401)
.send()
}
// setting session to store and set cookie
request.sessionStore.set(request.session.sessionId, request.session, async function() {
user.sessionId = request.session.sessionId
await userRepository.update(user)
// send 200 and send set-token
reply
.code(200)
.send()
})
})
done()
}
module.exports = plugin
Loading…
Cancel
Save