WIP
test / test (push) Failing after 38s Details

This commit is contained in:
Luca Bilke 2024-06-26 19:51:18 +02:00
parent 8d25de682a
commit 1b22ce6d22
No known key found for this signature in database
GPG Key ID: C9E851809C1A5BDE
9 changed files with 135 additions and 72 deletions

View File

@ -8,27 +8,10 @@ gleam test # Run the tests
gleam shell # Run an Erlang shell
```
## Flow
### Upload
take file upload
-> get hash of file
-> test against CSAM hash list
-> generate UUID
-> point UUID at hash of file
-> save file if hash doesn't exist
-> return UUID
### Download
take file UUID
-> search for UUID in table and get hash
-> return file if hash exists
## TODO
- [] Handle file upload
- [] Handle file download
- [] Testing against CSAM hash list
- [] Logging IPs (up and down) of detected CSAM uploads
- [X] Handle link GET
- [X] Handle link POST
- [] Handle file POST
- [] Handle file GET
- [] Web Frontend

View File

@ -1,8 +1,13 @@
import envoy
import gleam/int
import gleam/pgo
import gleam/result.{unwrap}
import wisp
pub type Context {
Context(db: pgo.Connection, config: Config)
}
pub type Config {
Config(
port: Int,

View File

@ -1,12 +1,12 @@
import app/config.{type Config}
import app/web.{type Context}
import app/config.{type Context}
import app/web
import app/web/file
import app/web/link
import app/web/root
import wisp.{type Request, type Response}
pub fn handle_request(req: Request, config: Config) -> Response {
use req: Request, ctx: Context <- web.middleware(req, config)
pub fn handle_request(req: Request, ctx: Context) -> Response {
use req: Request <- web.middleware(req)
case wisp.path_segments(req) {
["f", ..] -> file.handle_request(req, ctx)

View File

@ -1,5 +1,3 @@
import app/config.{type Config}
import gleam/pgo
import wisp.{type Request, type Response}
pub const html_head = "
@ -18,27 +16,13 @@ pub const html_tail = "
</html>
"
pub type Context {
Context(db: pgo.Connection, config: Config)
}
pub fn middleware(
req: Request,
config: Config,
handle_request: fn(Request, Context) -> Response,
handle_request: fn(Request) -> Response,
) -> Response {
let req = wisp.method_override(req)
use <- wisp.log_request(req)
use <- wisp.rescue_crashes
use req <- wisp.handle_head(req)
let db =
pgo.connect(
pgo.Config(
..pgo.default_config(),
host: config.postgres_host,
database: config.postgres_db,
pool_size: config.postgres_pool_size,
),
)
handle_request(req, Context(db, config))
handle_request(req)
}

View File

@ -1,43 +1,49 @@
import app/web.{type Context}
import app/config.{type Context}
import gleam/dynamic
import gleam/http.{Get, Post}
import gleam/list
import gleam/pgo
import gleam/result
import gleam/string
import wisp.{type Request, type Response}
const schema = "
CREATE TABLE IF NOT EXISTS `FileReference` (
nanoid TEXT <<key>>
PathID INT
);
CREATE TABLE IF NOT EXISTS `FilePath` (
PathID INT <<key>>
md5_hash BLOB
banned BOOLEAN
CREATE TABLE IF NOT EXISTS \"File\" (
nanoid VARCHAR(21) PRIMARY KEY,
md5_hash BYTEA
);
"
type File {
Reference(md5_hash: BitArray, nanoid: String)
Path(md5_hash: String, banned: Bool)
pub type File {
File(md5_hash: BitArray, nanoid: String)
}
fn hash_to_path(hash: String) -> List(String) {
pub fn prepare_database(ctx: Context) -> Result(Nil, pgo.QueryError) {
pgo.execute(schema, ctx.db, [], dynamic.dynamic)
|> result.map(fn(_) { Nil })
}
pub fn hash_to_path(hash: String) -> List(String) {
list.new()
|> list.append([hash |> string.slice(0, 2)])
|> list.append([hash |> string.slice(2, 2)])
|> list.append([hash |> string.slice(4, { hash |> string.length } - 4)])
}
pub fn handle_request(req: Request, ctx: Context) -> Response {
todo
}
fn serve_file(req, uuid: String) -> Response {
fn handle_nano_id(req: Request, nano_id: String, ct: Context) -> Response {
use <- wisp.require_method(req, Get)
todo as "implement serve_file"
}
fn receive_file(req: Request) -> Response {
fn handle_root(req: Request, ctx: Context) -> Response {
use <- wisp.require_method(req, Post)
todo as "implement receive_file"
}
pub fn handle_request(req: Request, ctx: Context) -> Response {
case wisp.path_segments(req) {
["f"] -> handle_root(req, ctx)
["f", nano_id] -> handle_nano_id(req, nano_id, ctx)
_ -> wisp.not_found()
}
}

View File

@ -1,4 +1,4 @@
import app/web.{type Context}
import app/config.{type Context}
import gleam/dynamic
import gleam/http.{Get, Post}
import gleam/int

View File

@ -1,14 +1,33 @@
import app/config
import app/config.{type Config, type Context, Context}
import app/router
import gleam/erlang/process
import gleam/pgo
import mist
import wisp
pub fn main() {
wisp.configure_logger()
let config = config.load_config_from_env()
fn with_context(config: Config, next: fn(Context) -> Nil) -> Nil {
let db =
pgo.connect(
pgo.Config(
..pgo.default_config(),
host: config.postgres_host,
database: config.postgres_db,
pool_size: config.postgres_pool_size,
),
)
let ctx = Context(db: db, config: config)
let entrypoint = router.handle_request(_, config)
next(ctx)
ctx.db |> pgo.disconnect
}
pub fn main() {
let config = config.load_config_from_env()
use ctx: Context <- with_context(config)
wisp.configure_logger()
let entrypoint = router.handle_request(_, ctx)
let assert Ok(_) =
wisp.mist_handler(entrypoint, config.secret_key_base)
|> mist.new

View File

@ -0,0 +1,68 @@
import app/config.{type Context, Config, Context}
import app/web/file
import gleam/dynamic
import gleam/option.{None, Some}
import gleam/pgo
import gleam/string
import gleeunit/should
const test_config = Config(
port: 8080,
max_bytes: 52_428_800,
url_root: "http://localhost",
secret_key_base: "cDv6ikrODZKjKbwSBBwspXInc61MYpCzQ8My9gW2QpQg3Y3lT7IJ5RJlzRN5HZK0",
postgres_db: "dumptruck",
postgres_user: "dumptruck",
postgres_password: "dumptruck",
postgres_host: "localhost",
postgres_pool_size: 15,
postgres_port: 5432,
)
fn with_context(testcase: fn(Context) -> t) -> t {
let ctx =
Context(
db: pgo.Config(
..pgo.default_config(),
database: test_config.postgres_db,
password: test_config.postgres_password |> Some,
user: test_config.postgres_user,
host: test_config.postgres_host,
pool_size: test_config.postgres_pool_size,
port: 5432,
)
|> pgo.connect,
config: test_config,
)
case file.prepare_database(ctx) {
Ok(_) -> {
let ret = testcase(ctx)
ctx.db |> pgo.disconnect
ret
}
Error(e) -> {
e |> string.inspect |> panic
}
}
}
pub fn null_test() {
use ctx <- with_context()
pgo.execute(
"select $1",
ctx.db,
[pgo.null()],
dynamic.element(0, dynamic.optional(dynamic.int)),
)
|> should.equal(Ok(pgo.Returned(count: 1, rows: [None])))
}
pub fn hash_to_path_test() {
"f7b478961451483b8c251c788750d5ef"
|> file.hash_to_path
|> should.equal(["f7", "b4", "78961451483b8c251c788750d5ef"])
}

View File

@ -1,8 +1,6 @@
import app/config.{Config}
import app/web.{type Context, Context}
import app/config.{type Context, Config, Context}
import app/web/link.{Link}
import gleam/dynamic
import gleam/io
import gleam/option.{None, Some}
import gleam/pgo
import gleam/result