Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

0.0.4 #12

Merged
merged 2 commits into from
Aug 8, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 2 additions & 1 deletion .env.example
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
HEYA=true #Used to check if the .env file is loaded, THIS IS REQUIRED!

PORT=7999 #The port LTS runs on.
UI_PORT=7998 #The port the WebUI runs on.
ENABLE_WEBUI=true #Enables the WebUI, where you can manage your buckets and files. The UI is available at /

WELCOME_MESSAGE=LittleTinyStorage #The message that is shown when visiting /
Expand All @@ -11,7 +12,7 @@ DELETE_BUCKETS_WHEN_ENV_REMOVED=false #DANGEROUS DANGEROUS DATA LOSS DANGEROUS A
CORS_ALLOWED_ORIGINS=* #The origins that are allowed to access the API, seperated by a comma

API_KEY=pleasehackme #The api key is used to authenticate with the API
BUCKETS=bucket1,bucket2 #The buckets that are created, seperated by a comma (yes, you can edit this after initialization)
BUCKETS=bucket1,bucket2 #The buckets that are created, seperated by a comma (yes, you can edit this after initialization)

#Per bucket configuration

Expand Down
3 changes: 0 additions & 3 deletions .github/workflows/test.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -2,9 +2,6 @@ name: Tests

on:
workflow_dispatch:
push:
branches:
- main
pull_request:
branches:
- main
Expand Down
3 changes: 2 additions & 1 deletion .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -2,4 +2,5 @@ node_modules/
.env
data/
out
dist/
dist/
web/
1 change: 1 addition & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@ A little tiny file storage server, for the people that use S3 when they really d
- Directory listings
- Store on your own server
- Completely configured using environment variables
- A web interface for managing your buckets and files

## Setup

Expand Down
71 changes: 69 additions & 2 deletions package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

7 changes: 5 additions & 2 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -3,9 +3,11 @@
"author": "dandandev",
"type": "module",
"dependencies": {
"anzip": "^0.2.0",
"dotenv": "^16.4.5",
"jose": "^5.6.3",
"kleur": "^4.1.5"
"kleur": "^4.1.5",
"mime": "^4.0.4"
},
"scripts": {
"build:windows": "bun build dist/index.js --compile --outfile out/littletinystorage-win --minify --sourcemap --target bun-windows-x64",
Expand All @@ -21,6 +23,7 @@
},
"devDependencies": {
"@types/jsonwebtoken": "^9.0.6",
"@types/node": "^22.1.0"
"@types/node": "^22.1.0",
"@types/yauzl": "^2.10.3"
}
}
29 changes: 29 additions & 0 deletions src/anzip.d.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
declare module "anzip" {
interface Options {
pattern?: RegExp;
disableSave?: boolean;
outputContent?: boolean;
entryHandler?: Promise<boolean>;
outputPath?: string;
flattenPath?: boolean;
disableOutput?: boolean;
rules?: Options[];
}

interface File {
name: string;
directory: string;
saved: boolean;
content: Buffer;
error: Error;
}

interface Result {
duration: number;
files: File[];
}

function anzip(filename: string, opts?: Options): Promise<Result>;

export = anzip;
}
5 changes: 3 additions & 2 deletions src/http.ts
Original file line number Diff line number Diff line change
Expand Up @@ -26,9 +26,10 @@ const directoryTemplate = `

export function createServer(
requestListener: http.RequestListener,
port: number
port: number,
name: string
) {
console.log(`🚀 LTS is running on port ${port}`);
console.log(`🚀 ${name} is running on port ${port}`);
return http.createServer(requestListener).listen(port);
}

Expand Down
34 changes: 33 additions & 1 deletion src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,8 @@ import * as path from "path";
import * as https from "https";
import { buckets, dataDir } from "./utils.js";
import { createServer, requestListener } from "./http.js";
import { requestListener as uiRequestListener } from "./ui.js";
import anzip from "anzip";

//Initial setup
if (!process.env.HEYA) {
Expand All @@ -32,6 +34,34 @@ if (!process.env.HEYA) {
}
}

//WebUI
if (process.env.ENABLE_WEBUI === "true") {
const webExists = fs.existsSync("./web");
if (!webExists) {
console.log("Downloading web interface...");
//delete old zip
if (fs.existsSync("./webui.zip")) fs.unlinkSync("./webui.zip");
fetch(
"https://github.com/dandanthedev/littletinystorage-webui/releases/latest/download/build.zip"
)
.then((res) => res.arrayBuffer())
.then((buffer) => {
fs.writeFileSync("./webui.zip", Buffer.from(buffer));
console.log("Web interface downloaded, extracting...");
anzip("webui.zip").then(() => {
console.log(
"Web interface extracted, deleting zip file and renaming build folder..."
);
fs.unlinkSync("./webui.zip");
setTimeout(() => {
//todo: find better solution
fs.renameSync("./build", "./web");
}, 100);
});
});
}
}

//Create data directory
if (!fs.existsSync(dataDir)) {
fs.mkdirSync(dataDir);
Expand Down Expand Up @@ -75,5 +105,7 @@ if (process.env.DELETE_BUCKETS_WHEN_ENV_REMOVED === "true") {
}

const port = parseInt(process.env.PORT ?? "7999");
const uiPort = parseInt(process.env.UI_PORT ?? "7998");

createServer(requestListener, port);
createServer(requestListener, port, "LTS");
createServer(uiRequestListener, uiPort, "WebUI");
34 changes: 34 additions & 0 deletions src/ui.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
import { IncomingMessage, ServerResponse } from "http";
import * as fs from "fs";
import * as path from "path";
import * as mime from "mime";
import { resp } from "./utils.js";

export const requestListener = async function (
req: IncomingMessage,
res: ServerResponse
) {
if (!req.url) return;
//send files from ./web directory
let fileName = req.url.replace("/", "");
if (!fileName) fileName = "index.html";

console.log(fileName);

const exts = ["js", "css", "png"];

if (
fileName &&
!fileName.endsWith(".html") &&
!exts.map((ext) => fileName.endsWith("." + ext)).includes(true) //most cursed thing i've ever seen but it works
) {
fileName = fileName + ".html";
if (!fs.existsSync(path.join("./web", fileName))) return resp(res, 404);
}

if (fileName) {
const file = fs.createReadStream(path.join("./web", fileName));
const mimeType = mime.default.getType(fileName);
return resp(res, 200, file, "file", mimeType ?? undefined);
}
};
7 changes: 4 additions & 3 deletions src/utils.ts
Original file line number Diff line number Diff line change
Expand Up @@ -11,19 +11,20 @@ export function resp(
res: ServerResponse,
status: number,
body?: ResponseBody,
type?: ResponseType
type?: ResponseType,
mimeType?: string
) {
if (typeof body === "object" && !(body instanceof ReadStream))
body = JSON.stringify(body);

if (type) {
if (type && !mimeType) {
if (type === "json") res.setHeader("Content-Type", "application/json");
if (type === "html") res.setHeader("Content-Type", "text/html");
if (type === "file")
res.setHeader("Content-Type", "application/octet-stream");
}
if (mimeType) res.setHeader("Content-Type", mimeType);
res.writeHead(status);

if (body instanceof ReadStream) {
body.pipe(res);
} else {
Expand Down
3 changes: 2 additions & 1 deletion tsconfig.json
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@
"allowImportingTsExtensions": false,
"lib": ["ES2021.String"],
"moduleDetection": "force",
"removeComments": true
"removeComments": true,
"allowSyntheticDefaultImports": true
}
}
Loading