From 0fbb1a960675bff812d4b1014382bc1a16a058de Mon Sep 17 00:00:00 2001 From: renzynx Date: Mon, 19 Dec 2022 19:12:25 +0700 Subject: [PATCH] We know the game and we're gonna play it --- .github/workflows/build.yml | 56 ++++++++++++++++++ .github/workflows/docker-build.yml | 74 ------------------------ .gitignore | 1 + api/CODEOWNERS | 25 -------- api/Dockerfile | 3 - api/src/main.ts | 4 +- api/src/modules/root/root.controller.ts | 3 + api/src/modules/upload/upload.service.ts | 45 +++++++++----- docker-compose.example.yml | 12 +++- entrypoint.sh | 9 +++ web/Dockerfile | 8 +-- 11 files changed, 114 insertions(+), 126 deletions(-) create mode 100644 .github/workflows/build.yml delete mode 100644 .github/workflows/docker-build.yml create mode 100644 .gitignore delete mode 100644 api/CODEOWNERS create mode 100644 entrypoint.sh diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml new file mode 100644 index 0000000..ffa1c87 --- /dev/null +++ b/.github/workflows/build.yml @@ -0,0 +1,56 @@ +concurrency: build +name: Build +on: + push: + branches: + - main + pull_request: + branches: + - main + +jobs: + build: + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v3 + + - name: Set up Buildx + uses: docker/setup-buildx-action@v2 + + - name: Login to GitHub Container Registry + uses: docker/login-action@v1 + with: + registry: ghcr.io + username: ${{ github.repository_owner }} + password: ${{ secrets.GITHUB_TOKEN }} + + - name: Build and push + uses: docker/build-push-action@v2 + with: + context: ./api + file: ./api/Dockerfile + push: true + tags: ghcr.io/${{ github.repository_owner }}/bliss:latest + + web: + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v3 + + - name: Set up Buildx + uses: docker/setup-buildx-action@v2 + + - name: Login to GitHub Container Registry + uses: docker/login-action@v1 + with: + registry: ghcr.io + username: ${{ github.repository_owner }} + password: ${{ secrets.GITHUB_TOKEN }} + + - name: Build and push + uses: docker/build-push-action@v2 + with: + context: ./web + file: ./web/Dockerfile + push: true + tags: ghcr.io/${{ github.repository_owner }}/web:latest diff --git a/.github/workflows/docker-build.yml b/.github/workflows/docker-build.yml deleted file mode 100644 index b3e185f..0000000 --- a/.github/workflows/docker-build.yml +++ /dev/null @@ -1,74 +0,0 @@ -name: Docker Image CI - -on: - push: - branches: ['main'] - paths: - - 'api/src/**' - - 'web/src/**' - - 'api/prisma/**' - - '.github/**' - - 'api/Dockerfile' - - 'web/Dockerfile' - - 'web/entrypoint.sh' - pull_request: - branches: ['main'] - paths: - - 'api/src/**' - - 'web/src/**' - - 'api/prisma/**' - - '.github/**' - - 'api/Dockerfile' - - 'web/Dockerfile' - -jobs: - build: - runs-on: ubuntu-latest - - defaults: - run: - working-directory: api - - steps: - - name: Check out the repo - uses: actions/checkout@v3 - - - name: Set up QEMU - uses: docker/setup-qemu-action@v1 - id: qemu - - - name: Setup Buildx - uses: docker/setup-buildx-action@v2 - id: buildx - - - name: Login to GitHub Container Registry - uses: docker/login-action@v2 - with: - registry: ghcr.io - username: ${{ github.actor }} - password: ${{ secrets.GITHUB_TOKEN }} - - - name: Build api image and push to GitHub Container Registry - uses: docker/build-push-action@v3 - with: - context: ./api - file: ./api/Dockerfile - platforms: linux/amd64,linux/arm64 - push: true - tags: ghcr.io/renzynx/bliss:latest - cache-from: type=gha - cache-to: type=gha,mode=max - - - name: Switch working directory - run: cd ../web - - - name: Build web image and push to GitHub Container Registry - uses: docker/build-push-action@v3 - with: - context: ./web - file: ./web/Dockerfile - platforms: linux/amd64,linux/arm64 - push: true - tags: ghcr.io/renzynx/web:latest - cache-from: type=gha - cache-to: type=gha,mode=max diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..412c257 --- /dev/null +++ b/.gitignore @@ -0,0 +1 @@ +docker-compose.yml \ No newline at end of file diff --git a/api/CODEOWNERS b/api/CODEOWNERS deleted file mode 100644 index 682f5ad..0000000 --- a/api/CODEOWNERS +++ /dev/null @@ -1,25 +0,0 @@ -# Each line represents a rule, followed by a list of members. -# These members are the default owners for all files that match the specified pattern. -# The pattern generally follows the same syntax used for .gitignore files. -# The last matching rule always wins; those that appear lower in the file take precedence over rules that appear higher up. -# Specify owners by their username, email, or role assignment in the project. - -# Examples: - -# Member with username "john.smith" and member with email "alex@mycompany.com" -# own any JavaScript file in repository -# *.js john.smith alex@mycompany.com - -# Bob owns all files under "subdir" directory at the repository root and all its subdirectories -# /subdir/ Bob - -# All members from team named "Product Team" file under root "Product Documentation" directory -# "/Product Documentation" "Product Team" - -# All members who are assigned the Project Collaborator role own any file under docs/ directory -# anywhere in the repository, but not further nested files -# docs/* "Project Collaborator" - -# This file itself is owned by members who are assigned the Project Admin role in this project. -CODEOWNERS "Project Admin" -`` diff --git a/api/Dockerfile b/api/Dockerfile index c42285b..698a5f6 100644 --- a/api/Dockerfile +++ b/api/Dockerfile @@ -34,13 +34,10 @@ RUN apt-get update && apt-get install --no-install-recommends -y \ WORKDIR /app COPY --from=builder /app/package.json ./package.json -COPY --from=builder /app/yarn.lock . COPY --from=builder /app/node_modules ./node_modules COPY --from=builder /app/dist ./dist COPY --from=builder /app/nest-cli.json ./nest-cli.json COPY --from=builder /app/prisma ./prisma -COPY --from=builder /app/tsconfig.build.json ./tsconfig.build.json -COPY --from=builder /app/tsconfig.json ./tsconfig.json ENV NODE_ENV production diff --git a/api/src/main.ts b/api/src/main.ts index 6ab4765..7ae427f 100644 --- a/api/src/main.ts +++ b/api/src/main.ts @@ -36,9 +36,7 @@ async function bootstrap() { resave: false, saveUninitialized: false, cookie: { - secure: - process.env.NODE_ENV === "production" && - process.env.USE_SSL === "true", + secure: process.env.NODE_ENV === "production", httpOnly: true, maxAge: 1000 * 60 * 60 * 24 * 7, // 7 days sameSite: "lax", diff --git a/api/src/modules/root/root.controller.ts b/api/src/modules/root/root.controller.ts index 09e56b4..ecff557 100644 --- a/api/src/modules/root/root.controller.ts +++ b/api/src/modules/root/root.controller.ts @@ -30,6 +30,9 @@ export class RootController { @Get(":slug") @Render("index") file(@Param("slug") slug: string, @Request() req: ERequest) { + if (!slug) { + return "Hello World!"; + } return this.rootService.getFile(slug, req); } diff --git a/api/src/modules/upload/upload.service.ts b/api/src/modules/upload/upload.service.ts index 8053275..63d78e5 100644 --- a/api/src/modules/upload/upload.service.ts +++ b/api/src/modules/upload/upload.service.ts @@ -103,21 +103,26 @@ export class UploadService { const slug = generateApiKey(12); - const stream = createWriteStream( - join(uploadDir, `${slug}_${file.originalname}`), - { - flags: "w", + const stream = createWriteStream(join(uploadDir, slug), { flags: "w" }).on( + "error", + (e) => { + this.logger.error(e.message); + throw new InternalServerErrorException( + "Something went wrong in our end, please try again later." + ); } - ).on("error", (e) => { + ); + + stream.write(file.buffer); + stream.end(); + + stream.on("error", (e) => { this.logger.error(e.message); throw new InternalServerErrorException( "Something went wrong in our end, please try again later." ); }); - stream.write(file.buffer); - stream.end(); - const mime = lookUp(file.originalname); if (mime.includes("image") && user.embed_settings?.enabled) { @@ -140,7 +145,7 @@ export class UploadService { }, }); - const protocol = process.env.USE_SSL === "true" ? "https" : req.protocol; + const protocol = req.headers["x-forwarded-proto"] || req.protocol; const baseUrl = `${protocol}://${req.get("host")}`; @@ -177,8 +182,7 @@ export class UploadService { const ext = name.split(".").pop(); const data = req.body.toString().split(",")[1]; const buffer = Buffer.from(data, "base64"); - const id = md5(`${name}${req.ip}`); - const slug = generateApiKey(12); + const id = md5(name + req.ip); const tmpName = `tmp_${id}.${ext}`; if (firstChunk && existsSync(join(uploadDir, tmpName))) { @@ -187,11 +191,24 @@ export class UploadService { await writeFile(join(uploadDir, tmpName), buffer, { flag: "a" }); if (lastChunk) { const mimetype = lookUp(name); - + let slug = generateApiKey(12); await rename( join(uploadDir, tmpName), - join(uploadDir, `${slug}_${name}`) - ); + join(uploadDir, `${slug}.${ext}`) + ).catch(async (reason) => { + if (reason === "EEXIST") { + slug = generateApiKey(12); + await rename( + join(uploadDir, tmpName), + join(uploadDir, `${slug}.${ext}`) + ); + } else { + this.logger.error(reason); + throw new InternalServerErrorException( + "Something went wrong in our end, please try again later." + ); + } + }); if (mimetype.includes("image") && user.embed_settings?.enabled) { this.createOEmbedJSON({ diff --git a/docker-compose.example.yml b/docker-compose.example.yml index 0c4ebff..4380d55 100644 --- a/docker-compose.example.yml +++ b/docker-compose.example.yml @@ -1,7 +1,10 @@ version: '3.9' services: api: - image: ghcr.io/renzynx/bliss:latest + image: bliss/api:latest + build: + context: ./api + dockerfile: Dockerfile container_name: api restart: always environment: @@ -42,10 +45,13 @@ services: networks: - bliss volumes: - - ./uploads:/app/uploads + - ./api/uploads:/app/uploads web: - image: ghcr.io/renzynx/web:latest + image: bliss/web:latest + build: + context: ./web + dockerfile: Dockerfile container_name: web restart: always ports: diff --git a/entrypoint.sh b/entrypoint.sh new file mode 100644 index 0000000..248b05a --- /dev/null +++ b/entrypoint.sh @@ -0,0 +1,9 @@ +#!/bin/sh + +echo "Check that we have NEXT_PUBLIC_API_URL vars" +test -n "$NEXT_PUBLIC_API_URL" + +find /app/.next \( -type d -name .git -prune \) -o -type f -print0 | xargs -0 sed -i "s#APP_NEXT_PUBLIC_API_URL#$NEXT_PUBLIC_API_URL#g" + +echo "Starting Nextjs" +exec "$@" \ No newline at end of file diff --git a/web/Dockerfile b/web/Dockerfile index 5e96816..cdb150c 100644 --- a/web/Dockerfile +++ b/web/Dockerfile @@ -11,11 +11,12 @@ RUN yarn install --immutable FROM node:18-alpine AS builder +ENV NEXT_TELEMETRY_DISABLED 1 + WORKDIR /app -COPY --from=deps /app/node_modules ./node_modules COPY . . - +COPY --from=deps /app/node_modules ./node_modules RUN NEXT_PUBLIC_API_URL=APP_NEXT_PUBLIC_API_URL yarn build @@ -30,12 +31,11 @@ COPY --from=builder /app/public ./public COPY --from=builder /app/.next ./.next COPY --from=builder /app/node_modules ./node_modules COPY --from=builder /app/package.json ./package.json -COPY --from=builder /app/yarn.lock ./yarn.lock -COPY --from=builder /app/next.config.js ./next.config.js COPY --from=builder /app/entrypoint.sh ./entrypoint.sh RUN addgroup --system --gid 1001 nodejs RUN adduser --system --uid 1001 nextjs +RUN chown -R nextjs:nodejs /app/.next USER nextjs