feat: rebrand Hemmelig to paste.es for cloudhost.es

- Set Spanish as default language with ephemeral/encrypted privacy focus
- Translate all user-facing strings and legal pages to Spanish
- Replace Norwegian flag with Spanish flag in footer
- Remove Hemmelig/terces.cloud links, add cloudhost.es sponsorship
- Rewrite PrivacyPage: zero data collection, ephemeral design emphasis
- Rewrite TermsPage: Spanish law, RGPD, paste.es/CloudHost.es references
- Update PWA manifest, HTML meta tags, package.json branding
- Rename webhook headers to X-Paste-Event / X-Paste-Signature
- Update API docs title and contact to paste.es / cloudhost.es

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
2026-02-24 09:30:19 +01:00
commit bc9f96cbd4
268 changed files with 45773 additions and 0 deletions

View File

@@ -0,0 +1,71 @@
-- CreateTable
CREATE TABLE "secrets" (
"id" BIGINT NOT NULL PRIMARY KEY,
"secret" TEXT NOT NULL,
"title" TEXT,
"views" INTEGER DEFAULT 1,
"password" TEXT,
"is_burnable" BOOLEAN DEFAULT false,
"created_at" DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP,
"expires_at" DATETIME,
"is_public" BOOLEAN DEFAULT false,
"ip_range" TEXT DEFAULT ''
);
-- CreateTable
CREATE TABLE "user" (
"id" TEXT NOT NULL PRIMARY KEY,
"name" TEXT NOT NULL,
"email" TEXT NOT NULL,
"emailVerified" BOOLEAN NOT NULL,
"image" TEXT,
"createdAt" DATETIME NOT NULL,
"updatedAt" DATETIME NOT NULL
);
-- CreateTable
CREATE TABLE "session" (
"id" TEXT NOT NULL PRIMARY KEY,
"expiresAt" DATETIME NOT NULL,
"token" TEXT NOT NULL,
"createdAt" DATETIME NOT NULL,
"updatedAt" DATETIME NOT NULL,
"ipAddress" TEXT,
"userAgent" TEXT,
"userId" TEXT NOT NULL,
CONSTRAINT "session_userId_fkey" FOREIGN KEY ("userId") REFERENCES "user" ("id") ON DELETE CASCADE ON UPDATE CASCADE
);
-- CreateTable
CREATE TABLE "account" (
"id" TEXT NOT NULL PRIMARY KEY,
"accountId" TEXT NOT NULL,
"providerId" TEXT NOT NULL,
"userId" TEXT NOT NULL,
"accessToken" TEXT,
"refreshToken" TEXT,
"idToken" TEXT,
"accessTokenExpiresAt" DATETIME,
"refreshTokenExpiresAt" DATETIME,
"scope" TEXT,
"password" TEXT,
"createdAt" DATETIME NOT NULL,
"updatedAt" DATETIME NOT NULL,
CONSTRAINT "account_userId_fkey" FOREIGN KEY ("userId") REFERENCES "user" ("id") ON DELETE CASCADE ON UPDATE CASCADE
);
-- CreateTable
CREATE TABLE "verification" (
"id" TEXT NOT NULL PRIMARY KEY,
"identifier" TEXT NOT NULL,
"value" TEXT NOT NULL,
"expiresAt" DATETIME NOT NULL,
"createdAt" DATETIME,
"updatedAt" DATETIME
);
-- CreateIndex
CREATE UNIQUE INDEX "user_email_key" ON "user"("email");
-- CreateIndex
CREATE UNIQUE INDEX "session_token_key" ON "session"("token");

View File

@@ -0,0 +1,26 @@
/*
Warnings:
- The primary key for the `secrets` table will be changed. If it partially fails, the table could be left without primary key constraint.
- You are about to drop the column `is_public` on the `secrets` table. All the data in the column will be lost.
*/
-- RedefineTables
PRAGMA defer_foreign_keys=ON;
PRAGMA foreign_keys=OFF;
CREATE TABLE "new_secrets" (
"id" TEXT NOT NULL PRIMARY KEY,
"secret" TEXT NOT NULL,
"title" TEXT,
"views" INTEGER DEFAULT 1,
"password" TEXT,
"is_burnable" BOOLEAN DEFAULT false,
"created_at" DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP,
"expires_at" DATETIME,
"ip_range" TEXT DEFAULT ''
);
INSERT INTO "new_secrets" ("created_at", "expires_at", "id", "ip_range", "is_burnable", "password", "secret", "title", "views") SELECT "created_at", "expires_at", "id", "ip_range", "is_burnable", "password", "secret", "title", "views" FROM "secrets";
DROP TABLE "secrets";
ALTER TABLE "new_secrets" RENAME TO "secrets";
PRAGMA foreign_keys=ON;
PRAGMA defer_foreign_keys=OFF;

View File

@@ -0,0 +1,25 @@
/*
Warnings:
- Added the required column `username` to the `user` table without a default value. This is not possible if the table is not empty.
*/
-- RedefineTables
PRAGMA defer_foreign_keys=ON;
PRAGMA foreign_keys=OFF;
CREATE TABLE "new_user" (
"id" TEXT NOT NULL PRIMARY KEY,
"name" TEXT NOT NULL,
"username" TEXT NOT NULL,
"email" TEXT NOT NULL,
"emailVerified" BOOLEAN NOT NULL,
"image" TEXT,
"createdAt" DATETIME NOT NULL,
"updatedAt" DATETIME NOT NULL
);
INSERT INTO "new_user" ("createdAt", "email", "emailVerified", "id", "image", "name", "updatedAt") SELECT "createdAt", "email", "emailVerified", "id", "image", "name", "updatedAt" FROM "user";
DROP TABLE "user";
ALTER TABLE "new_user" RENAME TO "user";
CREATE UNIQUE INDEX "user_email_key" ON "user"("email");
PRAGMA foreign_keys=ON;
PRAGMA defer_foreign_keys=OFF;

View File

@@ -0,0 +1,2 @@
-- AlterTable
ALTER TABLE "user" ADD COLUMN "displayUsername" TEXT;

View File

@@ -0,0 +1,26 @@
/*
Warnings:
- You are about to alter the column `expires_at` on the `secrets` table. The data in that column could be lost. The data in that column will be cast from `DateTime` to `Int`.
- Made the column `expires_at` on table `secrets` required. This step will fail if there are existing NULL values in that column.
*/
-- RedefineTables
PRAGMA defer_foreign_keys=ON;
PRAGMA foreign_keys=OFF;
CREATE TABLE "new_secrets" (
"id" TEXT NOT NULL PRIMARY KEY,
"secret" TEXT NOT NULL,
"title" TEXT,
"views" INTEGER DEFAULT 1,
"password" TEXT,
"is_burnable" BOOLEAN DEFAULT false,
"created_at" DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP,
"expires_at" INTEGER NOT NULL,
"ip_range" TEXT DEFAULT ''
);
INSERT INTO "new_secrets" ("created_at", "expires_at", "id", "ip_range", "is_burnable", "password", "secret", "title", "views") SELECT "created_at", "expires_at", "id", "ip_range", "is_burnable", "password", "secret", "title", "views" FROM "secrets";
DROP TABLE "secrets";
ALTER TABLE "new_secrets" RENAME TO "secrets";
PRAGMA foreign_keys=ON;
PRAGMA defer_foreign_keys=OFF;

View File

@@ -0,0 +1,27 @@
/*
Warnings:
- You are about to alter the column `secret` on the `secrets` table. The data in that column could be lost. The data in that column will be cast from `String` to `Binary`.
- You are about to alter the column `title` on the `secrets` table. The data in that column could be lost. The data in that column will be cast from `String` to `Binary`.
- Made the column `title` on table `secrets` required. This step will fail if there are existing NULL values in that column.
*/
-- RedefineTables
PRAGMA defer_foreign_keys=ON;
PRAGMA foreign_keys=OFF;
CREATE TABLE "new_secrets" (
"id" TEXT NOT NULL PRIMARY KEY,
"secret" BLOB NOT NULL,
"title" BLOB NOT NULL,
"views" INTEGER DEFAULT 1,
"password" TEXT,
"is_burnable" BOOLEAN DEFAULT false,
"created_at" DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP,
"expires_at" INTEGER NOT NULL,
"ip_range" TEXT DEFAULT ''
);
INSERT INTO "new_secrets" ("created_at", "expires_at", "id", "ip_range", "is_burnable", "password", "secret", "title", "views") SELECT "created_at", "expires_at", "id", "ip_range", "is_burnable", "password", "secret", "title", "views" FROM "secrets";
DROP TABLE "secrets";
ALTER TABLE "new_secrets" RENAME TO "secrets";
PRAGMA foreign_keys=ON;
PRAGMA defer_foreign_keys=OFF;

View File

@@ -0,0 +1,25 @@
/*
Warnings:
- You are about to alter the column `expires_at` on the `secrets` table. The data in that column could be lost. The data in that column will be cast from `Int` to `DateTime`.
*/
-- RedefineTables
PRAGMA defer_foreign_keys=ON;
PRAGMA foreign_keys=OFF;
CREATE TABLE "new_secrets" (
"id" TEXT NOT NULL PRIMARY KEY,
"secret" BLOB NOT NULL,
"title" BLOB NOT NULL,
"views" INTEGER DEFAULT 1,
"password" TEXT,
"is_burnable" BOOLEAN DEFAULT false,
"created_at" DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP,
"expires_at" DATETIME NOT NULL,
"ip_range" TEXT DEFAULT ''
);
INSERT INTO "new_secrets" ("created_at", "expires_at", "id", "ip_range", "is_burnable", "password", "secret", "title", "views") SELECT "created_at", "expires_at", "id", "ip_range", "is_burnable", "password", "secret", "title", "views" FROM "secrets";
DROP TABLE "secrets";
ALTER TABLE "new_secrets" RENAME TO "secrets";
PRAGMA foreign_keys=ON;
PRAGMA defer_foreign_keys=OFF;

View File

@@ -0,0 +1,21 @@
-- RedefineTables
PRAGMA defer_foreign_keys=ON;
PRAGMA foreign_keys=OFF;
CREATE TABLE "new_secrets" (
"id" TEXT NOT NULL PRIMARY KEY,
"secret" BLOB NOT NULL,
"title" BLOB NOT NULL,
"views" INTEGER DEFAULT 1,
"password" TEXT,
"is_burnable" BOOLEAN DEFAULT false,
"created_at" DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP,
"expires_at" DATETIME NOT NULL,
"ip_range" TEXT DEFAULT '',
"userId" TEXT,
CONSTRAINT "secrets_userId_fkey" FOREIGN KEY ("userId") REFERENCES "user" ("id") ON DELETE SET NULL ON UPDATE CASCADE
);
INSERT INTO "new_secrets" ("created_at", "expires_at", "id", "ip_range", "is_burnable", "password", "secret", "title", "views") SELECT "created_at", "expires_at", "id", "ip_range", "is_burnable", "password", "secret", "title", "views" FROM "secrets";
DROP TABLE "secrets";
ALTER TABLE "new_secrets" RENAME TO "secrets";
PRAGMA foreign_keys=ON;
PRAGMA defer_foreign_keys=OFF;

View File

@@ -0,0 +1,31 @@
-- CreateTable
CREATE TABLE "files" (
"id" TEXT NOT NULL PRIMARY KEY,
"filename" TEXT NOT NULL,
"path" TEXT NOT NULL,
"createdAt" DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP
);
-- RedefineTables
PRAGMA defer_foreign_keys=ON;
PRAGMA foreign_keys=OFF;
CREATE TABLE "new_secrets" (
"id" TEXT NOT NULL PRIMARY KEY,
"secret" BLOB NOT NULL,
"title" BLOB NOT NULL,
"views" INTEGER DEFAULT 1,
"password" TEXT,
"is_burnable" BOOLEAN DEFAULT false,
"created_at" DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP,
"expires_at" DATETIME NOT NULL,
"ip_range" TEXT DEFAULT '',
"userId" TEXT,
"fileId" TEXT,
CONSTRAINT "secrets_userId_fkey" FOREIGN KEY ("userId") REFERENCES "user" ("id") ON DELETE SET NULL ON UPDATE CASCADE,
CONSTRAINT "secrets_fileId_fkey" FOREIGN KEY ("fileId") REFERENCES "files" ("id") ON DELETE SET NULL ON UPDATE CASCADE
);
INSERT INTO "new_secrets" ("created_at", "expires_at", "id", "ip_range", "is_burnable", "password", "secret", "title", "userId", "views") SELECT "created_at", "expires_at", "id", "ip_range", "is_burnable", "password", "secret", "title", "userId", "views" FROM "secrets";
DROP TABLE "secrets";
ALTER TABLE "new_secrets" RENAME TO "secrets";
PRAGMA foreign_keys=ON;
PRAGMA defer_foreign_keys=OFF;

View File

@@ -0,0 +1,41 @@
/*
Warnings:
- You are about to drop the column `fileId` on the `secrets` table. All the data in the column will be lost.
*/
-- CreateTable
CREATE TABLE "_FileToSecrets" (
"A" TEXT NOT NULL,
"B" TEXT NOT NULL,
CONSTRAINT "_FileToSecrets_A_fkey" FOREIGN KEY ("A") REFERENCES "files" ("id") ON DELETE CASCADE ON UPDATE CASCADE,
CONSTRAINT "_FileToSecrets_B_fkey" FOREIGN KEY ("B") REFERENCES "secrets" ("id") ON DELETE CASCADE ON UPDATE CASCADE
);
-- RedefineTables
PRAGMA defer_foreign_keys=ON;
PRAGMA foreign_keys=OFF;
CREATE TABLE "new_secrets" (
"id" TEXT NOT NULL PRIMARY KEY,
"secret" BLOB NOT NULL,
"title" BLOB NOT NULL,
"views" INTEGER DEFAULT 1,
"password" TEXT,
"is_burnable" BOOLEAN DEFAULT false,
"created_at" DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP,
"expires_at" DATETIME NOT NULL,
"ip_range" TEXT DEFAULT '',
"userId" TEXT,
CONSTRAINT "secrets_userId_fkey" FOREIGN KEY ("userId") REFERENCES "user" ("id") ON DELETE SET NULL ON UPDATE CASCADE
);
INSERT INTO "new_secrets" ("created_at", "expires_at", "id", "ip_range", "is_burnable", "password", "secret", "title", "userId", "views") SELECT "created_at", "expires_at", "id", "ip_range", "is_burnable", "password", "secret", "title", "userId", "views" FROM "secrets";
DROP TABLE "secrets";
ALTER TABLE "new_secrets" RENAME TO "secrets";
PRAGMA foreign_keys=ON;
PRAGMA defer_foreign_keys=OFF;
-- CreateIndex
CREATE UNIQUE INDEX "_FileToSecrets_AB_unique" ON "_FileToSecrets"("A", "B");
-- CreateIndex
CREATE INDEX "_FileToSecrets_B_index" ON "_FileToSecrets"("B");

View File

@@ -0,0 +1,5 @@
-- AlterTable
ALTER TABLE "user" ADD COLUMN "banExpires" DATETIME;
ALTER TABLE "user" ADD COLUMN "banReason" TEXT;
ALTER TABLE "user" ADD COLUMN "banned" BOOLEAN DEFAULT false;
ALTER TABLE "user" ADD COLUMN "role" TEXT DEFAULT 'user';

View File

@@ -0,0 +1,28 @@
-- CreateTable
CREATE TABLE "instance_settings" (
"id" TEXT NOT NULL PRIMARY KEY,
"instanceName" TEXT DEFAULT 'Hemmelig Instance',
"instanceDescription" TEXT DEFAULT 'Secure secret sharing platform',
"allowRegistration" BOOLEAN DEFAULT true,
"requireEmailVerification" BOOLEAN DEFAULT false,
"maxSecretsPerUser" INTEGER DEFAULT 100,
"defaultSecretExpiration" INTEGER DEFAULT 72,
"maxSecretSize" INTEGER DEFAULT 1024,
"enforceHttps" BOOLEAN DEFAULT true,
"allowPasswordProtection" BOOLEAN DEFAULT true,
"allowIpRestriction" BOOLEAN DEFAULT true,
"maxPasswordAttempts" INTEGER DEFAULT 3,
"sessionTimeout" INTEGER DEFAULT 24,
"enableRateLimiting" BOOLEAN DEFAULT true,
"rateLimitRequests" INTEGER DEFAULT 100,
"rateLimitWindow" INTEGER DEFAULT 60,
"smtpHost" TEXT,
"smtpPort" INTEGER,
"smtpUsername" TEXT,
"smtpPassword" TEXT,
"smtpSecure" BOOLEAN DEFAULT true,
"fromEmail" TEXT,
"fromName" TEXT,
"createdAt" DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP,
"updatedAt" DATETIME NOT NULL
);

View File

@@ -0,0 +1,12 @@
-- CreateTable
CREATE TABLE "tracking" (
"id" TEXT NOT NULL PRIMARY KEY,
"eventType" TEXT NOT NULL,
"path" TEXT NOT NULL,
"userAgent" TEXT,
"ipAddress" TEXT,
"city" TEXT,
"country" TEXT,
"region" TEXT,
"createdAt" DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP
);

View File

@@ -0,0 +1,10 @@
/*
Warnings:
- You are about to drop the `tracking` table. If the table is not empty, all the data it contains will be lost.
*/
-- DropTable
PRAGMA foreign_keys=off;
DROP TABLE "tracking";
PRAGMA foreign_keys=on;

View File

@@ -0,0 +1,28 @@
/*
Warnings:
- Added the required column `salt` to the `secrets` table without a default value. This is not possible if the table is not empty.
*/
-- RedefineTables
PRAGMA defer_foreign_keys=ON;
PRAGMA foreign_keys=OFF;
CREATE TABLE "new_secrets" (
"id" TEXT NOT NULL PRIMARY KEY,
"secret" BLOB NOT NULL,
"title" BLOB NOT NULL,
"views" INTEGER DEFAULT 1,
"password" TEXT,
"salt" TEXT NOT NULL,
"is_burnable" BOOLEAN DEFAULT false,
"created_at" DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP,
"expires_at" DATETIME NOT NULL,
"ip_range" TEXT DEFAULT '',
"userId" TEXT,
CONSTRAINT "secrets_userId_fkey" FOREIGN KEY ("userId") REFERENCES "user" ("id") ON DELETE SET NULL ON UPDATE CASCADE
);
INSERT INTO "new_secrets" ("created_at", "expires_at", "id", "ip_range", "is_burnable", "password", "secret", "title", "userId", "views") SELECT "created_at", "expires_at", "id", "ip_range", "is_burnable", "password", "secret", "title", "userId", "views" FROM "secrets";
DROP TABLE "secrets";
ALTER TABLE "new_secrets" RENAME TO "secrets";
PRAGMA foreign_keys=ON;
PRAGMA defer_foreign_keys=OFF;

View File

@@ -0,0 +1,40 @@
/*
Warnings:
- You are about to drop the column `enforceHttps` on the `instance_settings` table. All the data in the column will be lost.
- You are about to drop the column `maxPasswordAttempts` on the `instance_settings` table. All the data in the column will be lost.
- You are about to drop the column `maxSecretsPerUser` on the `instance_settings` table. All the data in the column will be lost.
- You are about to drop the column `sessionTimeout` on the `instance_settings` table. All the data in the column will be lost.
*/
-- RedefineTables
PRAGMA defer_foreign_keys=ON;
PRAGMA foreign_keys=OFF;
CREATE TABLE "new_instance_settings" (
"id" TEXT NOT NULL PRIMARY KEY,
"instanceName" TEXT DEFAULT '',
"instanceDescription" TEXT DEFAULT '',
"allowRegistration" BOOLEAN DEFAULT true,
"requireEmailVerification" BOOLEAN DEFAULT false,
"defaultSecretExpiration" INTEGER DEFAULT 72,
"maxSecretSize" INTEGER DEFAULT 1024,
"allowPasswordProtection" BOOLEAN DEFAULT true,
"allowIpRestriction" BOOLEAN DEFAULT true,
"enableRateLimiting" BOOLEAN DEFAULT true,
"rateLimitRequests" INTEGER DEFAULT 100,
"rateLimitWindow" INTEGER DEFAULT 60,
"smtpHost" TEXT,
"smtpPort" INTEGER,
"smtpUsername" TEXT,
"smtpPassword" TEXT,
"smtpSecure" BOOLEAN DEFAULT true,
"fromEmail" TEXT,
"fromName" TEXT,
"createdAt" DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP,
"updatedAt" DATETIME NOT NULL
);
INSERT INTO "new_instance_settings" ("allowIpRestriction", "allowPasswordProtection", "allowRegistration", "createdAt", "defaultSecretExpiration", "enableRateLimiting", "fromEmail", "fromName", "id", "instanceDescription", "instanceName", "maxSecretSize", "rateLimitRequests", "rateLimitWindow", "requireEmailVerification", "smtpHost", "smtpPassword", "smtpPort", "smtpSecure", "smtpUsername", "updatedAt") SELECT "allowIpRestriction", "allowPasswordProtection", "allowRegistration", "createdAt", "defaultSecretExpiration", "enableRateLimiting", "fromEmail", "fromName", "id", "instanceDescription", "instanceName", "maxSecretSize", "rateLimitRequests", "rateLimitWindow", "requireEmailVerification", "smtpHost", "smtpPassword", "smtpPort", "smtpSecure", "smtpUsername", "updatedAt" FROM "instance_settings";
DROP TABLE "instance_settings";
ALTER TABLE "new_instance_settings" RENAME TO "instance_settings";
PRAGMA foreign_keys=ON;
PRAGMA defer_foreign_keys=OFF;

View File

@@ -0,0 +1,36 @@
/*
Warnings:
- You are about to drop the column `fromEmail` on the `instance_settings` table. All the data in the column will be lost.
- You are about to drop the column `fromName` on the `instance_settings` table. All the data in the column will be lost.
- You are about to drop the column `smtpHost` on the `instance_settings` table. All the data in the column will be lost.
- You are about to drop the column `smtpPassword` on the `instance_settings` table. All the data in the column will be lost.
- You are about to drop the column `smtpPort` on the `instance_settings` table. All the data in the column will be lost.
- You are about to drop the column `smtpSecure` on the `instance_settings` table. All the data in the column will be lost.
- You are about to drop the column `smtpUsername` on the `instance_settings` table. All the data in the column will be lost.
*/
-- RedefineTables
PRAGMA defer_foreign_keys=ON;
PRAGMA foreign_keys=OFF;
CREATE TABLE "new_instance_settings" (
"id" TEXT NOT NULL PRIMARY KEY,
"instanceName" TEXT DEFAULT '',
"instanceDescription" TEXT DEFAULT '',
"allowRegistration" BOOLEAN DEFAULT true,
"requireEmailVerification" BOOLEAN DEFAULT false,
"defaultSecretExpiration" INTEGER DEFAULT 72,
"maxSecretSize" INTEGER DEFAULT 1024,
"allowPasswordProtection" BOOLEAN DEFAULT true,
"allowIpRestriction" BOOLEAN DEFAULT true,
"enableRateLimiting" BOOLEAN DEFAULT true,
"rateLimitRequests" INTEGER DEFAULT 100,
"rateLimitWindow" INTEGER DEFAULT 60,
"createdAt" DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP,
"updatedAt" DATETIME NOT NULL
);
INSERT INTO "new_instance_settings" ("allowIpRestriction", "allowPasswordProtection", "allowRegistration", "createdAt", "defaultSecretExpiration", "enableRateLimiting", "id", "instanceDescription", "instanceName", "maxSecretSize", "rateLimitRequests", "rateLimitWindow", "requireEmailVerification", "updatedAt") SELECT "allowIpRestriction", "allowPasswordProtection", "allowRegistration", "createdAt", "defaultSecretExpiration", "enableRateLimiting", "id", "instanceDescription", "instanceName", "maxSecretSize", "rateLimitRequests", "rateLimitWindow", "requireEmailVerification", "updatedAt" FROM "instance_settings";
DROP TABLE "instance_settings";
ALTER TABLE "new_instance_settings" RENAME TO "instance_settings";
PRAGMA foreign_keys=ON;
PRAGMA defer_foreign_keys=OFF;

View File

@@ -0,0 +1,7 @@
-- CreateTable
CREATE TABLE "visitor_analytics" (
"id" TEXT NOT NULL PRIMARY KEY,
"path" TEXT NOT NULL,
"uniqueId" TEXT NOT NULL,
"timestamp" DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP
);

View File

@@ -0,0 +1,24 @@
-- AlterTable
ALTER TABLE "instance_settings" ADD COLUMN "logoUrl" TEXT DEFAULT '';
ALTER TABLE "instance_settings" ADD COLUMN "primaryColor" TEXT DEFAULT '#14b8a6';
ALTER TABLE "instance_settings" ADD COLUMN "requireApproval" BOOLEAN DEFAULT false;
ALTER TABLE "instance_settings" ADD COLUMN "requireInviteCode" BOOLEAN DEFAULT false;
-- AlterTable
ALTER TABLE "user" ADD COLUMN "approved" BOOLEAN DEFAULT true;
ALTER TABLE "user" ADD COLUMN "inviteCodeUsed" TEXT;
-- CreateTable
CREATE TABLE "invite_codes" (
"id" TEXT NOT NULL PRIMARY KEY,
"code" TEXT NOT NULL,
"uses" INTEGER NOT NULL DEFAULT 0,
"maxUses" INTEGER DEFAULT 1,
"expiresAt" DATETIME,
"createdBy" TEXT NOT NULL,
"createdAt" DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP,
"isActive" BOOLEAN NOT NULL DEFAULT true
);
-- CreateIndex
CREATE UNIQUE INDEX "invite_codes_code_key" ON "invite_codes"("code");

View File

@@ -0,0 +1,54 @@
/*
Warnings:
- You are about to drop the column `requireApproval` on the `instance_settings` table. All the data in the column will be lost.
- You are about to drop the column `approved` on the `user` table. All the data in the column will be lost.
*/
-- RedefineTables
PRAGMA defer_foreign_keys=ON;
PRAGMA foreign_keys=OFF;
CREATE TABLE "new_instance_settings" (
"id" TEXT NOT NULL PRIMARY KEY,
"instanceName" TEXT DEFAULT '',
"instanceDescription" TEXT DEFAULT '',
"allowRegistration" BOOLEAN DEFAULT true,
"requireEmailVerification" BOOLEAN DEFAULT false,
"defaultSecretExpiration" INTEGER DEFAULT 72,
"maxSecretSize" INTEGER DEFAULT 1024,
"allowPasswordProtection" BOOLEAN DEFAULT true,
"allowIpRestriction" BOOLEAN DEFAULT true,
"enableRateLimiting" BOOLEAN DEFAULT true,
"rateLimitRequests" INTEGER DEFAULT 100,
"rateLimitWindow" INTEGER DEFAULT 60,
"requireInviteCode" BOOLEAN DEFAULT false,
"logoUrl" TEXT DEFAULT '',
"primaryColor" TEXT DEFAULT '#14b8a6',
"createdAt" DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP,
"updatedAt" DATETIME NOT NULL
);
INSERT INTO "new_instance_settings" ("allowIpRestriction", "allowPasswordProtection", "allowRegistration", "createdAt", "defaultSecretExpiration", "enableRateLimiting", "id", "instanceDescription", "instanceName", "logoUrl", "maxSecretSize", "primaryColor", "rateLimitRequests", "rateLimitWindow", "requireEmailVerification", "requireInviteCode", "updatedAt") SELECT "allowIpRestriction", "allowPasswordProtection", "allowRegistration", "createdAt", "defaultSecretExpiration", "enableRateLimiting", "id", "instanceDescription", "instanceName", "logoUrl", "maxSecretSize", "primaryColor", "rateLimitRequests", "rateLimitWindow", "requireEmailVerification", "requireInviteCode", "updatedAt" FROM "instance_settings";
DROP TABLE "instance_settings";
ALTER TABLE "new_instance_settings" RENAME TO "instance_settings";
CREATE TABLE "new_user" (
"id" TEXT NOT NULL PRIMARY KEY,
"name" TEXT NOT NULL,
"username" TEXT NOT NULL,
"email" TEXT NOT NULL,
"emailVerified" BOOLEAN NOT NULL,
"image" TEXT,
"createdAt" DATETIME NOT NULL,
"updatedAt" DATETIME NOT NULL,
"displayUsername" TEXT,
"role" TEXT DEFAULT 'user',
"banned" BOOLEAN DEFAULT false,
"banReason" TEXT,
"banExpires" DATETIME,
"inviteCodeUsed" TEXT
);
INSERT INTO "new_user" ("banExpires", "banReason", "banned", "createdAt", "displayUsername", "email", "emailVerified", "id", "image", "inviteCodeUsed", "name", "role", "updatedAt", "username") SELECT "banExpires", "banReason", "banned", "createdAt", "displayUsername", "email", "emailVerified", "id", "image", "inviteCodeUsed", "name", "role", "updatedAt", "username" FROM "user";
DROP TABLE "user";
ALTER TABLE "new_user" RENAME TO "user";
CREATE UNIQUE INDEX "user_email_key" ON "user"("email");
PRAGMA foreign_keys=ON;
PRAGMA defer_foreign_keys=OFF;

View File

@@ -0,0 +1,3 @@
-- AlterTable - Add organization fields
ALTER TABLE "instance_settings" ADD COLUMN "allowedEmailDomains" TEXT DEFAULT '';
ALTER TABLE "instance_settings" ADD COLUMN "requireRegisteredUser" BOOLEAN DEFAULT false;

View File

@@ -0,0 +1,34 @@
/*
Warnings:
- You are about to drop the column `logoUrl` on the `instance_settings` table. All the data in the column will be lost.
- You are about to drop the column `primaryColor` on the `instance_settings` table. All the data in the column will be lost.
*/
-- RedefineTables
PRAGMA defer_foreign_keys=ON;
PRAGMA foreign_keys=OFF;
CREATE TABLE "new_instance_settings" (
"id" TEXT NOT NULL PRIMARY KEY,
"instanceName" TEXT DEFAULT '',
"instanceDescription" TEXT DEFAULT '',
"allowRegistration" BOOLEAN DEFAULT true,
"requireEmailVerification" BOOLEAN DEFAULT false,
"defaultSecretExpiration" INTEGER DEFAULT 72,
"maxSecretSize" INTEGER DEFAULT 1024,
"allowPasswordProtection" BOOLEAN DEFAULT true,
"allowIpRestriction" BOOLEAN DEFAULT true,
"enableRateLimiting" BOOLEAN DEFAULT true,
"rateLimitRequests" INTEGER DEFAULT 100,
"rateLimitWindow" INTEGER DEFAULT 60,
"requireInviteCode" BOOLEAN DEFAULT false,
"allowedEmailDomains" TEXT DEFAULT '',
"requireRegisteredUser" BOOLEAN DEFAULT false,
"createdAt" DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP,
"updatedAt" DATETIME NOT NULL
);
INSERT INTO "new_instance_settings" ("allowIpRestriction", "allowPasswordProtection", "allowRegistration", "allowedEmailDomains", "createdAt", "defaultSecretExpiration", "enableRateLimiting", "id", "instanceDescription", "instanceName", "maxSecretSize", "rateLimitRequests", "rateLimitWindow", "requireEmailVerification", "requireInviteCode", "requireRegisteredUser", "updatedAt") SELECT "allowIpRestriction", "allowPasswordProtection", "allowRegistration", "allowedEmailDomains", "createdAt", "defaultSecretExpiration", "enableRateLimiting", "id", "instanceDescription", "instanceName", "maxSecretSize", "rateLimitRequests", "rateLimitWindow", "requireEmailVerification", "requireInviteCode", "requireRegisteredUser", "updatedAt" FROM "instance_settings";
DROP TABLE "instance_settings";
ALTER TABLE "new_instance_settings" RENAME TO "instance_settings";
PRAGMA foreign_keys=ON;
PRAGMA defer_foreign_keys=OFF;

View File

@@ -0,0 +1,8 @@
/*
Warnings:
- A unique constraint covering the columns `[username]` on the table `user` will be added. If there are existing duplicate values, this will fail.
*/
-- CreateIndex
CREATE UNIQUE INDEX "user_username_key" ON "user"("username");

View File

@@ -0,0 +1,6 @@
-- AlterTable
ALTER TABLE "instance_settings" ADD COLUMN "webhookEnabled" BOOLEAN DEFAULT false;
ALTER TABLE "instance_settings" ADD COLUMN "webhookOnBurn" BOOLEAN DEFAULT true;
ALTER TABLE "instance_settings" ADD COLUMN "webhookOnView" BOOLEAN DEFAULT true;
ALTER TABLE "instance_settings" ADD COLUMN "webhookSecret" TEXT DEFAULT '';
ALTER TABLE "instance_settings" ADD COLUMN "webhookUrl" TEXT DEFAULT '';

View File

@@ -0,0 +1,15 @@
-- CreateTable
CREATE TABLE "api_keys" (
"id" TEXT NOT NULL PRIMARY KEY,
"name" TEXT NOT NULL,
"key_hash" TEXT NOT NULL,
"key_prefix" TEXT NOT NULL,
"userId" TEXT NOT NULL,
"last_used_at" DATETIME,
"expires_at" DATETIME,
"created_at" DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP,
CONSTRAINT "api_keys_userId_fkey" FOREIGN KEY ("userId") REFERENCES "user" ("id") ON DELETE CASCADE ON UPDATE CASCADE
);
-- CreateIndex
CREATE UNIQUE INDEX "api_keys_key_hash_key" ON "api_keys"("key_hash");

View File

@@ -0,0 +1,4 @@
-- AlterTable
ALTER TABLE "user" ADD COLUMN "twoFactorBackupCodes" TEXT;
ALTER TABLE "user" ADD COLUMN "twoFactorEnabled" BOOLEAN DEFAULT false;
ALTER TABLE "user" ADD COLUMN "twoFactorSecret" TEXT;

View File

@@ -0,0 +1,43 @@
/*
Warnings:
- You are about to drop the column `twoFactorBackupCodes` on the `user` table. All the data in the column will be lost.
- You are about to drop the column `twoFactorSecret` on the `user` table. All the data in the column will be lost.
*/
-- CreateTable
CREATE TABLE "twoFactor" (
"id" TEXT NOT NULL PRIMARY KEY,
"secret" TEXT NOT NULL,
"backupCodes" TEXT NOT NULL,
"userId" TEXT NOT NULL,
CONSTRAINT "twoFactor_userId_fkey" FOREIGN KEY ("userId") REFERENCES "user" ("id") ON DELETE CASCADE ON UPDATE CASCADE
);
-- RedefineTables
PRAGMA defer_foreign_keys=ON;
PRAGMA foreign_keys=OFF;
CREATE TABLE "new_user" (
"id" TEXT NOT NULL PRIMARY KEY,
"name" TEXT NOT NULL,
"username" TEXT NOT NULL,
"email" TEXT NOT NULL,
"emailVerified" BOOLEAN NOT NULL,
"image" TEXT,
"createdAt" DATETIME NOT NULL,
"updatedAt" DATETIME NOT NULL,
"displayUsername" TEXT,
"role" TEXT DEFAULT 'user',
"banned" BOOLEAN DEFAULT false,
"banReason" TEXT,
"banExpires" DATETIME,
"inviteCodeUsed" TEXT,
"twoFactorEnabled" BOOLEAN DEFAULT false
);
INSERT INTO "new_user" ("banExpires", "banReason", "banned", "createdAt", "displayUsername", "email", "emailVerified", "id", "image", "inviteCodeUsed", "name", "role", "twoFactorEnabled", "updatedAt", "username") SELECT "banExpires", "banReason", "banned", "createdAt", "displayUsername", "email", "emailVerified", "id", "image", "inviteCodeUsed", "name", "role", "twoFactorEnabled", "updatedAt", "username" FROM "user";
DROP TABLE "user";
ALTER TABLE "new_user" RENAME TO "user";
CREATE UNIQUE INDEX "user_username_key" ON "user"("username");
CREATE UNIQUE INDEX "user_email_key" ON "user"("email");
PRAGMA foreign_keys=ON;
PRAGMA defer_foreign_keys=OFF;

View File

@@ -0,0 +1,2 @@
-- AlterTable
ALTER TABLE "instance_settings" ADD COLUMN "importantMessage" TEXT DEFAULT '';

View File

@@ -0,0 +1,2 @@
-- CreateIndex
CREATE INDEX "visitor_analytics_timestamp_idx" ON "visitor_analytics"("timestamp");

View File

@@ -0,0 +1,3 @@
-- AlterTable
ALTER TABLE "instance_settings" ADD COLUMN "metricsEnabled" BOOLEAN DEFAULT false;
ALTER TABLE "instance_settings" ADD COLUMN "metricsSecret" TEXT DEFAULT '';

View File

@@ -0,0 +1,37 @@
-- CreateTable
CREATE TABLE "secret_requests" (
"id" TEXT NOT NULL PRIMARY KEY,
"title" TEXT NOT NULL,
"description" TEXT,
"max_views" INTEGER NOT NULL DEFAULT 1,
"expires_in" INTEGER NOT NULL,
"password" TEXT,
"allowed_ip" TEXT,
"prevent_burn" BOOLEAN NOT NULL DEFAULT false,
"token" TEXT NOT NULL,
"webhook_url" TEXT,
"webhook_secret" TEXT,
"status" TEXT NOT NULL DEFAULT 'pending',
"user_id" TEXT NOT NULL,
"secret_id" TEXT,
"created_at" DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP,
"expires_at" DATETIME NOT NULL,
"fulfilled_at" DATETIME,
CONSTRAINT "secret_requests_user_id_fkey" FOREIGN KEY ("user_id") REFERENCES "user" ("id") ON DELETE CASCADE ON UPDATE CASCADE,
CONSTRAINT "secret_requests_secret_id_fkey" FOREIGN KEY ("secret_id") REFERENCES "secrets" ("id") ON DELETE SET NULL ON UPDATE CASCADE
);
-- CreateIndex
CREATE UNIQUE INDEX "secret_requests_token_key" ON "secret_requests"("token");
-- CreateIndex
CREATE UNIQUE INDEX "secret_requests_secret_id_key" ON "secret_requests"("secret_id");
-- CreateIndex
CREATE INDEX "secret_requests_user_id_idx" ON "secret_requests"("user_id");
-- CreateIndex
CREATE INDEX "secret_requests_token_idx" ON "secret_requests"("token");
-- CreateIndex
CREATE INDEX "secret_requests_status_idx" ON "secret_requests"("status");

View File

@@ -0,0 +1,11 @@
-- AlterTable
ALTER TABLE "instance_settings" ADD COLUMN "allowFileUploads" BOOLEAN DEFAULT true;
-- CreateIndex
CREATE INDEX "secrets_expires_at_idx" ON "secrets"("expires_at");
-- CreateIndex
CREATE INDEX "secrets_userId_idx" ON "secrets"("userId");
-- CreateIndex
CREATE INDEX "visitor_analytics_uniqueId_idx" ON "visitor_analytics"("uniqueId");

View File

@@ -0,0 +1,2 @@
-- AlterTable
ALTER TABLE "instance_settings" ADD COLUMN "disableEmailPasswordSignup" BOOLEAN DEFAULT false;

View File

@@ -0,0 +1,2 @@
-- AlterTable
ALTER TABLE "instance_settings" ADD COLUMN "instanceLogo" TEXT DEFAULT '';

View File

@@ -0,0 +1,3 @@
# Please do not edit this file manually
# It should be added in your version-control system (e.g., Git)
provider = "sqlite"

237
prisma/schema.prisma Normal file
View File

@@ -0,0 +1,237 @@
datasource db {
provider = "sqlite"
}
generator client {
provider = "prisma-client"
output = "./generated/prisma"
}
model Secrets {
id String @id @default(uuid())
secret Bytes
title Bytes
views Int? @default(1)
password String?
salt String
isBurnable Boolean? @default(false) @map("is_burnable")
createdAt DateTime @default(now()) @map("created_at")
expiresAt DateTime @map("expires_at")
ipRange String? @default("") @map("ip_range")
userId String?
user User? @relation(fields: [userId], references: [id])
files File[] @relation
secretRequest SecretRequest?
@@index([expiresAt])
@@index([userId])
@@map("secrets")
}
model File {
id String @id @default(uuid())
filename String
path String
createdAt DateTime @default(now())
secrets Secrets[] @relation
@@map("files")
}
model User {
id String @id
name String
username String @unique
email String
emailVerified Boolean
image String?
createdAt DateTime
updatedAt DateTime
sessions Session[]
accounts Account[]
displayUsername String?
role String? @default("user")
banned Boolean? @default(false)
banReason String?
banExpires DateTime?
inviteCodeUsed String?
twoFactorEnabled Boolean? @default(false)
Secrets Secrets[]
apiKeys ApiKey[]
twoFactor TwoFactor[]
secretRequests SecretRequest[]
@@unique([email])
@@map("user")
}
model TwoFactor {
id String @id @default(uuid())
secret String
backupCodes String
userId String
user User @relation(fields: [userId], references: [id], onDelete: Cascade)
@@map("twoFactor")
}
model Session {
id String @id
expiresAt DateTime
token String
createdAt DateTime
updatedAt DateTime
ipAddress String?
userAgent String?
userId String
user User @relation(fields: [userId], references: [id], onDelete: Cascade)
@@unique([token])
@@map("session")
}
model Account {
id String @id
accountId String
providerId String
userId String
user User @relation(fields: [userId], references: [id], onDelete: Cascade)
accessToken String?
refreshToken String?
idToken String?
accessTokenExpiresAt DateTime?
refreshTokenExpiresAt DateTime?
scope String?
password String?
createdAt DateTime
updatedAt DateTime
@@map("account")
}
model Verification {
id String @id
identifier String
value String
expiresAt DateTime
createdAt DateTime?
updatedAt DateTime?
@@map("verification")
}
model InstanceSettings {
id String @id @default(uuid())
instanceName String? @default("")
instanceDescription String? @default("")
instanceLogo String? @default("") // Base64 encoded logo image
allowRegistration Boolean? @default(true)
requireEmailVerification Boolean? @default(false)
defaultSecretExpiration Int? @default(72) // hours
maxSecretSize Int? @default(1024) // KB
allowPasswordProtection Boolean? @default(true)
allowIpRestriction Boolean? @default(true)
enableRateLimiting Boolean? @default(true)
rateLimitRequests Int? @default(100)
rateLimitWindow Int? @default(60) // minutes
// Organization features
requireInviteCode Boolean? @default(false)
allowedEmailDomains String? @default("") // comma-separated list of allowed email domains
requireRegisteredUser Boolean? @default(false) // only registered users can create secrets
disableEmailPasswordSignup Boolean? @default(false) // disable email/password registration (social login only)
// Webhook notifications
webhookEnabled Boolean? @default(false)
webhookUrl String? @default("")
webhookSecret String? @default("") // HMAC secret for signing webhook payloads
webhookOnView Boolean? @default(true) // send webhook when secret is viewed
webhookOnBurn Boolean? @default(true) // send webhook when secret is burned/deleted
// Important message alert
importantMessage String? @default("") // Message to display to all users
// Prometheus metrics
metricsEnabled Boolean? @default(false)
metricsSecret String? @default("") // Bearer token for /metrics endpoint
// File uploads
allowFileUploads Boolean? @default(true)
createdAt DateTime @default(now())
updatedAt DateTime @updatedAt
@@map("instance_settings")
}
model InviteCode {
id String @id @default(uuid())
code String @unique
uses Int @default(0)
maxUses Int? @default(1)
expiresAt DateTime?
createdBy String
createdAt DateTime @default(now())
isActive Boolean @default(true)
@@map("invite_codes")
}
model VisitorAnalytics {
id String @id @default(uuid())
path String
uniqueId String
timestamp DateTime @default(now())
@@index([timestamp])
@@index([uniqueId])
@@map("visitor_analytics")
}
model ApiKey {
id String @id @default(uuid())
name String
keyHash String @unique @map("key_hash")
keyPrefix String @map("key_prefix")
userId String
user User @relation(fields: [userId], references: [id], onDelete: Cascade)
lastUsedAt DateTime? @map("last_used_at")
expiresAt DateTime? @map("expires_at")
createdAt DateTime @default(now()) @map("created_at")
@@map("api_keys")
}
model SecretRequest {
id String @id @default(uuid())
title String // Displayed to Creator
description String? // Optional additional context
// Pre-configured secret settings
maxViews Int @default(1) @map("max_views")
expiresIn Int @map("expires_in") // Seconds until secret expires after creation
password String? // Optional password protection (hashed)
allowedIp String? @map("allowed_ip") // Optional IP restriction
preventBurn Boolean @default(false) @map("prevent_burn")
// Request security
token String @unique // Secure token for Creator Link
// Webhook configuration
webhookUrl String? @map("webhook_url") // Optional webhook URL
webhookSecret String? @map("webhook_secret") // HMAC secret for webhook signature
// Status tracking
status String @default("pending") // pending | fulfilled | expired | cancelled
// Relationships
userId String @map("user_id") // Requester's user ID
user User @relation(fields: [userId], references: [id], onDelete: Cascade)
secretId String? @unique @map("secret_id") // Created secret (once fulfilled)
secret Secrets? @relation(fields: [secretId], references: [id], onDelete: SetNull)
// Timestamps
createdAt DateTime @default(now()) @map("created_at")
expiresAt DateTime @map("expires_at") // When the Creator Link expires
fulfilledAt DateTime? @map("fulfilled_at") // When secret was created
@@index([userId])
@@index([token])
@@index([status])
@@map("secret_requests")
}