fet: Add changes lol

Signed-off-by: Florian BOUILLON <f.bouillon@aptatio.com>
This commit is contained in:
2023-06-28 17:30:18 +02:00
parent 9530be5c43
commit ff07f8f4a5
24 changed files with 656 additions and 511 deletions

2
src/env.d.ts vendored
View File

@ -22,7 +22,7 @@ declare namespace App {
authKey?: string
responseBuilder: {
body(body: string | Buffer | object | null | undefined): this
headers(headers: HeadersInit ): this
headers(headers: Record<string, string>): this
addHeader(key: string, value: string): this
addHeaders(headers: Record<string, string>): this
removeHeader(key: string): this

View File

@ -1,4 +1,5 @@
---
import { WifiOff } from 'lucide-astro'
export interface Props {
title: string;
}
@ -16,21 +17,21 @@ const { title } = Astro.props;
<meta name="generator" content={Astro.generator} />
<title>{title}</title>
</head>
<body>
<slot />
<body class="bg-gray-50">
<aside class="fixed top-0 left-0 z-40 w-64 p-4 h-screen bg-white border-r-2 border-gray-100">
<div class="mb-2 flex">
<img src="/logo.svg" class="w-1/2" alt="FI3D Logo">
<WifiOff class='pokemon' />
</div>
<ul class="space-y-2 font-medium">
<li class="p-4 w-full bg-red-100 hover:bg-red-200 cursor-pointer text-center">Item</li>
</ul>
</aside>
<div class="p-4 sm:ml-64">
<slot />
</div>
</body>
</html>
<style is:global>
:root {
--accent: 124, 58, 237;
--accent-gradient: linear-gradient(45deg, rgb(var(--accent)), #da62c4 30%, white 60%);
}
html {
font-family: system-ui, sans-serif;
background-color: #F6F6F6;
}
code {
font-family: Menlo, Monaco, Lucida Console, Liberation Mono, DejaVu Sans Mono,
Bitstream Vera Sans Mono, Courier New, monospace;
}
</style>

3
src/libs/README.md Normal file
View File

@ -0,0 +1,3 @@
# Libs
Globally independent objects/classes/functions that MUST be unit testable by themselve

View File

@ -1,6 +1,6 @@
import { objectLoop } from '@dzeio/object-util'
import StatusCode from './HTTP/StatusCode'
import { buildRFC7807 } from './RFCs/RFC7807'
import StatusCode from './StatusCode'
import ResponseBuilder from './ResponseBuilder'
interface StorageItem {
pointsRemaining: number
@ -33,36 +33,40 @@ export default class RateLimiter {
private storage: Record<string, StorageItem> = {}
public constructor(
private points = RateLimiter.points,
private timeSpan = RateLimiter.timeSpan
) {}
public consume(key: string, value: number = 1): Response | RateLimitHeaders {
let item = this.storage[key]
const now = (new Date().getTime() / 1000)
if (!item) {
item = {
pointsRemaining: RateLimiter.points,
timeReset: now + RateLimiter.timeSpan
pointsRemaining: this.points,
timeReset: now + this.timeSpan
}
}
if (item.timeReset <= now) {
item.timeReset = now + RateLimiter.timeSpan
item.pointsRemaining = RateLimiter.points
item.timeReset = now + this.timeSpan
item.pointsRemaining = this.points
}
item.pointsRemaining -= value
this.storage[key] = item
const headers: RateLimitHeaders = {
"X-RateLimit-Limit": RateLimiter.points.toFixed(0),
"X-RateLimit-Limit": this.points.toFixed(0),
"X-RateLimit-Remaining": Math.max(item.pointsRemaining, 0).toFixed(0),
"X-RateLimit-Reset": item.timeReset.toFixed(0)
}
if (item.pointsRemaining < 0) {
const res = new ResponseBuilder()
const resp = buildRFC7807({
type: '/docs/error/rate-limited',
status: StatusCode.TOO_MANY_REQUESTS,
title: 'You are being rate limited as you have done too many requests to the server'
})
resp.headers.append('Retry-After', (item.timeReset - now).toFixed(0))
objectLoop(headers, (value, key) => {
resp.headers.append(key, value)
})
}, res)
res.addHeader('Retry-After', (item.timeReset - now).toFixed(0))
res.addHeaders(headers as any)
return resp
}
return headers

View File

@ -18,18 +18,14 @@ export default class ResponseBuilder {
return this
}
private _headers: Headers = new Headers()
public headers(headers: HeadersInit ) {
if (headers instanceof Headers) {
this._headers = headers
} else {
this._headers = new Headers(headers)
}
private _headers: Record<string, string> = {}
public headers(headers: Record<string, string>) {
this._headers = headers
return this
}
public addHeader(key: string, value: string) {
this._headers.append(key, value)
this._headers[key] = value
return this
}
@ -41,7 +37,7 @@ export default class ResponseBuilder {
}
public removeHeader(key: string) {
this._headers.delete(key)
delete this._headers[key]
return this
}

View File

@ -4,7 +4,7 @@
* @returns a number if parsing happened correctly or undefined
*/
function parseNumber(str: string): number | undefined {
if (!/^(\d|\.)+$/g.test(str)) {
if (!/^-?(\d|\.)+$/g.test(str)) {
return undefined
}
const float = parseFloat(str)
@ -53,10 +53,10 @@ export function getParams(data: string) {
const lines = data.split('\n').filter((it) => it.startsWith(';') && it.includes('='))
// create the config object
const obj: Record<string, string | number> = {}
// loop through eacj config
// loop through each config
for (const line of lines) {
// get its key and value
const [key, value] = line.split('=', 2).map((it) => it.slice(1).trim())
const [key, value] = line.slice(1).split(/ *= */, 2).map((it) => it.trim())
// sip if it has no key or value
if (!key || !value) {
continue
@ -78,10 +78,10 @@ export function getParams(data: string) {
if (offset > 0) {
realKey = `${realKey}_${offset}`
}
// detect key collisions
if (obj[realKey] && obj[realKey] !== realValue) {
throw new Error(`Key collision ${key}=${realValue} ${realKey}=${obj[realKey]}`)
}
// detect key collisions (it will never happens with the while above)
// if (obj[realKey] && obj[realKey] !== realValue) {
// throw new Error(`Key collision ${key}=${realValue} ${realKey}=${obj[realKey]}`)
// }
// set the value to the key
obj[realKey] = realValue
// transform the time to a number of seconds

View File

@ -1,5 +1,3 @@
import Client from './Client'
/**
* the Dao is the object that connect the Database or source to the application layer
*

View File

@ -3,7 +3,13 @@ import Passthrough from '../components/Passthrough.astro'
import Layout from '../layouts/Layout.astro'
import DaoFactory from '../models/DaoFactory'
const user = await DaoFactory.get('user').get('648f81f857503c7d29465318')
const session = DaoFactory.get('session').getSession(Astro.request)
if (!session) {
return Astro.redirect('/')
}
const user = await DaoFactory.get('user').get(session.userId)
const list = await DaoFactory.get('apiKey').findAll({
user: user!.id
})

View File

@ -7,12 +7,9 @@ import { spawn } from 'node:child_process'
import fs from 'node:fs/promises'
import os from 'node:os'
import path from 'node:path'
import StatusCode from '../../../../libs/HTTP/StatusCode'
import { buildRFC7807 } from '../../../../libs/RFCs/RFC7807'
import RateLimiter from '../../../../libs/RateLimiter'
import ResponseBuilder from '../../../../libs/ResponseBuilder'
import StatusCode from '../../../../libs/StatusCode'
import { getParams } from '../../../../libs/gcodeUtils'
import { validateAuth } from '../../../../libs/validateAuth'
import DaoFactory from '../../../../models/DaoFactory'
interface SliceError {
@ -20,7 +17,6 @@ interface SliceError {
output: Array<string>
}
let tmpDir: string
/**

View File

@ -1,7 +1,7 @@
import { objectOmit } from '@dzeio/object-util'
import type { APIRoute } from 'astro'
import StatusCode from '../../../../../../libs/HTTP/StatusCode'
import { buildRFC7807 } from '../../../../../../libs/RFCs/RFC7807'
import StatusCode from '../../../../../../libs/StatusCode'
import DaoFactory from '../../../../../../models/DaoFactory'
export const post: APIRoute = async ({ params, request, locals }) => {

View File

@ -1,6 +1,6 @@
import type { APIRoute } from 'astro'
import crypto from 'node:crypto'
import StatusCode from '../../../../../../libs/StatusCode'
import StatusCode from '../../../../../../libs/HTTP/StatusCode'
import DaoFactory from '../../../../../../models/DaoFactory'
export const post: APIRoute = async ({ params, locals }) => {

View File

@ -1,6 +1,6 @@
import type { APIRoute } from 'astro'
import StatusCode from '../../../../libs/HTTP/StatusCode'
import { buildRFC7807 } from '../../../../libs/RFCs/RFC7807'
import StatusCode from '../../../../libs/StatusCode'
export const get: APIRoute = async ({ locals }) => {
return locals.responseBuilder

View File

@ -1,7 +1,7 @@
---
import Layout from '../../layouts/Layout.astro'
import { getEntry } from 'astro:content'
import StatusCode from '../../libs/StatusCode'
import StatusCode from '../../libs/HTTP/StatusCode'
const page = Astro.params.page