From f09afada86b8399bbc93349185a698ec218aba5b Mon Sep 17 00:00:00 2001 From: Grzegorz Godlewski Date: Sun, 19 May 2024 19:56:20 +0200 Subject: [PATCH 1/5] Create separate docker for each feature branch --- .github/pull_request.md | 0 .github/workflows/feat-deploy.yml | 111 ++++++++++++++++++++++++++++++ 2 files changed, 111 insertions(+) create mode 100644 .github/pull_request.md create mode 100644 .github/workflows/feat-deploy.yml diff --git a/.github/pull_request.md b/.github/pull_request.md new file mode 100644 index 00000000..e69de29b diff --git a/.github/workflows/feat-deploy.yml b/.github/workflows/feat-deploy.yml new file mode 100644 index 00000000..91c99558 --- /dev/null +++ b/.github/workflows/feat-deploy.yml @@ -0,0 +1,111 @@ +name: Feat Branch Deploy + +on: + push: + branches: + - feat/* + +jobs: + test: + runs-on: ubuntu-latest + + steps: + - uses: actions/checkout@v3 + + - run: sudo apt-get update + - run: sudo apt-get install -y libkrb5-dev + + - name: Use Node.js 20.x + uses: actions/setup-node@v3 + with: + node-version: 20 + cache: npm + + - name: Install node_modules + run: npm install + + - name: Lint + run: npm run lint + + - name: Test + run: npm run test + + build: + needs: test + runs-on: wgd-dev + + steps: + - name: Extract branch name + shell: bash + run: echo "::set-env name=BRANCH_NAME::$(echo ${GITHUB_REF#refs/heads/} | sed 's/\//_/g')" + - name: Test + run: echo "${BRANCH_NAME}" + + - uses: actions/checkout@v3 + + - name: Use Node.js 20.x + uses: actions/setup-node@v3 + with: + node-version: 20 + cache: npm + + - name: Build action runner + run: docker build -t "wgd-action-runner:${BRANCH_NAME}" --build-arg "GIT_SHA=${GITHUB_SHA}" apps/wgd-action-runner + + - name: Build hugo docs + run: | + docker run \ + -v "${GITHUB_WORKSPACE}/hugo:/site" \ + -v "${GITHUB_WORKSPACE}/website:/website" \ + -v "/var/www/${BRANCH_NAME}.wikigdrive.com:/dist/hugo" \ + --env CONFIG_TOML="/site/config/_default/config.toml" --env BASE_URL="https://${BRANCH_NAME}.wikigdrive.com" \ + wgd-action-runner:${BRANCH_NAME} /steps/step_render_hugo + + - name: Copy index for vite + run: mkdir -p ${GITHUB_WORKSPACE}/dist/hugo && cp -rf /var/www/${BRANCH_NAME}.wikigdrive.com/* ${GITHUB_WORKSPACE}/dist/hugo + + - uses: whoan/docker-build-with-cache-action@v5 + with: + image_name: "wikigdrive-feature" + image_tag: "${{ github.sha }}" + push_image_and_stages: false + build_extra_args: "{'--build-arg': 'GIT_SHA=${{ github.sha }}'}" + + - name: Stop and remove + run: docker stop "wikigdrive-${BRANCH_NAME}" ; docker rm "wikigdrive-${BRANCH_NAME}" + continue-on-error: true + + - name: "Create empty volume" + run: docker volume rm -f "wikiGDrive${BRANCH_NAME}" ; docker volume create "wikiGDrive${BRANCH_NAME}" + + - name: Start + run: | + docker run -d --name "wikigdrive-${BRANCH_NAME}" \ + --restart unless-stopped \ + --network nginx \ + -v "wikiGDrive${BRANCH_NAME}":/data \ + -v /home/wikigdrive/service_account.json:/service_account.json \ + -v /home/wikigdrive/env.develop:/usr/src/app/.env \ + -v /var/run/docker.sock:/var/run/docker.sock \ + -v "/var/www/${BRANCH_NAME}.wikigdrive.com:/usr/src/app/dist/hugo" \ + -e "GIT_SHA=${GITHUB_SHA}" \ + -e "ZIPKIN_URL=https://${BRANCH_NAME}.wikigdrive.com/zipkin" \ + -e "ZIPKIN_SERVICE=wikigdrive-${BRANCH_NAME}" \ + --link=zipkin:zipkin \ + "wikigdrive-feature:${GITHUB_SHA}" wikigdrive \ + --service_account /service_account.json \ + --share_email mie-docs-wikigdrive@wikigdrive.iam.gserviceaccount.com \ + --workdir /data \ + server 3000 + + - name: "Nginx setup" + run: "TODO" + + - name: Create pull request + id: open-pr + uses: repo-sync/pull-request@v2 + with: + destination_branch: "master" + pr_title: "${BRANCH_NAME}" + pr_template: ".github/pull_request.md" + pr_draft: true From d2a4273192fc36c9c63975a465648575852eac45 Mon Sep 17 00:00:00 2001 From: Grzegorz Godlewski Date: Sun, 30 Jun 2024 22:54:41 +0200 Subject: [PATCH 2/5] Fix pr nginx deploy --- .github/workflows/DevelopServerDeploy.yml | 1 + .github/workflows/feat-deploy.yml | 66 -------------- .github/workflows/pull-request.yml | 102 ++++++++++++++-------- 3 files changed, 65 insertions(+), 104 deletions(-) diff --git a/.github/workflows/DevelopServerDeploy.yml b/.github/workflows/DevelopServerDeploy.yml index ea5d57b6..594882b9 100644 --- a/.github/workflows/DevelopServerDeploy.yml +++ b/.github/workflows/DevelopServerDeploy.yml @@ -72,6 +72,7 @@ jobs: run: | docker run -d --name wikigdrive-develop \ --restart unless-stopped \ + --network nginx \ -v wikiGDriveDevelop:/data \ -v /home/wikigdrive/service_account.json:/service_account.json \ -v /home/wikigdrive/env.develop:/usr/src/app/.env \ diff --git a/.github/workflows/feat-deploy.yml b/.github/workflows/feat-deploy.yml index 91c99558..34e4df1e 100644 --- a/.github/workflows/feat-deploy.yml +++ b/.github/workflows/feat-deploy.yml @@ -35,72 +35,6 @@ jobs: runs-on: wgd-dev steps: - - name: Extract branch name - shell: bash - run: echo "::set-env name=BRANCH_NAME::$(echo ${GITHUB_REF#refs/heads/} | sed 's/\//_/g')" - - name: Test - run: echo "${BRANCH_NAME}" - - - uses: actions/checkout@v3 - - - name: Use Node.js 20.x - uses: actions/setup-node@v3 - with: - node-version: 20 - cache: npm - - - name: Build action runner - run: docker build -t "wgd-action-runner:${BRANCH_NAME}" --build-arg "GIT_SHA=${GITHUB_SHA}" apps/wgd-action-runner - - - name: Build hugo docs - run: | - docker run \ - -v "${GITHUB_WORKSPACE}/hugo:/site" \ - -v "${GITHUB_WORKSPACE}/website:/website" \ - -v "/var/www/${BRANCH_NAME}.wikigdrive.com:/dist/hugo" \ - --env CONFIG_TOML="/site/config/_default/config.toml" --env BASE_URL="https://${BRANCH_NAME}.wikigdrive.com" \ - wgd-action-runner:${BRANCH_NAME} /steps/step_render_hugo - - - name: Copy index for vite - run: mkdir -p ${GITHUB_WORKSPACE}/dist/hugo && cp -rf /var/www/${BRANCH_NAME}.wikigdrive.com/* ${GITHUB_WORKSPACE}/dist/hugo - - - uses: whoan/docker-build-with-cache-action@v5 - with: - image_name: "wikigdrive-feature" - image_tag: "${{ github.sha }}" - push_image_and_stages: false - build_extra_args: "{'--build-arg': 'GIT_SHA=${{ github.sha }}'}" - - - name: Stop and remove - run: docker stop "wikigdrive-${BRANCH_NAME}" ; docker rm "wikigdrive-${BRANCH_NAME}" - continue-on-error: true - - - name: "Create empty volume" - run: docker volume rm -f "wikiGDrive${BRANCH_NAME}" ; docker volume create "wikiGDrive${BRANCH_NAME}" - - - name: Start - run: | - docker run -d --name "wikigdrive-${BRANCH_NAME}" \ - --restart unless-stopped \ - --network nginx \ - -v "wikiGDrive${BRANCH_NAME}":/data \ - -v /home/wikigdrive/service_account.json:/service_account.json \ - -v /home/wikigdrive/env.develop:/usr/src/app/.env \ - -v /var/run/docker.sock:/var/run/docker.sock \ - -v "/var/www/${BRANCH_NAME}.wikigdrive.com:/usr/src/app/dist/hugo" \ - -e "GIT_SHA=${GITHUB_SHA}" \ - -e "ZIPKIN_URL=https://${BRANCH_NAME}.wikigdrive.com/zipkin" \ - -e "ZIPKIN_SERVICE=wikigdrive-${BRANCH_NAME}" \ - --link=zipkin:zipkin \ - "wikigdrive-feature:${GITHUB_SHA}" wikigdrive \ - --service_account /service_account.json \ - --share_email mie-docs-wikigdrive@wikigdrive.iam.gserviceaccount.com \ - --workdir /data \ - server 3000 - - - name: "Nginx setup" - run: "TODO" - - name: Create pull request id: open-pr uses: repo-sync/pull-request@v2 diff --git a/.github/workflows/pull-request.yml b/.github/workflows/pull-request.yml index 9734c854..290cce87 100644 --- a/.github/workflows/pull-request.yml +++ b/.github/workflows/pull-request.yml @@ -3,9 +3,10 @@ name: Pull request created on: pull_request: branches: [ master ] + types: [submitted, edited, synchronize] jobs: - build: + test: runs-on: ubuntu-latest steps: @@ -29,43 +30,68 @@ jobs: - name: Test run: npm run test - test: + build: + needs: test runs-on: wgd-dev steps: - - uses: actions/checkout@v3 - - - name: Use Node.js 20.x - uses: actions/setup-node@v3 - with: - node-version: 20 - cache: npm - - - name: Build action runner - run: docker build -t "wgd-action-runner:test" --build-arg "GIT_SHA=${GITHUB_SHA}" apps/wgd-action-runner - - - name: Build hugo docs - run: | - docker run \ - -v "${GITHUB_WORKSPACE}/hugo:/site" \ - -v "${GITHUB_WORKSPACE}/website:/website" \ - -v "/var/www/test.wikigdrive.com:/dist/hugo" \ - --env CONFIG_TOML="/site/config/_default/config.toml" --env BASE_URL="https://test.wikigdrive.com" \ - wgd-action-runner:test /steps/step_render_hugo - - - name: Copy index for vite - run: mkdir -p dist/hugo && cp -rf /var/www/test.wikigdrive.com/* dist/hugo - - - name: Build - run: docker build -t wikigdrive-test --build-arg "GIT_SHA=${GITHUB_SHA}" . - - - name: Stop - run: docker stop wikigdrive-test - continue-on-error: true - - - name: Remove - run: docker rm wikigdrive-test - continue-on-error: true - - - name: Start - run: docker run -t -v wikiGDriveExample:/data -v /home/wikigdrive/service_account.json:/service_account.json -v "/var/www/dev.wikigdrive.com:/usr/src/app/dist/hugo" wikigdrive-test wikigdrive --service_account /service_account.json --share_email mie-docs-wikigdrive@wikigdrive.iam.gserviceaccount.com --transform_subdir / --workdir /data pull 0AIkOKXbzWCtSUk9PVA + - name: Test + run: echo "${{ github.event.number }}" + + - uses: actions/checkout@v3 + + - name: Use Node.js 20.x + uses: actions/setup-node@v3 + with: + node-version: 20 + cache: npm + + - name: Build action runner + run: docker build -t "wgd-action-runner:pr-${{ github.event.number }}" --build-arg "GIT_SHA=${GITHUB_SHA}" apps/wgd-action-runner + + - name: Build hugo docs + run: | + docker run \ + -v "${GITHUB_WORKSPACE}/hugo:/site" \ + -v "${GITHUB_WORKSPACE}/website:/website" \ + -v "/var/www/pr-${{ github.event.number }}.wikigdrive.com:/dist/hugo" \ + --env CONFIG_TOML="/site/config/_default/config.toml" --env BASE_URL="https://pr-${{ github.event.number }}.wikigdrive.com" \ + wgd-action-runner:pr-${{ github.event.number }} /steps/step_render_hugo + + - name: Copy index for vite + run: mkdir -p ${GITHUB_WORKSPACE}/dist/hugo && cp -rf /var/www/pr-${{ github.event.number }}.wikigdrive.com/* ${GITHUB_WORKSPACE}/dist/hugo + + - name: build + uses: whoan/docker-build-with-cache-action@v5 + with: + image_name: "wikigdrive-feature" + image_tag: "${{ github.sha }}" + push_image_and_stages: false + build_extra_args: "{'--build-arg': 'GIT_SHA=${{ github.sha }}'}" + + - name: Stop and remove + run: docker stop "pr-${{ github.event.number }}" ; docker rm "pr-${{ github.event.number }}" + continue-on-error: true + + - name: "Create empty volume" + run: docker volume rm -f "pr-${{ github.event.number }}" ; docker volume create "pr-${{ github.event.number }}" + + - name: Start + run: | + docker run -d --name "pr-${{ github.event.number }}" \ + --restart unless-stopped \ + --network nginx \ + -v "pr-${{ github.event.number }}":/data \ + -v /home/wikigdrive/service_account.json:/service_account.json \ + -v /home/wikigdrive/env.develop:/usr/src/app/.env \ + -v /var/run/docker.sock:/var/run/docker.sock \ + -v "/var/www/pr-${{ github.event.number }}.wikigdrive.com:/usr/src/app/dist/hugo" \ + -e "GIT_SHA=${GITHUB_SHA}" \ + -e "ZIPKIN_URL=https://pr-${{ github.event.number }}.wikigdrive.com/zipkin" \ + -e "ZIPKIN_SERVICE=pr-${{ github.event.number }}" \ + --link=zipkin:zipkin \ + "wikigdrive-feature:${GITHUB_SHA}" wikigdrive \ + --service_account /service_account.json \ + --share_email mie-docs-wikigdrive@wikigdrive.iam.gserviceaccount.com \ + --workdir /data \ + server 3000 From fb6d501bb6e7a541a1b432a23ea839703ff1029a Mon Sep 17 00:00:00 2001 From: Grzegorz Godlewski Date: Tue, 2 Jul 2024 20:43:17 +0200 Subject: [PATCH 3/5] Add authentication through main instance --- .github/workflows/pull-request.yml | 11 +++--- src/containers/server/ServerContainer.ts | 19 +++------- src/containers/server/auth.ts | 34 +++++++++++------- src/containers/server/routes/Controller.ts | 9 +++-- .../server/routes/DriveUiController.ts | 29 ++++++++------- .../server/routes/FolderController.ts | 36 +++++++++---------- .../server/routes/GoogleDriveController.ts | 33 ++++++++--------- src/google/AuthClient.ts | 8 ++--- 8 files changed, 88 insertions(+), 91 deletions(-) diff --git a/.github/workflows/pull-request.yml b/.github/workflows/pull-request.yml index 290cce87..0966a171 100644 --- a/.github/workflows/pull-request.yml +++ b/.github/workflows/pull-request.yml @@ -3,7 +3,7 @@ name: Pull request created on: pull_request: branches: [ master ] - types: [submitted, edited, synchronize] + types: [edited, synchronize] jobs: test: @@ -47,7 +47,7 @@ jobs: cache: npm - name: Build action runner - run: docker build -t "wgd-action-runner:pr-${{ github.event.number }}" --build-arg "GIT_SHA=${GITHUB_SHA}" apps/wgd-action-runner + run: docker build -t "wgd-action-runner:pr-${{ github.event.number }}" --build-arg "GIT_SHA=${{ github.sha }}" apps/wgd-action-runner - name: Build hugo docs run: | @@ -86,11 +86,14 @@ jobs: -v /home/wikigdrive/env.develop:/usr/src/app/.env \ -v /var/run/docker.sock:/var/run/docker.sock \ -v "/var/www/pr-${{ github.event.number }}.wikigdrive.com:/usr/src/app/dist/hugo" \ - -e "GIT_SHA=${GITHUB_SHA}" \ + -e "GIT_SHA=${{ github.sha }}" \ -e "ZIPKIN_URL=https://pr-${{ github.event.number }}.wikigdrive.com/zipkin" \ -e "ZIPKIN_SERVICE=pr-${{ github.event.number }}" \ + -e "AUTH_DOMAIN=https://dev.wikigdrive.com" \ + -e "AUTH_INSTANCE=pr-${{ github.event.number }}" \ + -e "DOMAIN=https://pr-${{ github.event.number }}.wikigdrive.com" \ --link=zipkin:zipkin \ - "wikigdrive-feature:${GITHUB_SHA}" wikigdrive \ + "wikigdrive-feature:${{ github.sha }}" wikigdrive \ --service_account /service_account.json \ --share_email mie-docs-wikigdrive@wikigdrive.iam.gserviceaccount.com \ --workdir /data \ diff --git a/src/containers/server/ServerContainer.ts b/src/containers/server/ServerContainer.ts index 3b70554a..fbf89385 100644 --- a/src/containers/server/ServerContainer.ts +++ b/src/containers/server/ServerContainer.ts @@ -10,7 +10,6 @@ import rateLimit from 'express-rate-limit'; import compress from 'compression'; import {Container, ContainerConfig, ContainerEngine} from '../../ContainerEngine.ts'; -import {FileId} from '../../model/model.ts'; import {saveRunningInstance} from './loadRunningInstance.ts'; import {urlToFolderId} from '../../utils/idParsers.ts'; import {GoogleDriveService} from '../../google/GoogleDriveService.ts'; @@ -51,15 +50,6 @@ const __dirname = path.dirname(__filename); const HTML_DIR = __dirname + '/../../../apps/ui'; const MAIN_DIR = __dirname + '/../../..'; -interface TreeItem { - id: FileId; - name: string; - mimeType: string; - children?: TreeItem[]; -} - -export const isHtml = req => req.headers.accept.indexOf('text/html') > -1; - function getDurationInMilliseconds(start) { const NS_PER_SEC = 1e9; const NS_TO_MS = 1e6; @@ -153,7 +143,7 @@ export class ServerContainer extends Container { async initAuth(app) { app.use('/auth/logout', authenticateOptionally(this.logger)); - app.post('/auth/logout', async (req, res, next) => { + app.post('/auth/logout', async (req, res) => { if (req.user?.google_access_token) { const authClient = new UserAuthClient(process.env.GOOGLE_AUTH_CLIENT_ID, process.env.GOOGLE_AUTH_CLIENT_SECRET); await authClient.revokeToken(req.user.google_access_token); @@ -165,9 +155,7 @@ export class ServerContainer extends Container { app.get('/auth/:driveId', async (req, res, next) => { try { - const hostname = req.header('host'); - const protocol = hostname.indexOf('localhost') > -1 ? 'http://' : 'https://'; - const serverUrl = protocol + hostname; + const serverUrl = process.env.AUTH_DOMAIN || process.env.DOMAIN; const driveId = urlToFolderId(req.params.driveId); const redirectTo = req.query.redirectTo; const popupWindow = req.query.popupWindow; @@ -175,7 +163,8 @@ export class ServerContainer extends Container { const state = new URLSearchParams(filterParams({ driveId: driveId !== 'none' ? (driveId || '') : '', redirectTo, - popupWindow: popupWindow === 'true' ? 'true' : '' + popupWindow: popupWindow === 'true' ? 'true' : '', + instance: process.env.AUTH_INSTANCE })).toString(); const authClient = new UserAuthClient(process.env.GOOGLE_AUTH_CLIENT_ID, process.env.GOOGLE_AUTH_CLIENT_SECRET); diff --git a/src/containers/server/auth.ts b/src/containers/server/auth.ts index 82c70036..214d7599 100644 --- a/src/containers/server/auth.ts +++ b/src/containers/server/auth.ts @@ -1,12 +1,12 @@ import jsonwebtoken from 'jsonwebtoken'; -import {decrypt, encrypt} from '../../google/GoogleAuthService'; -import {GoogleDriveService} from '../../google/GoogleDriveService'; -import {Logger} from 'winston'; import type {Request, Response} from 'express'; -import {UserAuthClient} from '../../google/AuthClient'; -import {FolderRegistryContainer} from '../folder_registry/FolderRegistryContainer'; -import {urlToFolderId} from '../../utils/idParsers'; -import {initJob, JobManagerContainer} from '../job/JobManagerContainer'; +import {Logger} from 'winston'; +import {decrypt, encrypt} from '../../google/GoogleAuthService.ts'; +import {GoogleDriveService} from '../../google/GoogleDriveService.ts'; +import {UserAuthClient} from '../../google/AuthClient.ts'; +import {FolderRegistryContainer} from '../folder_registry/FolderRegistryContainer.ts'; +import {urlToFolderId} from '../../utils/idParsers.ts'; +import {initJob, JobManagerContainer} from '../job/JobManagerContainer.ts'; export class AuthError extends Error { public status: number; @@ -21,7 +21,7 @@ export class AuthError extends Error { export function redirError(req: Request, msg: string) { const err = new AuthError(msg + ' for: ' + req.originalUrl, 401); - const [empty, driveId] = req.path.split('/'); + const [, driveId] = req.path.split('/'); const redirectTo: string = req.headers['redirect-to'] ? req.headers['redirect-to'].toString() : ''; if (redirectTo && redirectTo.startsWith('/') && redirectTo.indexOf('//') === -1) { @@ -177,7 +177,7 @@ function sanitizeRedirect(redirectTo: string) { return `/drive/${folderId}`; } -export async function getAuth(req, res: Response, next) { +export async function getAuth(req: Request, res: Response, next) { try { const hostname = req.header('host'); const protocol = hostname.indexOf('localhost') > -1 ? 'http://' : 'https://'; @@ -185,6 +185,14 @@ export async function getAuth(req, res: Response, next) { const state = new URLSearchParams(req.query.state.toString()); + if (!process.env.AUTH_INSTANCE) { // main auth host + const instance = state.get('instance'); + if (instance && instance.match(/^pr-\d+$/)) { + res.redirect(`https://${instance}.wikigdrive.com${req.originalUrl}`); + return; + } + } + const driveId = urlToFolderId(state.get('driveId')); const folderRegistryContainer = this.engine.getContainer('folder_registry'); @@ -192,7 +200,7 @@ export async function getAuth(req, res: Response, next) { if (driveId && shareDrive) { const googleDriveService = new GoogleDriveService(this.logger, null); const authClient = new UserAuthClient(process.env.GOOGLE_AUTH_CLIENT_ID, process.env.GOOGLE_AUTH_CLIENT_SECRET); - await authClient.authorizeResponseCode(req.query.code, `${serverUrl}/auth`); + await authClient.authorizeResponseCode(req.query.code.toString(), `${serverUrl}/auth`); await googleDriveService.shareDrive(await authClient.getAccessToken(), driveId, this.params.share_email); @@ -204,7 +212,7 @@ export async function getAuth(req, res: Response, next) { const uploadDrive = !!state.get('uploadDrive'); if (driveId && uploadDrive) { const authClient = new UserAuthClient(process.env.GOOGLE_AUTH_CLIENT_ID, process.env.GOOGLE_AUTH_CLIENT_SECRET); - await authClient.authorizeResponseCode(req.query.code, `${serverUrl}/auth`); + await authClient.authorizeResponseCode(req.query.code.toString(), `${serverUrl}/auth`); const jobManagerContainer = this.engine.getContainer('job_manager'); await jobManagerContainer.schedule(driveId, { @@ -226,7 +234,7 @@ export async function getAuth(req, res: Response, next) { const redirectTo = sanitizeRedirect(state.get('redirectTo')); const authClient = new UserAuthClient(process.env.GOOGLE_AUTH_CLIENT_ID, process.env.GOOGLE_AUTH_CLIENT_SECRET); - await authClient.authorizeResponseCode(req.query.code, `${serverUrl}/auth`); + await authClient.authorizeResponseCode(req.query.code.toString(), `${serverUrl}/auth`); const googleDriveService = new GoogleDriveService(this.logger, null); const googleUser: GoogleUser = await authClient.getUser(await authClient.getAccessToken()); @@ -257,7 +265,7 @@ export async function getAuth(req, res: Response, next) { } catch (err) { if (err.message.indexOf('invalid_grant') > -1) { if (req.query.state) { - const state = new URLSearchParams(req.query.state); + const state = new URLSearchParams(req.query.state.toString()); const redirectTo = state.get('redirectTo'); res.redirect(redirectTo || '/'); } else { diff --git a/src/containers/server/routes/Controller.ts b/src/containers/server/routes/Controller.ts index 8a89a6da..3ae57ca2 100644 --- a/src/containers/server/routes/Controller.ts +++ b/src/containers/server/routes/Controller.ts @@ -1,8 +1,7 @@ -import type { Router } from 'express'; import type * as express from 'express'; -import SwaggerDocService from './SwaggerDocService'; import winston from 'winston'; -import {instrumentAndWrap} from '../../../telemetry'; +import SwaggerDocService from './SwaggerDocService.ts'; +import {instrumentAndWrap} from '../../../telemetry.ts'; // import SwaggerDocService from '../api-docs.api/SwaggerDocService'; export const HttpStatus = { @@ -104,8 +103,8 @@ export class ErrorHandler implements ControllerCallContext { export interface ControllerRoute { errorHandlers: ErrorHandler[]; - inputFilters: RouteFilter[]; - outputFilters: RouteFilter[]; + inputFilters: RouteFilter[]; + outputFilters: RouteFilter[]; roles: string[]; method?: string; routePath?: string; diff --git a/src/containers/server/routes/DriveUiController.ts b/src/containers/server/routes/DriveUiController.ts index ac031043..3aeec679 100644 --- a/src/containers/server/routes/DriveUiController.ts +++ b/src/containers/server/routes/DriveUiController.ts @@ -1,20 +1,20 @@ +import {Logger} from 'winston'; import { Controller, RouteErrorHandler, RouteGet, RouteParamQuery, RouteResponse -} from './Controller'; -import {FileContentService} from '../../../utils/FileContentService'; -import {Logger} from 'winston'; -import {ShareErrorHandler} from './FolderController'; -import {filterParams} from '../../../google/driveFetch'; -import {GoogleDriveService} from '../../../google/GoogleDriveService'; -import {GoogleApiContainer} from '../../google_api/GoogleApiContainer'; -import {MarkdownTreeProcessor} from '../../transform/MarkdownTreeProcessor'; -import {UserConfigService} from '../../google_folder/UserConfigService'; -import {UserAuthClient} from '../../../google/AuthClient'; -import {getContentFileService} from '../../transform/utils'; +} from './Controller.ts'; +import {FileContentService} from '../../../utils/FileContentService.ts'; +import {ShareErrorHandler} from './FolderController.ts'; +import {filterParams} from '../../../google/driveFetch.ts'; +import {GoogleDriveService} from '../../../google/GoogleDriveService.ts'; +import {GoogleApiContainer} from '../../google_api/GoogleApiContainer.ts'; +import {MarkdownTreeProcessor} from '../../transform/MarkdownTreeProcessor.ts'; +import {UserConfigService} from '../../google_folder/UserConfigService.ts'; +import {UserAuthClient} from '../../../google/AuthClient.ts'; +import {getContentFileService} from '../../transform/utils.ts'; export class DriveUiController extends Controller { @@ -31,7 +31,6 @@ export class DriveUiController extends Controller { throw new Error('No state query parameter'); } const obj = JSON.parse(state); - const userId = obj.userId; const action = obj.action; const ids = obj.ids; @@ -44,8 +43,7 @@ export class DriveUiController extends Controller { const drives = await this.googleApiContainer.listDrives(); const driveIds = drives.map(drive => drive.id); - const googleFile = await googleDriveService.getFile(auth, fileId); - let dir = googleFile; + let dir = await googleDriveService.getFile(auth, fileId); while (dir.parentId) { dir = await googleDriveService.getFile(auth, dir.parentId); } @@ -94,10 +92,11 @@ export class DriveUiController extends Controller { @RouteErrorHandler(new ShareErrorHandler()) @RouteResponse('stream') async getInstall() { - const serverUrl = process.env.DOMAIN; + const serverUrl = process.env.AUTH_DOMAIN || process.env.DOMAIN; const state = new URLSearchParams(filterParams({ driveui: 1, + instance: process.env.AUTH_INSTANCE // driveId: driveId !== 'none' ? (driveId || '') : '', // redirectTo })).toString(); diff --git a/src/containers/server/routes/FolderController.ts b/src/containers/server/routes/FolderController.ts index 8e2d41e6..cfc8674a 100644 --- a/src/containers/server/routes/FolderController.ts +++ b/src/containers/server/routes/FolderController.ts @@ -1,27 +1,27 @@ +import type * as express from 'express'; +import {Logger} from 'winston'; import { Controller, ErrorHandler, RouteErrorHandler, RouteParamPath, RouteParamMethod, RouteResponse, RouteUse, RouteParamBody -} from './Controller'; -import {MimeTypes} from '../../../model/GoogleFile'; -import {AuthConfig} from '../../../model/AccountJson'; -import {FileContentService} from '../../../utils/FileContentService'; -import type * as express from 'express'; -import {TreeItem} from '../../../model/TreeItem'; -import {UserConfigService} from '../../google_folder/UserConfigService'; -import {DirectoryScanner, isTextFileName} from '../../transform/DirectoryScanner'; -import {GitChange, GitScanner} from '../../../git/GitScanner'; -import {MarkdownTreeProcessor} from '../../transform/MarkdownTreeProcessor'; -import {Logger} from 'winston'; -import {clearCachedChanges} from '../../job/JobManagerContainer'; -import {getContentFileService} from '../../transform/utils'; -import {LocalLog} from '../../transform/LocalLog'; -import {ContainerEngine} from '../../../ContainerEngine'; -import {FolderRegistryContainer} from '../../folder_registry/FolderRegistryContainer'; -import {GoogleTreeProcessor} from '../../google_folder/GoogleTreeProcessor'; -import {FileId} from '../../../model/model'; +} from './Controller.ts'; +import {MimeTypes} from '../../../model/GoogleFile.ts'; +import {AuthConfig} from '../../../model/AccountJson.ts'; +import {FileContentService} from '../../../utils/FileContentService.ts'; +import {TreeItem} from '../../../model/TreeItem.ts'; +import {UserConfigService} from '../../google_folder/UserConfigService.ts'; +import {DirectoryScanner, isTextFileName} from '../../transform/DirectoryScanner.ts'; +import {GitChange, GitScanner} from '../../../git/GitScanner.ts'; +import {MarkdownTreeProcessor} from '../../transform/MarkdownTreeProcessor.ts'; +import {clearCachedChanges} from '../../job/JobManagerContainer.ts'; +import {getContentFileService} from '../../transform/utils.ts'; +import {LocalLog} from '../../transform/LocalLog.ts'; +import {ContainerEngine} from '../../../ContainerEngine.ts'; +import {FolderRegistryContainer} from '../../folder_registry/FolderRegistryContainer.ts'; +import {GoogleTreeProcessor} from '../../google_folder/GoogleTreeProcessor.ts'; +import {FileId} from '../../../model/model.ts'; export const extToMime = { 'js': 'application/javascript', diff --git a/src/containers/server/routes/GoogleDriveController.ts b/src/containers/server/routes/GoogleDriveController.ts index 77cfe65f..98301c84 100644 --- a/src/containers/server/routes/GoogleDriveController.ts +++ b/src/containers/server/routes/GoogleDriveController.ts @@ -5,17 +5,17 @@ import { RouteParamPath, RouteParamUser, RouteResponse -} from './Controller'; -import {FileContentService} from '../../../utils/FileContentService'; -import {addPreviewUrl, getCachedChanges, outputDirectory, ShareErrorHandler} from './FolderController'; -import {UserConfigService} from '../../google_folder/UserConfigService'; -import {MarkdownTreeProcessor} from '../../transform/MarkdownTreeProcessor'; -import {getContentFileService} from '../../transform/utils'; -import {GoogleTreeProcessor} from '../../google_folder/GoogleTreeProcessor'; -import {UserAuthClient} from '../../../google/AuthClient'; -import {filterParams} from '../../../google/driveFetch'; -import {GoogleDriveService} from '../../../google/GoogleDriveService'; -import {redirError} from '../auth'; +} from './Controller.ts'; +import {FileContentService} from '../../../utils/FileContentService.ts'; +import {addPreviewUrl, getCachedChanges, outputDirectory, ShareErrorHandler} from './FolderController.ts'; +import {UserConfigService} from '../../google_folder/UserConfigService.ts'; +import {MarkdownTreeProcessor} from '../../transform/MarkdownTreeProcessor.ts'; +import {getContentFileService} from '../../transform/utils.ts'; +import {GoogleTreeProcessor} from '../../google_folder/GoogleTreeProcessor.ts'; +import {UserAuthClient} from '../../../google/AuthClient.ts'; +import {filterParams} from '../../../google/driveFetch.ts'; +import {GoogleDriveService} from '../../../google/GoogleDriveService.ts'; +import {redirError} from '../auth.ts'; export class GoogleDriveController extends Controller { @@ -25,11 +25,12 @@ export class GoogleDriveController extends Controller { @RouteGet('/:driveId/share') async getShare(@RouteParamUser() user, @RouteParamPath('driveId') driveId: string) { - const serverUrl = process.env.DOMAIN; + const serverUrl = process.env.AUTH_DOMAIN || process.env.DOMAIN; const state = new URLSearchParams(filterParams({ shareDrive: 1, - driveId: driveId !== 'none' ? (driveId || '') : '' + driveId: driveId !== 'none' ? (driveId || '') : '', + instance: process.env.AUTH_INSTANCE })).toString(); const authClient = new UserAuthClient(process.env.GOOGLE_AUTH_CLIENT_ID, process.env.GOOGLE_AUTH_CLIENT_SECRET); @@ -43,11 +44,12 @@ export class GoogleDriveController extends Controller { @RouteGet('/:driveId/upload') async getUpload(@RouteParamUser() user, @RouteParamPath('driveId') driveId: string) { - const serverUrl = process.env.DOMAIN; + const serverUrl = process.env.AUTH_DOMAIN || process.env.DOMAIN; const state = new URLSearchParams(filterParams({ uploadDrive: 1, - driveId: driveId !== 'none' ? (driveId || '') : '' + driveId: driveId !== 'none' ? (driveId || '') : '', + instance: process.env.AUTH_INSTANCE })).toString(); const authClient = new UserAuthClient(process.env.GOOGLE_AUTH_CLIENT_ID, process.env.GOOGLE_AUTH_CLIENT_SECRET); @@ -104,7 +106,6 @@ export class GoogleDriveController extends Controller { } catch (err) { if (err.status === 401) { throw redirError(this.req, err.message); - return; } } diff --git a/src/google/AuthClient.ts b/src/google/AuthClient.ts index d3fab160..e421cc43 100644 --- a/src/google/AuthClient.ts +++ b/src/google/AuthClient.ts @@ -1,12 +1,12 @@ 'use strict'; -import {convertResponseToError, GoogleDriveServiceError} from './driveFetch'; -import {ServiceAccountJson} from '../model/AccountJson'; import jsonwebtoken from 'jsonwebtoken'; -import {AuthError, GoogleUser} from '../containers/server/auth'; import open from 'open'; import readline from 'readline'; import {promisify} from 'util'; +import {convertResponseToError} from './driveFetch.ts'; +import {ServiceAccountJson} from '../model/AccountJson.ts'; +import {AuthError, GoogleUser} from '../containers/server/auth.ts'; export const SCOPES = [ 'https://www.googleapis.com/auth/userinfo.email', @@ -58,8 +58,6 @@ async function refreshToken(client_id: string, client_secret: string, refresh_to export async function getCliCode(client_id: string): Promise { const authUrl = 'https://accounts.google.com/o/oauth2/v2/auth?' + new URLSearchParams({ client_id, - // redirect_uri: , - // response_type: 'code', access_type: 'offline', include_granted_scopes: 'true', scope: SCOPES.join(' '), From 53d17bcfdd1b3a05962f51b97b72e0f0d161531f Mon Sep 17 00:00:00 2001 From: Grzegorz Godlewski Date: Tue, 2 Jul 2024 23:24:36 +0200 Subject: [PATCH 4/5] Fix redirect --- src/containers/server/auth.ts | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/src/containers/server/auth.ts b/src/containers/server/auth.ts index 214d7599..f12d07ae 100644 --- a/src/containers/server/auth.ts +++ b/src/containers/server/auth.ts @@ -150,6 +150,14 @@ export async function handleShare(req: Request, res: Response, next) { export async function handlePopupClose(req: Request, res: Response, next) { try { const state = new URLSearchParams(req.query.state.toString()); + if (!process.env.AUTH_INSTANCE) { // main auth host + const instance = state.get('instance'); + if (instance && instance.match(/^pr-\d+$/)) { + next(); + return; + } + } + if (state.get('popupWindow') === 'true') { openerRedirect(res, req.url.replace('popupWindow', '')); return; From a89314ed89a50dfc63ef8b448bc63ef3afa55728 Mon Sep 17 00:00:00 2001 From: Grzegorz Godlewski Date: Tue, 2 Jul 2024 23:44:16 +0200 Subject: [PATCH 5/5] Fix redirect uri mismatch --- src/containers/server/auth.ts | 12 +++--------- 1 file changed, 3 insertions(+), 9 deletions(-) diff --git a/src/containers/server/auth.ts b/src/containers/server/auth.ts index f12d07ae..1edb03cd 100644 --- a/src/containers/server/auth.ts +++ b/src/containers/server/auth.ts @@ -109,9 +109,7 @@ export function validateGetAuthState(req: Request, res: Response, next) { export async function handleDriveUiInstall(req: Request, res: Response, next) { try { - const hostname = req.header('host'); - const protocol = hostname.indexOf('localhost') > -1 ? 'http://' : 'https://'; - const serverUrl = protocol + hostname; + const serverUrl = process.env.AUTH_DOMAIN || process.env.DOMAIN; const state = new URLSearchParams(req.query.state.toString()); const driveui = urlToFolderId(state.get('driveui')); @@ -129,9 +127,7 @@ export async function handleDriveUiInstall(req: Request, res: Response, next) { export async function handleShare(req: Request, res: Response, next) { try { - const hostname = req.header('host'); - const protocol = hostname.indexOf('localhost') > -1 ? 'http://' : 'https://'; - const serverUrl = protocol + hostname; + const serverUrl = process.env.AUTH_DOMAIN || process.env.DOMAIN; const state = new URLSearchParams(req.query.state.toString()); const shareId = urlToFolderId(state.get('shareId')); @@ -187,9 +183,7 @@ function sanitizeRedirect(redirectTo: string) { export async function getAuth(req: Request, res: Response, next) { try { - const hostname = req.header('host'); - const protocol = hostname.indexOf('localhost') > -1 ? 'http://' : 'https://'; - const serverUrl = protocol + hostname; + const serverUrl = process.env.AUTH_DOMAIN || process.env.DOMAIN; const state = new URLSearchParams(req.query.state.toString());