All work on icebox

This commit is contained in:
mmcwilliams 2025-03-31 12:00:12 -04:00
parent 19b077e6cf
commit 8919032849
49 changed files with 2944 additions and 622 deletions

2
.gitignore vendored
View File

@ -1,3 +1,5 @@
node_modules node_modules
.env .env
watch/* watch/*
data/*
*.DS_Store

1
default.env Normal file
View File

@ -0,0 +1 @@
DATABASE_FILE=data/icebox.sqlite

3
dist/env/index.d.ts vendored Normal file
View File

@ -0,0 +1,3 @@
export declare function envString(variable: string, defaultString: string): string;
export declare function envFloat(variable: string, defaultFloat: number): number;
export declare function envInt(variable: string, defaultInt: number): number;

16
dist/env/index.js vendored Normal file
View File

@ -0,0 +1,16 @@
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.envString = envString;
exports.envFloat = envFloat;
exports.envInt = envInt;
function envString(variable, defaultString) {
return typeof process.env[variable] !== 'undefined' ? process.env[variable] : defaultString;
}
function envFloat(variable, defaultFloat) {
return typeof process.env[variable] !== 'undefined' ? parseFloat(process.env[variable]) : defaultFloat;
}
function envInt(variable, defaultInt) {
return typeof process.env[variable] !== 'undefined' ? parseInt(process.env[variable]) : defaultInt;
}
module.exports = { envString, envFloat, envInt };
//# sourceMappingURL=index.js.map

1
dist/env/index.js.map vendored Normal file
View File

@ -0,0 +1 @@
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/env/index.ts"],"names":[],"mappings":";;AAAA,8BAEC;AAED,4BAEC;AAED,wBAEC;AAVD,SAAgB,SAAS,CAAE,QAAiB,EAAE,aAAsB;IACnE,OAAO,OAAO,OAAO,CAAC,GAAG,CAAC,QAAQ,CAAC,KAAK,WAAW,CAAC,CAAC,CAAC,OAAO,CAAC,GAAG,CAAC,QAAQ,CAAC,CAAC,CAAC,CAAC,aAAa,CAAC;AAC7F,CAAC;AAED,SAAgB,QAAQ,CAAE,QAAiB,EAAE,YAAqB;IACjE,OAAO,OAAO,OAAO,CAAC,GAAG,CAAC,QAAQ,CAAC,KAAK,WAAW,CAAC,CAAC,CAAC,UAAU,CAAC,OAAO,CAAC,GAAG,CAAC,QAAQ,CAAC,CAAC,CAAC,CAAC,CAAC,YAAY,CAAC;AACxG,CAAC;AAED,SAAgB,MAAM,CAAE,QAAiB,EAAE,UAAmB;IAC7D,OAAO,OAAO,OAAO,CAAC,GAAG,CAAC,QAAQ,CAAC,KAAK,WAAW,CAAC,CAAC,CAAC,QAAQ,CAAC,OAAO,CAAC,GAAG,CAAC,QAAQ,CAAC,CAAC,CAAC,CAAC,CAAC,UAAU,CAAC;AACpG,CAAC;AAED,MAAM,CAAC,OAAO,GAAG,EAAE,SAAS,EAAE,QAAQ,EAAE,MAAM,EAAE,CAAC"}

11
dist/file/index.d.ts vendored Normal file
View File

@ -0,0 +1,11 @@
interface FileInfo {
success: boolean;
hash?: string;
size?: number;
created?: number;
error?: Error | undefined;
}
export declare class File {
static info(filePath: string): Promise<FileInfo>;
}
export {};

56
dist/file/index.js vendored Normal file
View File

@ -0,0 +1,56 @@
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.File = void 0;
const promises_1 = require("fs/promises");
const size_1 = require("../size");
const hash_1 = require("../hash");
class File {
static async info(filePath) {
let success = false;
let hash;
let fileSize;
let created;
let stats;
let error;
try {
hash = await hash_1.Hashes.file(filePath);
}
catch (err) {
error = err;
return {
success,
error
};
}
try {
fileSize = await (0, size_1.size)(filePath);
}
catch (err) {
error = err;
return {
success,
error
};
}
try {
stats = await (0, promises_1.stat)(filePath);
created = stats.birthtimeMs;
}
catch (err) {
error = err;
return {
success,
error
};
}
success = true;
return {
success,
hash,
size: fileSize,
created
};
}
}
exports.File = File;
//# sourceMappingURL=index.js.map

1
dist/file/index.js.map vendored Normal file
View File

@ -0,0 +1 @@
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/file/index.ts"],"names":[],"mappings":";;;AAAA,0CAAmC;AAGnC,kCAA+B;AAC/B,kCAAiC;AAUjC,MAAa,IAAI;IACT,MAAM,CAAC,KAAK,CAAC,IAAI,CAAE,QAAiB;QAC1C,IAAI,OAAO,GAAa,KAAK,CAAC;QAC9B,IAAI,IAAa,CAAC;QAClB,IAAI,QAAiB,CAAC;QACtB,IAAI,OAAgB,CAAC;QACrB,IAAI,KAAa,CAAC;QAClB,IAAI,KAAa,CAAC;QAElB,IAAI,CAAC;YACJ,IAAI,GAAG,MAAM,aAAM,CAAC,IAAI,CAAC,QAAQ,CAAC,CAAC;QACpC,CAAC;QAAC,OAAO,GAAG,EAAE,CAAC;YACd,KAAK,GAAG,GAAY,CAAC;YACrB,OAAO;gBACN,OAAO;gBACP,KAAK;aACL,CAAC;QACH,CAAC;QAED,IAAI,CAAC;YACJ,QAAQ,GAAG,MAAM,IAAA,WAAI,EAAC,QAAQ,CAAC,CAAA;QAChC,CAAC;QAAC,OAAO,GAAG,EAAE,CAAC;YACd,KAAK,GAAG,GAAY,CAAC;YACrB,OAAO;gBACN,OAAO;gBACP,KAAK;aACL,CAAC;QACH,CAAC;QAED,IAAI,CAAC;YACJ,KAAK,GAAG,MAAM,IAAA,eAAI,EAAC,QAAQ,CAAC,CAAC;YAC7B,OAAO,GAAG,KAAK,CAAC,WAAW,CAAC;QAC7B,CAAC;QAAC,OAAO,GAAG,EAAE,CAAC;YACd,KAAK,GAAG,GAAY,CAAC;YACrB,OAAO;gBACN,OAAO;gBACP,KAAK;aACL,CAAC;QACH,CAAC;QAED,OAAO,GAAG,IAAI,CAAC;QACf,OAAO;YACN,OAAO;YACP,IAAI;YACJ,IAAI,EAAG,QAAQ;YACf,OAAO;SACP,CAAC;IACH,CAAC;CACD;AAhDD,oBAgDC"}

4
dist/hash/index.d.ts vendored Normal file
View File

@ -0,0 +1,4 @@
export declare class Hashes {
static file(path: string): Promise<string>;
static string(str: string): string;
}

23
dist/hash/index.js vendored Normal file
View File

@ -0,0 +1,23 @@
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.Hashes = void 0;
const crypto_1 = require("crypto");
const fs_1 = require("fs");
class Hashes {
static async file(path) {
return new Promise((resolve, reject) => {
const hashSum = (0, crypto_1.createHash)('sha256');
const stream = (0, fs_1.createReadStream)(path);
stream.on('error', (err) => reject(err));
stream.on('data', (chunk) => hashSum.update(chunk));
stream.on('end', () => resolve(hashSum.digest('hex')));
});
}
static string(str) {
const sha = (0, crypto_1.createHash)('sha256').update(str);
return sha.digest('hex');
}
}
exports.Hashes = Hashes;
module.exports = { Hashes };
//# sourceMappingURL=index.js.map

1
dist/hash/index.js.map vendored Normal file
View File

@ -0,0 +1 @@
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/hash/index.ts"],"names":[],"mappings":";;;AAAA,mCAA0C;AAC1C,2BAAsC;AAEtC,MAAa,MAAM;IACX,MAAM,CAAC,KAAK,CAAC,IAAI,CAAE,IAAa;QACtC,OAAO,IAAI,OAAO,CAAC,CAAC,OAAkB,EAAE,MAAiB,EAAE,EAAE;YAC5D,MAAM,OAAO,GAAU,IAAA,mBAAU,EAAC,QAAQ,CAAC,CAAC;YAC5C,MAAM,MAAM,GAAS,IAAA,qBAAgB,EAAC,IAAI,CAAC,CAAC;YAC5C,MAAM,CAAC,EAAE,CAAC,OAAO,EAAE,CAAC,GAAW,EAAE,EAAE,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC,CAAC;YAC9C,MAAM,CAAC,EAAE,CAAC,MAAM,EAAE,CAAC,KAAc,EAAE,EAAE,CAAC,OAAO,CAAC,MAAM,CAAC,KAAK,CAAC,CAAC,CAAC;YAC7D,MAAM,CAAC,EAAE,CAAC,KAAK,EAAE,GAAG,EAAE,CAAC,OAAO,CAAC,OAAO,CAAC,MAAM,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC;QAC3D,CAAC,CAAC,CAAC;IACJ,CAAC;IAEM,MAAM,CAAC,MAAM,CAAE,GAAY;QACjC,MAAM,GAAG,GAAU,IAAA,mBAAU,EAAC,QAAQ,CAAC,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC;QACpD,OAAO,GAAG,CAAC,MAAM,CAAC,KAAK,CAAC,CAAC;IAC1B,CAAC;CACD;AAfD,wBAeC;AAED,MAAM,CAAC,OAAO,GAAG,EAAE,MAAM,EAAE,CAAC"}

1
dist/index.d.ts vendored
View File

@ -0,0 +1 @@
export {};

90
dist/index.js vendored
View File

@ -1,6 +1,79 @@
"use strict"; "use strict";
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
if (k2 === undefined) k2 = k;
var desc = Object.getOwnPropertyDescriptor(m, k);
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
desc = { enumerable: true, get: function() { return m[k]; } };
}
Object.defineProperty(o, k2, desc);
}) : (function(o, m, k, k2) {
if (k2 === undefined) k2 = k;
o[k2] = m[k];
}));
var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
Object.defineProperty(o, "default", { enumerable: true, value: v });
}) : function(o, v) {
o["default"] = v;
});
var __importStar = (this && this.__importStar) || (function () {
var ownKeys = function(o) {
ownKeys = Object.getOwnPropertyNames || function (o) {
var ar = [];
for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
return ar;
};
return ownKeys(o);
};
return function (mod) {
if (mod && mod.__esModule) return mod;
var result = {};
if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
__setModuleDefault(result, mod);
return result;
};
})();
var __importDefault = (this && this.__importDefault) || function (mod) {
return (mod && mod.__esModule) ? mod : { "default": mod };
};
Object.defineProperty(exports, "__esModule", { value: true });
const express_1 = __importDefault(require("express"));
const handlebars = __importStar(require("express-handlebars"));
const body_parser_1 = __importDefault(require("body-parser"));
const path_1 = require("path");
const env_1 = require("./env");
const log_1 = require("./log");
const PORT = (0, env_1.envInt)('PORT', 3835);
const viewsPath = (0, path_1.join)(__dirname, '../views');
const staticPath = (0, path_1.join)(__dirname, '../static');
const app = (0, express_1.default)();
const log = (0, log_1.createLog)('icebox');
const hbs = handlebars.create({
defaultLayout: 'main',
layoutsDir: (0, path_1.join)(viewsPath, './layouts'),
partialsDir: (0, path_1.join)(viewsPath, '/partials')
});
app.use(express_1.default.static(staticPath));
app.use(body_parser_1.default.urlencoded({ extended: true }));
app.engine('handlebars', hbs.engine);
app.set('view engine', 'handlebars');
app.set('views', viewsPath);
app.get('/', (req, res, next) => {
const data = {};
return res.render('home', data);
});
app.post('/lookup', (req, res, next) => {
const data = {
alert: {
class: 'primary',
message: 'Check your email. If one or more active download links are found they will be emailed to you.'
}
};
if (typeof req.body !== 'undefined') {
console.dir(req.body);
}
return res.render('home', data);
});
/* /*
import express from 'express';
import http from 'http'; import http from 'http';
import path from 'path'; import path from 'path';
import fs from 'fs'; import fs from 'fs';
@ -256,17 +329,8 @@ function cleanupSession(socketId: string): void {
console.log(`Cleaned up session for client ${socketId}`); console.log(`Cleaned up session for client ${socketId}`);
} }
// Start the server
server.listen(PORT, () => {
console.log(`Server running on port ${PORT}`);
// Create files directory if it doesn't exist
const filesDir = path.join(__dirname, 'files');
if (!fs.existsSync(filesDir)) {
fs.mkdirSync(filesDir);
console.log('Created files directory');
}
});
*/ */
app.listen(PORT, () => {
log.info(`Server running on port ${PORT}`);
});
//# sourceMappingURL=index.js.map //# sourceMappingURL=index.js.map

2
dist/index.js.map vendored
View File

@ -1 +1 @@
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":";AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;EA6QE"} {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AACA,sDAA8B;AAC9B,+DAAiD;AAEjD,8DAAqC;AACrC,+BAA4B;AAG5B,+BAA+B;AAC/B,+BAAkC;AAElC,MAAM,IAAI,GAAY,IAAA,YAAM,EAAC,MAAM,EAAE,IAAI,CAAC,CAAC;AAC3C,MAAM,SAAS,GAAY,IAAA,WAAI,EAAC,SAAS,EAAE,UAAU,CAAC,CAAC;AACvD,MAAM,UAAU,GAAY,IAAA,WAAI,EAAC,SAAS,EAAE,WAAW,CAAC,CAAC;AAEzD,MAAM,GAAG,GAAa,IAAA,iBAAO,GAAE,CAAC;AAChC,MAAM,GAAG,GAAY,IAAA,eAAS,EAAC,QAAQ,CAAC,CAAC;AACzC,MAAM,GAAG,GAAmC,UAAU,CAAC,MAAM,CAAC;IAC1D,aAAa,EAAE,MAAM;IACrB,UAAU,EAAE,IAAA,WAAI,EAAC,SAAS,EAAE,WAAW,CAAC;IACxC,WAAW,EAAE,IAAA,WAAI,EAAC,SAAS,EAAE,WAAW,CAAC;CAC5C,CAAC,CAAC;AAEH,GAAG,CAAC,GAAG,CAAC,iBAAO,CAAC,MAAM,CAAC,UAAU,CAAC,CAAC,CAAC;AACpC,GAAG,CAAC,GAAG,CAAC,qBAAU,CAAC,UAAU,CAAC,EAAE,QAAQ,EAAE,IAAI,EAAE,CAAC,CAAC,CAAC;AACnD,GAAG,CAAC,MAAM,CAAC,YAAY,EAAE,GAAG,CAAC,MAAM,CAAC,CAAC;AACrC,GAAG,CAAC,GAAG,CAAC,aAAa,EAAE,YAAY,CAAC,CAAC;AACrC,GAAG,CAAC,GAAG,CAAC,OAAO,EAAE,SAAS,CAAC,CAAC;AAE5B,GAAG,CAAC,GAAG,CAAC,GAAG,EAAE,CAAC,GAAa,EAAE,GAAc,EAAE,IAAmB,EAAE,EAAE;IAChE,MAAM,IAAI,GAAS,EAAE,CAAC;IACtB,OAAO,GAAG,CAAC,MAAM,CAAC,MAAM,EAAE,IAAI,CAAC,CAAC;AACpC,CAAC,CAAC,CAAC;AAEH,GAAG,CAAC,IAAI,CAAC,SAAS,EAAE,CAAC,GAAa,EAAE,GAAc,EAAE,IAAmB,EAAE,EAAE;IACvE,MAAM,IAAI,GAAS;QACf,KAAK,EAAG;YACJ,KAAK,EAAE,SAAS;YAChB,OAAO,EAAG,+FAA+F;SAC5G;KACJ,CAAC;IACF,IAAI,OAAO,GAAG,CAAC,IAAI,KAAK,WAAW,EAAE,CAAC;QAClC,OAAO,CAAC,GAAG,CAAC,GAAG,CAAC,IAAI,CAAC,CAAC;IAC1B,CAAC;IACD,OAAO,GAAG,CAAC,MAAM,CAAC,MAAM,EAAE,IAAI,CAAC,CAAC;AACpC,CAAC,CAAC,CAAA;AAEF;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;EAgQE;AAEF,GAAG,CAAC,MAAM,CAAC,IAAI,EAAE,GAAG,EAAE;IAClB,GAAG,CAAC,IAAI,CAAC,0BAA0B,IAAI,EAAE,CAAC,CAAC;AAC/C,CAAC,CAAC,CAAC"}

View File

@ -1 +1 @@
export {}; import 'dotenv/config';

40
dist/monitor/index.js vendored
View File

@ -3,6 +3,7 @@ var __importDefault = (this && this.__importDefault) || function (mod) {
return (mod && mod.__esModule) ? mod : { "default": mod }; return (mod && mod.__esModule) ? mod : { "default": mod };
}; };
Object.defineProperty(exports, "__esModule", { value: true }); Object.defineProperty(exports, "__esModule", { value: true });
require("dotenv/config");
const upload_1 = require("../upload"); const upload_1 = require("../upload");
const log_1 = require("../log"); const log_1 = require("../log");
const chokidar_1 = __importDefault(require("chokidar")); const chokidar_1 = __importDefault(require("chokidar"));
@ -30,4 +31,43 @@ async function main() {
}); });
} }
main().catch(log.error); main().catch(log.error);
/*
const minioResult = await uploadFileToS3('/path/to/your/file.pdf', {
region: 'us-east-1', // Region can be any string for MinIO
endpoint: 'https://minio.your-domain.com',
bucketName: 'your-minio-bucket',
credentials: {
accessKeyId: 'your-minio-access-key',
secretAccessKey: 'your-minio-secret-key'
},
forcePathStyle: true, // Important for most S3-compatible services
expirationSeconds: 3600
});
// Example 3: DigitalOcean Spaces
const spacesResult = await uploadFileToS3('/path/to/your/file.pdf', {
region: 'nyc3', // DigitalOcean datacenter region
endpoint: 'https://nyc3.digitaloceanspaces.com',
bucketName: 'your-space-name',
credentials: {
accessKeyId: 'your-spaces-key',
secretAccessKey: 'your-spaces-secret'
},
forcePathStyle: true,
expirationSeconds: 7200 // 2 hours
});
// Example 4: Wasabi
const wasabiResult = await uploadFileToS3('/path/to/your/file.pdf', {
region: 'us-east-1',
endpoint: 'https://s3.wasabisys.com',
bucketName: 'your-wasabi-bucket',
credentials: {
accessKeyId: 'your-wasabi-access-key',
secretAccessKey: 'your-wasabi-secret-key'
},
forcePathStyle: true,
expirationSeconds: 86400 // 24 hours
});
*/
//# sourceMappingURL=index.js.map //# sourceMappingURL=index.js.map

View File

@ -1 +1 @@
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/monitor/index.ts"],"names":[],"mappings":";;;;;AAAA,sCAAmC;AACnC,gCAAmC;AAEnC,wDAAgC;AAIhC,MAAM,UAAU,GAAY,IAAI,CAAC,CAAC,QAAQ;AAE1C,MAAM,GAAG,GAAY,IAAA,eAAS,EAAC,OAAO,CAAC,CAAC;AAExC,KAAK,UAAU,aAAa,CAAE,QAAiB;IAC9C,MAAM,MAAM,GAAc;QACzB,MAAM,EAAE,WAAW;QACnB,UAAU,EAAE,kBAAkB;QAC9B,iBAAiB,EAAE,UAAU;KAC7B,CAAC;IAEF,GAAG,CAAC,IAAI,CAAC,mBAAmB,QAAQ,EAAE,CAAC,CAAC;IACxC,MAAM,MAAM,GAAkB,MAAM,IAAA,eAAM,EAAC,MAAM,EAAE,QAAQ,EAAE,MAAM,CAAC,CAAC;IAErE,IAAI,MAAM,CAAC,OAAO,EAAE,CAAC;QACpB,GAAG,CAAC,IAAI,CAAC,yCAAyC,CAAC,CAAC;QACpD,GAAG,CAAC,IAAI,CAAC,cAAc,EAAE,MAAM,CAAC,GAAG,CAAC,CAAC;IACtC,CAAC;SAAM,CAAC;QACP,GAAG,CAAC,KAAK,CAAC,gBAAgB,EAAE,MAAM,CAAC,KAAK,CAAC,CAAC;IAC3C,CAAC;AACF,CAAC;AAED,KAAK,UAAU,IAAI;IAClB,kBAAQ,CAAC,KAAK,CAAC,SAAS,EAAE,EAAE,OAAO,EAAE,cAAc,EAAE,CAAC,CAAC,EAAE,CAAC,KAAK,EAAE,CAAC,KAAW,EAAE,IAAa,EAAE,EAAE;QAC/F,GAAG,CAAC,IAAI,CAAC,QAAQ,IAAI,4BAA4B,KAAK,EAAE,CAAC,CAAC;IAC3D,CAAC,CAAC,CAAC;AACJ,CAAC;AAED,IAAI,EAAE,CAAC,KAAK,CAAC,GAAG,CAAC,KAAK,CAAC,CAAC"} {"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/monitor/index.ts"],"names":[],"mappings":";;;;;AAAA,yBAAuB;AAEvB,sCAAmC;AACnC,gCAAmC;AAEnC,wDAAgC;AAIhC,MAAM,UAAU,GAAY,IAAI,CAAC,CAAC,QAAQ;AAE1C,MAAM,GAAG,GAAY,IAAA,eAAS,EAAC,OAAO,CAAC,CAAC;AAExC,KAAK,UAAU,aAAa,CAAE,QAAiB;IAC9C,MAAM,MAAM,GAAc;QACzB,MAAM,EAAE,WAAW;QACnB,UAAU,EAAE,kBAAkB;QAC9B,iBAAiB,EAAE,UAAU;KAC7B,CAAC;IAEF,GAAG,CAAC,IAAI,CAAC,mBAAmB,QAAQ,EAAE,CAAC,CAAC;IACxC,MAAM,MAAM,GAAkB,MAAM,IAAA,eAAM,EAAC,MAAM,EAAE,QAAQ,EAAE,MAAM,CAAC,CAAC;IAErE,IAAI,MAAM,CAAC,OAAO,EAAE,CAAC;QACpB,GAAG,CAAC,IAAI,CAAC,yCAAyC,CAAC,CAAC;QACpD,GAAG,CAAC,IAAI,CAAC,cAAc,EAAE,MAAM,CAAC,GAAG,CAAC,CAAC;IACtC,CAAC;SAAM,CAAC;QACP,GAAG,CAAC,KAAK,CAAC,gBAAgB,EAAE,MAAM,CAAC,KAAK,CAAC,CAAC;IAC3C,CAAC;AACF,CAAC;AAED,KAAK,UAAU,IAAI;IAClB,kBAAQ,CAAC,KAAK,CAAC,SAAS,EAAE,EAAE,OAAO,EAAE,cAAc,EAAE,CAAC,CAAC,EAAE,CAAC,KAAK,EAAE,CAAC,KAAW,EAAE,IAAa,EAAE,EAAE;QAC/F,GAAG,CAAC,IAAI,CAAC,QAAQ,IAAI,4BAA4B,KAAK,EAAE,CAAC,CAAC;IAC3D,CAAC,CAAC,CAAC;AACJ,CAAC;AAED,IAAI,EAAE,CAAC,KAAK,CAAC,GAAG,CAAC,KAAK,CAAC,CAAC;AAExB;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;EAsCE"}

1
dist/shortid/index.d.ts vendored Normal file
View File

@ -0,0 +1 @@
export declare function shortid(): string;

10
dist/shortid/index.js vendored Normal file
View File

@ -0,0 +1,10 @@
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.shortid = shortid;
function shortid() {
let firstPart = (Math.random() * 46656) | 0;
let secondPart = (Math.random() * 46656) | 0;
return ("000" + firstPart.toString(36)).slice(-3) + ("000" + secondPart.toString(36)).slice(-3);
}
module.exports = { shortid };
//# sourceMappingURL=index.js.map

1
dist/shortid/index.js.map vendored Normal file
View File

@ -0,0 +1 @@
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/shortid/index.ts"],"names":[],"mappings":";;AAAA,0BAIC;AAJD,SAAgB,OAAO;IACnB,IAAI,SAAS,GAAY,CAAC,IAAI,CAAC,MAAM,EAAE,GAAG,KAAK,CAAC,GAAG,CAAC,CAAC;IACrD,IAAI,UAAU,GAAY,CAAC,IAAI,CAAC,MAAM,EAAE,GAAG,KAAK,CAAC,GAAG,CAAC,CAAC;IACtD,OAAO,CAAC,KAAK,GAAG,SAAS,CAAC,QAAQ,CAAC,EAAE,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,GAAG,CAAC,KAAK,GAAG,UAAU,CAAC,QAAQ,CAAC,EAAE,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,CAAC;AACpG,CAAC;AAED,MAAM,CAAC,OAAO,GAAG,EAAE,OAAO,EAAE,CAAC"}

1
dist/size/index.d.ts vendored Normal file
View File

@ -0,0 +1 @@
export declare function size(filePath: string): Promise<number>;

10
dist/size/index.js vendored Normal file
View File

@ -0,0 +1,10 @@
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.size = size;
const promises_1 = require("fs/promises");
async function size(filePath) {
const stats = await (0, promises_1.stat)(filePath);
return stats.size;
}
module.exports = { size };
//# sourceMappingURL=index.js.map

1
dist/size/index.js.map vendored Normal file
View File

@ -0,0 +1 @@
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/size/index.ts"],"names":[],"mappings":";;AAGA,oBAGC;AAND,0CAAmC;AAG5B,KAAK,UAAU,IAAI,CAAE,QAAiB;IAC5C,MAAM,KAAK,GAAW,MAAM,IAAA,eAAI,EAAC,QAAQ,CAAC,CAAC;IAC3C,OAAO,KAAK,CAAC,IAAI,CAAC;AACnB,CAAC;AAED,MAAM,CAAC,OAAO,GAAG,EAAE,IAAI,EAAE,CAAC"}

1
dist/tmp/index.d.ts vendored Normal file
View File

@ -0,0 +1 @@
export declare function tmp(ext?: string, prefix?: string, fileName?: string | null): string;

17
dist/tmp/index.js vendored Normal file
View File

@ -0,0 +1,17 @@
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.tmp = tmp;
const os_1 = require("os");
const path_1 = require("path");
const crypto_1 = require("crypto");
const TMP = (0, os_1.tmpdir)();
function tmp(ext = '', prefix = '3d-tmp-', fileName = null) {
let path = null;
if (fileName === null) {
fileName = prefix + (0, crypto_1.randomBytes)(32).toString('hex') + ext;
}
path = (0, path_1.join)(TMP, fileName);
return path;
}
module.exports = { tmp };
//# sourceMappingURL=index.js.map

1
dist/tmp/index.js.map vendored Normal file
View File

@ -0,0 +1 @@
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/tmp/index.ts"],"names":[],"mappings":";;AAMA,kBAOC;AAbD,2BAA4B;AAC5B,+BAA4B;AAC5B,mCAAqC;AAErC,MAAM,GAAG,GAAY,IAAA,WAAM,GAAE,CAAC;AAE9B,SAAgB,GAAG,CAAE,MAAe,EAAE,EAAE,SAAkB,SAAS,EAAE,WAA2B,IAAI;IACnG,IAAI,IAAI,GAAmB,IAAI,CAAC;IAChC,IAAI,QAAQ,KAAK,IAAI,EAAE,CAAC;QACvB,QAAQ,GAAG,MAAM,GAAG,IAAA,oBAAW,EAAC,EAAE,CAAC,CAAC,QAAQ,CAAC,KAAK,CAAC,GAAG,GAAG,CAAC;IAC3D,CAAC;IACD,IAAI,GAAG,IAAA,WAAI,EAAC,GAAG,EAAE,QAAQ,CAAC,CAAC;IAC3B,OAAO,IAAI,CAAC;AACb,CAAC;AAED,MAAM,CAAC,OAAO,GAAG,EAAE,GAAG,EAAE,CAAC"}

View File

@ -2,6 +2,12 @@ interface S3Config {
region: string; region: string;
bucketName: string; bucketName: string;
expirationSeconds: number; expirationSeconds: number;
endpoint?: string;
credentials?: {
accessKeyId: string;
secretAccessKey: string;
};
forcePathStyle?: boolean;
} }
interface UploadResult { interface UploadResult {
success: boolean; success: boolean;

14
dist/upload/index.js vendored
View File

@ -33,9 +33,19 @@ async function upload(id, filePath, config) {
error: `Error reading file: ${error.message}` error: `Error reading file: ${error.message}`
}; };
} }
const s3Client = new client_s3_1.S3Client({ const s3ClientOptions = {
region: config.region region: config.region
}); };
if (config.endpoint) {
s3ClientOptions.endpoint = config.endpoint;
}
if (config.credentials) {
s3ClientOptions.credentials = config.credentials;
}
if (config.forcePathStyle !== undefined) {
s3ClientOptions.forcePathStyle = config.forcePathStyle;
}
const s3Client = new client_s3_1.S3Client(s3ClientOptions);
try { try {
const uploadCommand = new client_s3_1.PutObjectCommand({ const uploadCommand = new client_s3_1.PutObjectCommand({
Bucket: config.bucketName, Bucket: config.bucketName,

View File

@ -1 +1 @@
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/upload/index.ts"],"names":[],"mappings":";;AA0BA,wBA2DC;AArFD,kDAAkF;AAClF,wEAA6D;AAC7D,2BAAkD;AAClD,+BAAkD;AAiBlD;;;;;GAKG;AACI,KAAK,UAAU,MAAM,CAAE,EAAU,EAAE,QAAgB,EAAE,MAAgB;IAC3E,MAAM,QAAQ,GAAY,IAAA,cAAO,EAAC,QAAQ,CAAC,CAAC;IAC5C,MAAM,QAAQ,GAAY,IAAA,eAAQ,EAAC,QAAQ,CAAC,CAAC;IAC7C,MAAM,OAAO,GAAa,IAAA,cAAO,EAAC,QAAQ,CAAC,CAAC;IAC5C,MAAM,GAAG,GAAW,GAAG,EAAE,GAAG,OAAO,EAAE,CAAC;IAEtC,IAAI,CAAC,GAAG,EAAE,CAAC;QACV,OAAO;YACN,OAAO,EAAE,KAAK;YACd,KAAK,EAAE,sBAAsB;SAC7B,CAAC;IACH,CAAC;IAED,IAAI,UAAuB,CAAC;IAE5B,IAAI,CAAC;QACJ,UAAU,GAAG,IAAA,qBAAgB,EAAC,QAAQ,CAAC,CAAC;IACzC,CAAC;IAAC,OAAO,GAAG,EAAE,CAAC;QACd,MAAM,KAAK,GAAU,GAAY,CAAC;QAClC,OAAO;YACN,OAAO,EAAE,KAAK;YACd,KAAK,EAAE,uBAAuB,KAAK,CAAC,OAAO,EAAE;SAC7C,CAAC;IACH,CAAC;IAED,MAAM,QAAQ,GAAa,IAAI,oBAAQ,CAAC;QACvC,MAAM,EAAE,MAAM,CAAC,MAAM;KACrB,CAAC,CAAC;IAEH,IAAI,CAAC;QACJ,MAAM,aAAa,GAAqB,IAAI,4BAAgB,CAAC;YAC5D,MAAM,EAAE,MAAM,CAAC,UAAU;YACzB,GAAG,EAAE,GAAG;YACR,IAAI,EAAE,UAAU;SAChB,CAAC,CAAC;QAEH,MAAM,QAAQ,CAAC,IAAI,CAAC,aAAa,CAAC,CAAC;QAEnC,MAAM,UAAU,GAAqB,IAAI,4BAAgB,CAAC;YACzD,MAAM,EAAE,MAAM,CAAC,UAAU;YACzB,GAAG,EAAE,GAAG;SACR,CAAC,CAAC;QAEH,MAAM,GAAG,GAAW,MAAM,IAAA,mCAAY,EAAC,QAAQ,EAAE,UAAU,EAAE;YAC5D,SAAS,EAAE,MAAM,CAAC,iBAAiB;SACnC,CAAC,CAAC;QAEH,OAAO;YACN,OAAO,EAAE,IAAI;YACb,GAAG;YACH,GAAG;SACH,CAAC;IACH,CAAC;IAAC,OAAO,GAAG,EAAE,CAAC;QACd,MAAM,KAAK,GAAW,GAAY,CAAC;QACnC,OAAO;YACN,OAAO,EAAE,KAAK;YACd,KAAK,EAAE,0BAA0B,KAAK,CAAC,OAAO,EAAE;SAChD,CAAC;IACH,CAAC;AACF,CAAC;AAED,MAAM,CAAC,OAAO,GAAG,EAAE,MAAM,EAAE,CAAC"} {"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/upload/index.ts"],"names":[],"mappings":";;AA+BA,wBAyEC;AAxGD,kDAAkF;AAClF,wEAA6D;AAC7D,2BAAkD;AAClD,+BAAkD;AAsBlD;;;;;GAKG;AACI,KAAK,UAAU,MAAM,CAAE,EAAU,EAAE,QAAgB,EAAE,MAAgB;IACxE,MAAM,QAAQ,GAAY,IAAA,cAAO,EAAC,QAAQ,CAAC,CAAC;IAC5C,MAAM,QAAQ,GAAY,IAAA,eAAQ,EAAC,QAAQ,CAAC,CAAC;IAC7C,MAAM,OAAO,GAAa,IAAA,cAAO,EAAC,QAAQ,CAAC,CAAC;IAC5C,MAAM,GAAG,GAAW,GAAG,EAAE,GAAG,OAAO,EAAE,CAAC;IAEtC,IAAI,CAAC,GAAG,EAAE,CAAC;QACP,OAAO;YACH,OAAO,EAAE,KAAK;YACd,KAAK,EAAE,sBAAsB;SAChC,CAAC;IACN,CAAC;IAED,IAAI,UAAuB,CAAC;IAE5B,IAAI,CAAC;QACD,UAAU,GAAG,IAAA,qBAAgB,EAAC,QAAQ,CAAC,CAAC;IAC5C,CAAC;IAAC,OAAO,GAAG,EAAE,CAAC;QACX,MAAM,KAAK,GAAU,GAAY,CAAC;QAClC,OAAO;YACH,OAAO,EAAE,KAAK;YACd,KAAK,EAAE,uBAAuB,KAAK,CAAC,OAAO,EAAE;SAChD,CAAC;IACN,CAAC;IAED,MAAM,eAAe,GAAwB;QACzC,MAAM,EAAE,MAAM,CAAC,MAAM;KACxB,CAAC;IAEF,IAAI,MAAM,CAAC,QAAQ,EAAE,CAAC;QAClB,eAAe,CAAC,QAAQ,GAAG,MAAM,CAAC,QAAQ,CAAC;IAC/C,CAAC;IAED,IAAI,MAAM,CAAC,WAAW,EAAE,CAAC;QACrB,eAAe,CAAC,WAAW,GAAG,MAAM,CAAC,WAAW,CAAC;IACrD,CAAC;IAED,IAAI,MAAM,CAAC,cAAc,KAAK,SAAS,EAAE,CAAC;QACtC,eAAe,CAAC,cAAc,GAAG,MAAM,CAAC,cAAc,CAAC;IAC3D,CAAC;IAED,MAAM,QAAQ,GAAa,IAAI,oBAAQ,CAAC,eAAe,CAAC,CAAC;IAEzD,IAAI,CAAC;QACD,MAAM,aAAa,GAAqB,IAAI,4BAAgB,CAAC;YACzD,MAAM,EAAE,MAAM,CAAC,UAAU;YACzB,GAAG,EAAE,GAAG;YACR,IAAI,EAAE,UAAU;SACnB,CAAC,CAAC;QAEH,MAAM,QAAQ,CAAC,IAAI,CAAC,aAAa,CAAC,CAAC;QAEnC,MAAM,UAAU,GAAqB,IAAI,4BAAgB,CAAC;YACtD,MAAM,EAAE,MAAM,CAAC,UAAU;YACzB,GAAG,EAAE,GAAG;SACX,CAAC,CAAC;QAEH,MAAM,GAAG,GAAY,MAAM,IAAA,mCAAY,EAAC,QAAQ,EAAE,UAAU,EAAE;YAC1D,SAAS,EAAE,MAAM,CAAC,iBAAiB;SACtC,CAAC,CAAC;QAEH,OAAO;YACH,OAAO,EAAE,IAAI;YACb,GAAG;YACH,GAAG;SACN,CAAC;IACN,CAAC;IAAC,OAAO,GAAG,EAAE,CAAC;QACX,MAAM,KAAK,GAAW,GAAY,CAAC;QACnC,OAAO;YACH,OAAO,EAAE,KAAK;YACd,KAAK,EAAE,0BAA0B,KAAK,CAAC,OAAO,EAAE;SACnD,CAAC;IACN,CAAC;AACL,CAAC;AAED,MAAM,CAAC,OAAO,GAAG,EAAE,MAAM,EAAE,CAAC"}

1811
package-lock.json generated

File diff suppressed because it is too large Load Diff

View File

@ -21,13 +21,19 @@
"@aws-sdk/client-s3": "^3.777.0", "@aws-sdk/client-s3": "^3.777.0",
"@aws-sdk/s3-request-presigner": "^3.777.0", "@aws-sdk/s3-request-presigner": "^3.777.0",
"bcrypt": "^5.1.1", "bcrypt": "^5.1.1",
"body-parser": "^2.2.0",
"chokidar": "^4.0.3", "chokidar": "^4.0.3",
"dotenv": "^16.4.7", "dotenv": "^16.4.7",
"express": "^4.18.2", "express": "^4.18.2",
"express-handlebars": "^8.0.1",
"lodash": "^4.17.21", "lodash": "^4.17.21",
"moment": "^2.30.1",
"socket.io": "^4.7.2", "socket.io": "^4.7.2",
"socket.io-client": "^4.7.2", "socket.io-client": "^4.7.2",
"sqlite3": "^5.1.7",
"stripe": "^17.7.0",
"triple-beam": "^1.4.1", "triple-beam": "^1.4.1",
"uuid": "^11.1.0",
"winston": "^3.17.0" "winston": "^3.17.0"
}, },
"devDependencies": { "devDependencies": {

10
scripts/db.sh Normal file
View File

@ -0,0 +1,10 @@
#!/bin/bash
source .env
if [[ ! -f ${DATABASE_FILE} ]]; then
echo "Please define DATABASE_FILE in the .env file"
exit 1
fi
cat sql/setup.sql | sqlite3 ${DATABASE_FILE}

View File

@ -1,24 +1,43 @@
CREATE TABLE IF NOT EXISTS files { CREATE TABLE IF NOT EXISTS files (
id TEXT PRIMARY KEY, id TEXT PRIMARY KEY,
filename TEXT, filename TEXT NOT NULL,
original TEXT, original TEXT NOT NULL,
archive TEXT, archive TEXT,
paths TEXT, paths TEXT,
hash TEXT, hash TEXT NOT NULL,
size INTEGER, size INTEGER NOT NULL,
created INTEGER, created INTEGER NOT NULL
created_str TEXT );
};
CREATE TABLE IF NOT EXISTS access { CREATE TABLE IF NOT EXISTS access (
id TEXT PRIMARY KEY,
slug TEXT UNIQUE NOT NULL,
file TEXT NOT NULL,
user TEXT,
created INTEGER NOT NULL,
expires INTEGER NOT NULL,
paid INTEGER DEFAULT 0,
url TEXT UNIQUE NOT NULL,
service TEXT,
downloads INTEGER DEFAULT 0,
FOREIGN KEY(file) REFERENCES files(id),
FOREIGN KEY(user) REFERENCES users(id)
);
CREATE TABLE IF NOT EXISTS metadata (
id TEXT PRIMARY KEY, id TEXT PRIMARY KEY,
file TEXT REFERENCES files(id), file TEXT REFERENCES files(id),
created INTEGER, type TEXT,
created_str TEXT, width INTEGER,
expires INTEGER, height INTEGER,
expires_str TEXT, length REAL,
paid INTEGER DEFAULT 0, format TEXT,
url TEXT UNIQUE, preview TEXT
service TEXT, );
downloads INTEGER DEFAULT 0
} CREATE TABLE IF NOT EXISTS users (
id TEXT PRIMARY KEY,
email TEXT UNIQUE,
name TEXT,
created INTEGER
);

73
src/file/index.ts Normal file
View File

@ -0,0 +1,73 @@
import { stat } from 'fs/promises';
import type { Stats } from 'fs';
import { basename, resolve } from 'path';
import { size } from '../size';
import { Hashes } from '../hash';
interface FileInfo {
success : boolean;
filename? : string;
original? : string;
hash? : string;
size? : number;
created? : number;
error? : Error | undefined;
}
export class File {
public static async info (filePath : string) : Promise<FileInfo> {
const original : string = resolve(filePath);
const filename : string = basename(filePath);
let success : boolean = false;
let hash : string;
let fileSize : number;
let created : number;
let stats : Stats;
let error : Error;
try {
hash = await Hashes.file(filePath);
} catch (err) {
error = err as Error;
return {
success,
error
};
}
try {
fileSize = await size(filePath)
} catch (err) {
error = err as Error;
return {
success,
error
};
}
try {
stats = await stat(filePath);
created = stats.birthtimeMs;
} catch (err) {
error = err as Error;
return {
success,
error
};
}
success = true;
return {
success,
filename,
original,
hash,
size : fileSize,
created
};
}
}
module.exports = { File };
export type { FileInfo };

View File

@ -1,8 +1,5 @@
import { createHash, Hash } from 'crypto'; import { createHash, Hash } from 'crypto';
import { createReadStream } from 'fs'; import { createReadStream } from 'fs';
import { unlink } from 'fs/promises';
import { exec } from 'child_process';
import { tmp } from '../tmp';
export class Hashes { export class Hashes {
public static async file (path : string) : Promise<string> { public static async file (path : string) : Promise<string> {
@ -19,41 +16,6 @@ export class Hashes {
const sha : Hash = createHash('sha256').update(str); const sha : Hash = createHash('sha256').update(str);
return sha.digest('hex'); return sha.digest('hex');
} }
public static async gcode (gcodePath : string) : Promise<string> {
const dest : string = tmp('.gcode', '3d-gcode-hash-');
const cmd : string = `cat "${gcodePath}" | grep -v '; generated by PrusaSlicer' > "${dest}"`
let hash : string;
try {
await Hashes.exec(cmd);
} catch (err) {
throw err;
}
try {
hash = await Hashes.file(dest);
} catch (err) {
throw err;
}
try {
await unlink(dest);
} catch (err) {
throw err;
}
return hash;
}
private static async exec (cmd : string) {
return new Promise((resolve : Function, reject : Function) => {
return exec(cmd, (err : Error, stdout : string | Buffer, stderr : string | Buffer) => {
if (err) return reject(err);
return resolve(true);
});
});
}
} }
module.exports = { Hashes }; module.exports = { Hashes };

View File

@ -1,13 +1,89 @@
import express from 'express'; import express from 'express';
import { envInt } from './env'; import * as handlebars from 'express-handlebars';
import type { Express, Request, Response, NextFunction } from 'express';
import bodyParser from 'body-parser';
import { join } from 'path'; import { join } from 'path';
import type { Logger } from 'winston';
const app = express(); import { envInt } from './env';
const PORT = process.env.PORT || 3000; import { createLog } from './log';
// Serve static files const PORT : number = envInt('PORT', 3835);
app.use(express.static(join(__dirname, 'public'))); const viewsPath : string = join(__dirname, '../views');
const staticPath : string = join(__dirname, '../static');
const app : Express = express();
const log : Logger = createLog('icebox');
const hbs : handlebars.ExpressHandlebars = handlebars.create({
defaultLayout: 'main',
layoutsDir: join(viewsPath, './layouts'),
partialsDir: join(viewsPath, '/partials')
});
app.use(express.static(staticPath));
app.use(bodyParser.urlencoded({ extended: true }));
app.engine('handlebars', hbs.engine);
app.set('view engine', 'handlebars');
app.set('views', viewsPath);
app.get('/', (req : Request, res : Response, next : NextFunction) => {
const data : any = {};
return res.render('home', data);
});
app.post('/lookup', async (req : Request, res : Response, next : NextFunction) => {
const data : any = {
alert : {
class: 'primary',
message : 'Check your email. If one or more active download links are found they will be emailed to you.'
}
};
if (typeof req.body !== 'undefined') {
if (typeof req.body['first-name'] !== 'undefined' && req.body['first-name'] !== '') {
//bot trap
log.warn(`Potential bot trapped: ${JSON.stringify(req.body)}`);
} else if (typeof req.body.email !== 'undefined' && req.body.email.trim() !== '') {
}
}
return res.render('home', data);
});
app.get('/file/:id', async (req : Request, res : Response, next : NextFunction) => {
const data : any = {};
data.file = {
filename : 'Test.mov'
};
if ( false ) {
data.alert = {
class : 'warning',
message : `This download link expired `
}
}
if ( false ) {
data.alert = {
class : 'danger',
message : `No download link was found with this ID`
};
return res.render('home', data);
}
return res.render('file', data);
});
app.get('/example.txt', (req : Request, res : Response, next : NextFunction) => {
return res.send('Test');
});
app.post('/file/:id/download', async (req : Request, res : Response, next : NextFunction) => {
const data : any = {};
const url : string = `http://localhost:${PORT}/example.txt`;
return res.redirect(307, url);
});
/* /*
import http from 'http'; import http from 'http';
@ -265,16 +341,8 @@ function cleanupSession(socketId: string): void {
console.log(`Cleaned up session for client ${socketId}`); console.log(`Cleaned up session for client ${socketId}`);
} }
// Start the server
server.listen(PORT, () => {
console.log(`Server running on port ${PORT}`);
// Create files directory if it doesn't exist
const filesDir = path.join(__dirname, 'files');
if (!fs.existsSync(filesDir)) {
fs.mkdirSync(filesDir);
console.log('Created files directory');
}
});
*/ */
app.listen(PORT, () => {
log.info(`Server running on port ${PORT}`);
});

View File

@ -2,22 +2,31 @@ import 'dotenv/config';
import { upload } from '../upload'; import { upload } from '../upload';
import { createLog } from '../log'; import { createLog } from '../log';
import { File } from '../file';
import chokidar from 'chokidar'; import chokidar from 'chokidar';
import type { Logger } from 'winston'; import type { Logger } from 'winston';
import type { UploadResult, S3Config } from '../upload'; import type { UploadResult, S3Config } from '../upload';
import type { FileInfo } from '../file';
const EXPIRATION : number = 3600; //1 hour const EXPIRATION : number = 3600; //1 hour
const log : Logger = createLog('files'); const log : Logger = createLog('files');
async function processUpload (filePath : string) { async function process (filePath : string) {
const config : S3Config = { const config : S3Config = {
region: 'us-east-1', region: 'us-east-1',
bucketName: 'your-bucket-name', bucketName: 'your-bucket-name',
expirationSeconds: EXPIRATION expirationSeconds: EXPIRATION
}; };
const fileInfo : FileInfo = await File.info(filePath);
if (!fileInfo.success) {
log.error(`Error processing file info`, fileInfo.error);
return;
}
log.info(`Started upload: ${filePath}`); log.info(`Started upload: ${filePath}`);
const result : UploadResult = await upload('test', filePath, config); const result : UploadResult = await upload('test', filePath, config);

7
src/shortid/index.ts Normal file
View File

@ -0,0 +1,7 @@
export function shortid () : string {
let firstPart : number = (Math.random() * 46656) | 0;
let secondPart : number = (Math.random() * 46656) | 0;
return ("000" + firstPart.toString(36)).slice(-3) + ("000" + secondPart.toString(36)).slice(-3);
}
module.exports = { shortid };

16
src/tmp/index.ts Normal file
View File

@ -0,0 +1,16 @@
import { tmpdir } from 'os';
import { join } from 'path';
import { randomBytes } from 'crypto';
const TMP : string = tmpdir();
export function tmp (ext : string = '', prefix : string = '3d-tmp-', fileName : string | null = null) : string {
let path : string | null = null;
if (fileName === null) {
fileName = prefix + randomBytes(32).toString('hex') + ext;
}
path = join(TMP, fileName);
return path;
}
module.exports = { tmp };

View File

@ -86,7 +86,7 @@ export async function upload (id: string, filePath: string, config: S3Config): P
Key: key Key: key
}); });
const url: string = await getSignedUrl(s3Client, getCommand, { const url : string = await getSignedUrl(s3Client, getCommand, {
expiresIn: config.expirationSeconds expiresIn: config.expirationSeconds
}); });

7
static/css/bootstrap.min.css vendored Normal file

File diff suppressed because one or more lines are too long

7
static/css/style.css Normal file
View File

@ -0,0 +1,7 @@
#lookupForm #first-name{
display: none;
}
footer{
text-align: center;
}

7
static/js/bootstrap.min.js vendored Normal file

File diff suppressed because one or more lines are too long

14
views/file.handlebars Normal file
View File

@ -0,0 +1,14 @@
<div id="download" class="row justify-content-md-center">
{{#if file}}
<div class="card col col-lg-6">
<div class="card-body">
<form action="download" method="POST" id="downloadForm">
<div>
<h4>{{file.filename}}</h4>
</div>
<button type="submit" class="btn btn-primary">Download</button>
</form>
</div>
</div>
{{/if}}
</div>

16
views/home.handlebars Normal file
View File

@ -0,0 +1,16 @@
<div id="home" class="row justify-content-md-center">
<div class="card col col-lg-6">
<div class="card-body">
<form action="/lookup" method="POST" id="lookupForm">
<div class="form-group">
<label for="email">Lookup </label>
<input type="email" class="form-control" name="email" id="email" aria-describedby="emailHelp" placeholder="Enter email address">
<small id="emailHelp" class="form-text text-muted">The email that your file was originally shared to.</small>
</div>
<input type="text" name="first-name" id="first-name" />
<button type="submit" class="btn btn-primary">Submit</button>
</form>
</div>
</div>
</div>

View File

@ -0,0 +1,30 @@
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<meta http-equiv="X-UA-Compatible" content="ie=edge">
{{#if title}}
<title>Icebox- {{title}}</title>
{{else}}
<title>Icebox</title>
{{/if}}
<link rel="stylesheet" href="/css/bootstrap.min.css" />
<link rel="stylesheet" href="/css/style.css" />
</head>
<body>
<div id="main" class="container-fluid">
{{> nav}}
<div style="height: 80px;"></div>
{{#if alert}}
{{> alert}}
{{/if}}
{{{body}}}
</div>
{{> footer}}
</body>
<script src="/js/bootstrap.min.js"></script>
</html>

View File

@ -0,0 +1,3 @@
<div class="alert alert-{{alert.class}}" role="alert">
{{alert.message}}
</div>

View File

@ -0,0 +1,5 @@
<footer class="container-fluid">
<p class="small">
&copy; <script>document.write(/\d{4}/.exec(Date())[0])</script>
</p
</footer>

View File

@ -0,0 +1,29 @@
<nav class="navbar fixed-top navbar-expand-md navbar-dark bg-primary mb-3">
<div class="flex-row d-flex">
<button type="button" class="navbar-toggler mr-2 " data-toggle="offcanvas" title="Toggle responsive left sidebar">
<span class="navbar-toggler-icon"></span>
</button>
<a class="navbar-brand" href="/" title="Home">Icebox</a>
</div>
<button class="navbar-toggler" type="button" data-toggle="collapse" data-target="#collapsingNavbar">
<span class="navbar-toggler-icon"></span>
</button>
<div class="navbar-collapse collapse" id="collapsingNavbar">
<ul class="navbar-nav">
<li class="nav-item active">
<a class="nav-link" href="/">Home <span class="sr-only">Home</span></a>
</li>
<!--
links
-->
</ul>
<ul class="navbar-nav ml-auto">
<!--<li class="nav-item">
<a class="nav-link" href="#myAlert" data-toggle="collapse">Alert</a>
</li>
<li class="nav-item">
<a class="nav-link" href="" data-target="#myModal" data-toggle="modal">About</a>
</li>-->
</ul>
</div>
</nav>