Skip to content
This repository was archived by the owner on Jun 29, 2025. It is now read-only.
Open
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
14 changes: 13 additions & 1 deletion .github/workflows/build-docker-image.yml
Original file line number Diff line number Diff line change
Expand Up @@ -43,7 +43,7 @@ jobs:
username: ${{ github.repository_owner }}
password: ${{ secrets.GITHUB_TOKEN }}

- name: Build and push
- name: Build and push sqlite
uses: docker/build-push-action@v6
with:
context: .
Expand All @@ -53,3 +53,15 @@ jobs:
labels: ${{ steps.meta.outputs.labels }}
cache-from: type=gha
cache-to: type=gha,mode=max

- name: Build and push postgresql
uses: docker/build-push-action@v6
with:
context: .
platforms: linux/amd64,linux/arm64
push: true
tags: postgresql-${{ steps.meta.outputs.tags }}
labels: ${{ steps.meta.outputs.labels }}
build-args: "DB_DATASOURCE=postgresql"
cache-from: type=gha
cache-to: type=gha,mode=max
3 changes: 2 additions & 1 deletion .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,8 @@ yarn-error.log*

# env file
.env
!/backend/prisma/.env
!/backend/prisma/sqlite/.env
!/backend/prisma/postgresql/.env

# vercel
.vercel
Expand Down
4 changes: 2 additions & 2 deletions CONTRIBUTING.md
Original file line number Diff line number Diff line change
Expand Up @@ -73,8 +73,8 @@ The backend is built with [Nest.js](https://nestjs.com) and uses Typescript.

1. Open the `backend` folder
2. Install the dependencies with `npm install`
3. Push the database schema to the database by running `npx prisma db push`
4. Seed the database with `npx prisma db seed`
3. Push the database schema to the database by running `npx prisma db push --schema=prisma/sqlite/schema/`
4. Seed the database with `npx prisma db seed --schema=prisma/sqlite/schema/`
5. Start the backend with `npm run dev`

### Frontend
Expand Down
45 changes: 23 additions & 22 deletions Dockerfile
Original file line number Diff line number Diff line change
@@ -1,35 +1,40 @@
# Stage 1: Frontend dependencies
FROM node:22-alpine AS frontend-dependencies
ARG NODE_VERSION="22"
ARG ALPINE_VERSION=""

# Preamble: define base image used by all stages
FROM node:${NODE_VERSION}-alpine${ALPINE_VERSION} AS base
WORKDIR /opt/app

# Stage 1: Frontend dependencies
FROM base AS frontend-dependencies
COPY frontend/package.json frontend/package-lock.json ./
RUN npm ci

# Stage 2: Build frontend
FROM node:22-alpine AS frontend-builder
WORKDIR /opt/app
FROM base AS frontend-builder
COPY ./frontend .
COPY --from=frontend-dependencies /opt/app/node_modules ./node_modules
RUN npm run build

# Stage 3: Backend dependencies
FROM node:22-alpine AS backend-dependencies
FROM base AS backend-dependencies
RUN apk add --no-cache python3
WORKDIR /opt/app
COPY backend/package.json backend/package-lock.json ./
RUN npm ci

# Stage 4: Build backend
FROM node:22-alpine AS backend-builder
FROM base AS backend-builder
ARG DB_DATASOURCE=sqlite

RUN apk add openssl

WORKDIR /opt/app
COPY ./backend .
COPY --from=backend-dependencies /opt/app/node_modules ./node_modules
RUN npx prisma generate
RUN npx prisma generate --schema=prisma/${DB_DATASOURCE}/schema/
RUN npm run build && npm prune --production

# Stage 5: Final image
FROM node:22-alpine AS runner
FROM base AS runner
ENV NODE_ENV=docker

# Delete default node user
Expand All @@ -39,20 +44,16 @@ RUN apk update --no-cache \
&& apk upgrade --no-cache \
&& apk add --no-cache curl caddy su-exec openssl

WORKDIR /opt/app/frontend
COPY --from=frontend-builder /opt/app/public ./public
COPY --from=frontend-builder /opt/app/.next/standalone ./
COPY --from=frontend-builder /opt/app/.next/static ./.next/static
COPY --from=frontend-builder /opt/app/public ./frontend/public
COPY --from=frontend-builder /opt/app/.next/standalone ./frontend/
COPY --from=frontend-builder /opt/app/.next/static ./frontend/.next/static
COPY --from=frontend-builder /opt/app/public/img /tmp/img

WORKDIR /opt/app/backend
COPY --from=backend-builder /opt/app/node_modules ./node_modules
COPY --from=backend-builder /opt/app/dist ./dist
COPY --from=backend-builder /opt/app/prisma ./prisma
COPY --from=backend-builder /opt/app/package.json ./
COPY --from=backend-builder /opt/app/tsconfig.json ./

WORKDIR /opt/app
COPY --from=backend-builder /opt/app/node_modules ./backend/node_modules
COPY --from=backend-builder /opt/app/dist ./backend/dist
COPY --from=backend-builder /opt/app/prisma ./backend/prisma
COPY --from=backend-builder /opt/app/package.json ./backend/
COPY --from=backend-builder /opt/app/tsconfig.json ./backend/

COPY ./reverse-proxy /opt/app/reverse-proxy
COPY ./scripts/docker ./scripts/docker
Expand Down
4 changes: 2 additions & 2 deletions backend/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -4,10 +4,10 @@
"scripts": {
"build": "nest build",
"dev": "cross-env NODE_ENV=development nest start --watch",
"prod": "prisma migrate deploy && prisma db seed && node dist/src/main",
"prod": "prisma migrate deploy --schema=prisma/sqlite/schema/ && prisma db seed --schema=prisma/sqlite/schema/ && node dist/src/main",
"lint": "eslint 'src/**/*.ts'",
"format": "prettier --end-of-line=auto --write 'src/**/*.ts'",
"test:system": "prisma migrate reset -f && nest start & wait-on http://localhost:8080/api/configs && newman run ./test/newman-system-tests.json"
"test:system": "prisma migrate reset -f --schema=prisma/sqlite/schema/ && nest start & wait-on http://localhost:8080/api/configs && newman run ./test/newman-system-tests.json"
},
"prisma": {
"seed": "ts-node prisma/seed/config.seed.ts"
Expand Down
2 changes: 1 addition & 1 deletion backend/prisma/.env → backend/prisma/postgresql/.env
Original file line number Diff line number Diff line change
@@ -1,2 +1,2 @@
#This file is only used to set a default value for the database url
DATABASE_URL="file:../data/pingvin-share.db"
DATABASE_URL="postgresql://localhost"
1 change: 1 addition & 0 deletions backend/prisma/postgresql/schema/generator.prisma
Original file line number Diff line number Diff line change
@@ -0,0 +1,192 @@
-- CreateTable
CREATE TABLE "User" (
"id" TEXT NOT NULL,
"createdAt" TIMESTAMP(3) NOT NULL DEFAULT CURRENT_TIMESTAMP,
"updatedAt" TIMESTAMP(3) NOT NULL,
"username" TEXT NOT NULL,
"email" TEXT NOT NULL,
"password" TEXT,
"isAdmin" BOOLEAN NOT NULL DEFAULT false,
"ldapDN" TEXT,
"totpEnabled" BOOLEAN NOT NULL DEFAULT false,
"totpVerified" BOOLEAN NOT NULL DEFAULT false,
"totpSecret" TEXT,

CONSTRAINT "User_pkey" PRIMARY KEY ("id")
);

-- CreateTable
CREATE TABLE "RefreshToken" (
"id" TEXT NOT NULL,
"token" TEXT NOT NULL,
"createdAt" TIMESTAMP(3) NOT NULL DEFAULT CURRENT_TIMESTAMP,
"expiresAt" TIMESTAMP(3) NOT NULL,
"userId" TEXT NOT NULL,
"oauthIDToken" TEXT,

CONSTRAINT "RefreshToken_pkey" PRIMARY KEY ("id")
);

-- CreateTable
CREATE TABLE "LoginToken" (
"token" TEXT NOT NULL,
"createdAt" TIMESTAMP(3) NOT NULL DEFAULT CURRENT_TIMESTAMP,
"expiresAt" TIMESTAMP(3) NOT NULL,
"userId" TEXT NOT NULL,
"used" BOOLEAN NOT NULL DEFAULT false,

CONSTRAINT "LoginToken_pkey" PRIMARY KEY ("token")
);

-- CreateTable
CREATE TABLE "ResetPasswordToken" (
"token" TEXT NOT NULL,
"createdAt" TIMESTAMP(3) NOT NULL DEFAULT CURRENT_TIMESTAMP,
"expiresAt" TIMESTAMP(3) NOT NULL,
"userId" TEXT NOT NULL,

CONSTRAINT "ResetPasswordToken_pkey" PRIMARY KEY ("token")
);

-- CreateTable
CREATE TABLE "OAuthUser" (
"id" TEXT NOT NULL,
"provider" TEXT NOT NULL,
"providerUserId" TEXT NOT NULL,
"providerUsername" TEXT NOT NULL,
"userId" TEXT NOT NULL,

CONSTRAINT "OAuthUser_pkey" PRIMARY KEY ("id")
);

-- CreateTable
CREATE TABLE "Share" (
"id" TEXT NOT NULL,
"createdAt" TIMESTAMP(3) NOT NULL DEFAULT CURRENT_TIMESTAMP,
"name" TEXT,
"uploadLocked" BOOLEAN NOT NULL DEFAULT false,
"isZipReady" BOOLEAN NOT NULL DEFAULT false,
"views" INTEGER NOT NULL DEFAULT 0,
"expiration" TIMESTAMP(3) NOT NULL,
"description" TEXT,
"removedReason" TEXT,
"creatorId" TEXT,
"reverseShareId" TEXT,
"storageProvider" TEXT NOT NULL DEFAULT 'LOCAL',

CONSTRAINT "Share_pkey" PRIMARY KEY ("id")
);

-- CreateTable
CREATE TABLE "ReverseShare" (
"id" TEXT NOT NULL,
"createdAt" TIMESTAMP(3) NOT NULL DEFAULT CURRENT_TIMESTAMP,
"token" TEXT NOT NULL,
"shareExpiration" TIMESTAMP(3) NOT NULL,
"maxShareSize" TEXT NOT NULL,
"sendEmailNotification" BOOLEAN NOT NULL,
"remainingUses" INTEGER NOT NULL,
"simplified" BOOLEAN NOT NULL DEFAULT false,
"publicAccess" BOOLEAN NOT NULL DEFAULT true,
"creatorId" TEXT NOT NULL,

CONSTRAINT "ReverseShare_pkey" PRIMARY KEY ("id")
);

-- CreateTable
CREATE TABLE "ShareRecipient" (
"id" TEXT NOT NULL,
"email" TEXT NOT NULL,
"shareId" TEXT NOT NULL,

CONSTRAINT "ShareRecipient_pkey" PRIMARY KEY ("id")
);

-- CreateTable
CREATE TABLE "File" (
"id" TEXT NOT NULL,
"createdAt" TIMESTAMP(3) NOT NULL DEFAULT CURRENT_TIMESTAMP,
"name" TEXT NOT NULL,
"size" TEXT NOT NULL,
"shareId" TEXT NOT NULL,

CONSTRAINT "File_pkey" PRIMARY KEY ("id")
);

-- CreateTable
CREATE TABLE "ShareSecurity" (
"id" TEXT NOT NULL,
"createdAt" TIMESTAMP(3) NOT NULL DEFAULT CURRENT_TIMESTAMP,
"password" TEXT,
"maxViews" INTEGER,
"shareId" TEXT,

CONSTRAINT "ShareSecurity_pkey" PRIMARY KEY ("id")
);

-- CreateTable
CREATE TABLE "Config" (
"updatedAt" TIMESTAMP(3) NOT NULL,
"name" TEXT NOT NULL,
"category" TEXT NOT NULL,
"type" TEXT NOT NULL,
"defaultValue" TEXT NOT NULL DEFAULT '',
"value" TEXT,
"obscured" BOOLEAN NOT NULL DEFAULT false,
"secret" BOOLEAN NOT NULL DEFAULT true,
"locked" BOOLEAN NOT NULL DEFAULT false,
"order" INTEGER NOT NULL,

CONSTRAINT "Config_pkey" PRIMARY KEY ("name","category")
);

-- CreateIndex
CREATE UNIQUE INDEX "User_username_key" ON "User"("username");

-- CreateIndex
CREATE UNIQUE INDEX "User_email_key" ON "User"("email");

-- CreateIndex
CREATE UNIQUE INDEX "User_ldapDN_key" ON "User"("ldapDN");

-- CreateIndex
CREATE UNIQUE INDEX "RefreshToken_token_key" ON "RefreshToken"("token");

-- CreateIndex
CREATE UNIQUE INDEX "ResetPasswordToken_userId_key" ON "ResetPasswordToken"("userId");

-- CreateIndex
CREATE UNIQUE INDEX "ReverseShare_token_key" ON "ReverseShare"("token");

-- CreateIndex
CREATE UNIQUE INDEX "ShareSecurity_shareId_key" ON "ShareSecurity"("shareId");

-- AddForeignKey
ALTER TABLE "RefreshToken" ADD CONSTRAINT "RefreshToken_userId_fkey" FOREIGN KEY ("userId") REFERENCES "User"("id") ON DELETE CASCADE ON UPDATE CASCADE;

-- AddForeignKey
ALTER TABLE "LoginToken" ADD CONSTRAINT "LoginToken_userId_fkey" FOREIGN KEY ("userId") REFERENCES "User"("id") ON DELETE CASCADE ON UPDATE CASCADE;

-- AddForeignKey
ALTER TABLE "ResetPasswordToken" ADD CONSTRAINT "ResetPasswordToken_userId_fkey" FOREIGN KEY ("userId") REFERENCES "User"("id") ON DELETE CASCADE ON UPDATE CASCADE;

-- AddForeignKey
ALTER TABLE "OAuthUser" ADD CONSTRAINT "OAuthUser_userId_fkey" FOREIGN KEY ("userId") REFERENCES "User"("id") ON DELETE CASCADE ON UPDATE CASCADE;

-- AddForeignKey
ALTER TABLE "Share" ADD CONSTRAINT "Share_creatorId_fkey" FOREIGN KEY ("creatorId") REFERENCES "User"("id") ON DELETE CASCADE ON UPDATE CASCADE;

-- AddForeignKey
ALTER TABLE "Share" ADD CONSTRAINT "Share_reverseShareId_fkey" FOREIGN KEY ("reverseShareId") REFERENCES "ReverseShare"("id") ON DELETE CASCADE ON UPDATE CASCADE;

-- AddForeignKey
ALTER TABLE "ReverseShare" ADD CONSTRAINT "ReverseShare_creatorId_fkey" FOREIGN KEY ("creatorId") REFERENCES "User"("id") ON DELETE CASCADE ON UPDATE CASCADE;

-- AddForeignKey
ALTER TABLE "ShareRecipient" ADD CONSTRAINT "ShareRecipient_shareId_fkey" FOREIGN KEY ("shareId") REFERENCES "Share"("id") ON DELETE CASCADE ON UPDATE CASCADE;

-- AddForeignKey
ALTER TABLE "File" ADD CONSTRAINT "File_shareId_fkey" FOREIGN KEY ("shareId") REFERENCES "Share"("id") ON DELETE CASCADE ON UPDATE CASCADE;

-- AddForeignKey
ALTER TABLE "ShareSecurity" ADD CONSTRAINT "ShareSecurity_shareId_fkey" FOREIGN KEY ("shareId") REFERENCES "Share"("id") ON DELETE CASCADE ON UPDATE CASCADE;
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
# Please do not edit this file manually
# It should be added in your version-control system (e.g., Git)
provider = "postgresql"
1 change: 1 addition & 0 deletions backend/prisma/postgresql/schema/models.prisma
4 changes: 4 additions & 0 deletions backend/prisma/postgresql/schema/schema.prisma
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
datasource db {
provider = "postgresql"
url = env("DATABASE_URL")
}
4 changes: 4 additions & 0 deletions backend/prisma/schema/generator.prisma
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
generator client {
provider = "prisma-client-js"
previewFeatures = ["prismaSchemaFolder"]
}
Original file line number Diff line number Diff line change
@@ -1,12 +1,3 @@
generator client {
provider = "prisma-client-js"
}

datasource db {
provider = "sqlite"
url = env("DATABASE_URL")
}

model User {
id String @id @default(uuid())
createdAt DateTime @default(now())
Expand Down
2 changes: 1 addition & 1 deletion backend/prisma/seed/config.seed.ts
Original file line number Diff line number Diff line change
Expand Up @@ -412,7 +412,7 @@ const prisma = new PrismaClient({
db: {
url:
process.env.DATABASE_URL ||
"file:../data/pingvin-share.db?connection_limit=1",
"file:../../data/pingvin-share.db?connection_limit=1",
},
},
});
Expand Down
2 changes: 2 additions & 0 deletions backend/prisma/sqlite/.env
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
#This file is only used to set a default value for the database url
DATABASE_URL="file:../../../data/pingvin-share.db"
4 changes: 4 additions & 0 deletions backend/prisma/sqlite/schema/datasource.prisma
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
datasource db {
provider = "sqlite"
url = env("DATABASE_URL")
}
1 change: 1 addition & 0 deletions backend/prisma/sqlite/schema/generator.prisma
1 change: 1 addition & 0 deletions backend/prisma/sqlite/schema/models.prisma