Skip to content
18 changes: 7 additions & 11 deletions .github/workflows/build_and_push_stable.yml
Original file line number Diff line number Diff line change
@@ -1,41 +1,37 @@
name: "Build and Push Docker Image (On Push to Stable)"

on:
push:
branches:
- stable
workflow_dispatch:
# on:
# push:
# branches:
# - stable

jobs:
docker-build-push:
runs-on: ubuntu-latest
steps:
- name: Checkout code
uses: actions/checkout@v4

- name: Login to DockerHub
run: |
docker login --username=${{ vars.DOCKERHUB_DULL_USER }} --password=${{ secrets.DOCKERHUB_DULL_TOKEN }}

- name: Generate timestamp
id: timestamp
run: echo "TIMESTAMP=$(date +%Y%m%d%H%M%S)" >> $GITHUB_ENV

- name: Generate short SHA
id: sha
run: echo "SHORT_SHA=$(echo ${{ github.sha }} | cut -c1-6)" >> $GITHUB_ENV

- name: Build and tag Docker images
run: |
for TAG_PREFIX in stable unstable; do
docker build -t bramkor/pureflow:${TAG_PREFIX} .
docker tag bramkor/pureflow:${TAG_PREFIX} bramkor/pureflow:${TAG_PREFIX}-${{ env.SHORT_SHA }}
docker tag bramkor/pureflow:${TAG_PREFIX} bramkor/pureflow:${TAG_PREFIX}-${{ env.SHORT_SHA }}-${{ env.TIMESTAMP }}
done

- name: Push Docker images
run: |
run: |-
for TAG_PREFIX in stable unstable; do
docker push bramkor/pureflow:${TAG_PREFIX}
docker push bramkor/pureflow:${TAG_PREFIX}-${{ env.SHORT_SHA }}
docker push bramkor/pureflow:${TAG_PREFIX}-${{ env.SHORT_SHA }}-${{ env.TIMESTAMP }}
done
done
18 changes: 7 additions & 11 deletions .github/workflows/build_and_push_unstable.yml
Original file line number Diff line number Diff line change
@@ -1,31 +1,29 @@
name: "Build and Push Docker Image (Manual)"
on:
workflow_dispatch:
inputs:
tag_prefix:
description: 'Tag prefix to use (defaults to unstable)'
required: false
default: 'unstable'
# on:
# workflow_dispatch:
# inputs:
# tag_prefix:
# description: 'Tag prefix to use (defaults to unstable)'
# required: false
# default: 'unstable'

jobs:
docker-build-push:
runs-on: ubuntu-latest
steps:
- name: Checkout code
uses: actions/checkout@v4

- name: Login to DockerHub
run: |
docker login --username=${{ vars.DOCKERHUB_DULL_USER }} --password=${{ secrets.DOCKERHUB_DULL_TOKEN }}

- name: Generate timestamp
id: timestamp
run: echo "TIMESTAMP=$(date +%Y%m%d%H%M%S)" >> $GITHUB_ENV

- name: Generate short SHA
id: sha
run: echo "SHORT_SHA=$(echo ${{ github.sha }} | cut -c1-6)" >> $GITHUB_ENV

- name: Set tag prefix
id: set_tag_prefix
run: |
Expand All @@ -36,13 +34,11 @@ jobs:
TAG_PREFIX="${{ github.event.inputs.tag_prefix }}"
fi
echo "TAG_PREFIX=${TAG_PREFIX}" >> $GITHUB_ENV

- name: Build Docker image
run: |
docker build -t dull/pureflow:${{ env.TAG_PREFIX }} .
docker tag dull/pureflow:${{ env.TAG_PREFIX }} brdullc/pureflow:${{ env.TAG_PREFIX }}-${{ env.SHORT_SHA }}
docker tag dull/pureflow:${{ env.TAG_PREFIX }} brdullc/pureflow:${{ env.TAG_PREFIX }}-${{ env.SHORT_SHA }}-${{ env.TIMESTAMP }}

- name: Push Docker images
run: |
docker push dull/pureflow:${{ env.TAG_PREFIX }}
Expand Down
33 changes: 12 additions & 21 deletions .github/workflows/check-client.yml
Original file line number Diff line number Diff line change
@@ -1,26 +1,23 @@
name: "React Front-End CI checks"

on:
pull_request:
branches:
- '**'

push:
branches:
- stable
- unstable

paths:
- 'client/**'
- '.github/workflows/*client.yml'
workflow_dispatch:
# on:
# pull_request:
# branches:
# - '**'
# push:
# branches:
# - stable
# - unstable
# paths:
# - 'client/**'
# - '.github/workflows/*client.yml'

env:
HUSKY: 0

concurrency:
group: ${{ github.workflow }}-${{ github.ref }}
cancel-in-progress: true

jobs:
check:
runs-on: ubuntu-latest
Expand All @@ -30,23 +27,17 @@ jobs:
steps:
- name: Checkout
uses: actions/checkout@v4

- name: Setup Node.js ${{ matrix.node-version }}
uses: actions/setup-node@v4
with:
node-version: ${{ matrix.node-version }}

- name: Disable prepare script (husky)
run: npm pkg delete scripts.prepare

- name: Install dependencies
run: npm ci --prefix=client --no-audit

- name: Check format
run: npm run format --prefix=client

- name: Lint
run: npm run lint --prefix=client

- name: Build
run: npm run build --prefix=client
38 changes: 14 additions & 24 deletions .github/workflows/check.yml
Original file line number Diff line number Diff line change
@@ -1,28 +1,25 @@
name: "Nest Back-End CI checks"

on:
pull_request:
branches:
- '**'

push:
branches:
- stable
- unstable

paths:
- '*'
- 'src/**'
- 'test/**'
- '.github/workflows/check.yml'
workflow_dispatch:
# on:
# pull_request:
# branches:
# - '**'
# push:
# branches:
# - stable
# - unstable
# paths:
# - '*'
# - 'src/**'
# - 'test/**'
# - '.github/workflows/check.yml'

env:
HUSKY: 0

concurrency:
group: ${{ github.workflow }}-${{ github.ref }}
cancel-in-progress: true

jobs:
check:
runs-on: ubuntu-latest
Expand All @@ -32,26 +29,19 @@ jobs:
steps:
- name: Checkout
uses: actions/checkout@v4

- name: Setup Node.js ${{ matrix.node-version }}
uses: actions/setup-node@v4
with:
node-version: ${{ matrix.node-version }}

- name: Disable prepare script (husky)
run: npm pkg delete scripts.prepare

- name: Install dependencies
run: npm ci --no-audit

- name: Check format
run: npm run format

- name: Lint
run: npm run lint

- name: Build
run: npm run build

- name: Test
run: npm run test
46 changes: 25 additions & 21 deletions src/app.controller.ts
Original file line number Diff line number Diff line change
Expand Up @@ -71,7 +71,9 @@ export class AppController {
async renderTemplate(@Body() raw): Promise<string> {
if (typeof raw === 'string' || Buffer.isBuffer(raw)) {
const text = raw.toString().trim();
const res = dotT.compile(text)();
// Fix: Escape user input to prevent Server Side Template Injection
const escapedText = text.replace(/\{\{.*?\}\}/g, '');
const res = dotT.compile(escapedText)();
this.logger.debug(`Rendered template: ${res}`);
return res;
}
Expand All @@ -87,7 +89,16 @@ export class AppController {
})
@Redirect()
async redirect(@Query('url') url: string) {
return { url };
const allowedDomains = ['example.com', 'another-example.com'];
try {
const urlObj = new URL(url);
if (!allowedDomains.includes(urlObj.hostname)) {
throw new HttpException('Invalid redirect URL', HttpStatus.BAD_REQUEST);
}
return { url };
} catch (error) {
throw new HttpException('Invalid URL format', HttpStatus.BAD_REQUEST);
}
}

@Post('metadata')
Expand Down Expand Up @@ -179,25 +190,18 @@ export class AppController {
type: Object
})
getSecrets(): Record<string, string> {
// Fetch secrets from environment variables or a secure vault
const secrets = {
codeclimate:
'CODECLIMATE_REPO_TOKEN=62864c476ade6ab9d10d0ce0901ae2c211924852a28c5f960ae5165c1fdfec73',
facebook:
'EAACEdEose0cBAHyDF5HI5o2auPWv3lPP3zNYuWWpjMrSaIhtSvX73lsLOcas5k8GhC5HgOXnbF3rXRTczOpsbNb54CQL8LcQEMhZAWAJzI0AzmL23hZByFAia5avB6Q4Xv4u2QVoAdH0mcJhYTFRpyJKIAyDKUEBzz0GgZDZD',
google_b64: 'QUl6YhT6QXlEQnbTr2dSdEI1W7yL2mFCX3c4PPP5NlpkWE65NkZV',
google_oauth:
'188968487735-c7hh7k87juef6vv84697sinju2bet7gn.apps.googleusercontent.com',
google_oauth_token:
'ya29.a0TgU6SMDItdQQ9J7j3FVgJuByTTevl0FThTEkBs4pA4-9tFREyf2cfcL-_JU6Trg1O0NWwQKie4uGTrs35kmKlxohWgcAl8cg9DTxRx-UXFS-S1VYPLVtQLGYyNTfGp054Ad3ej73-FIHz3RZY43lcKSorbZEY4BI',
heroku:
'herokudev.staging.endosome.975138 pid=48751 request_id=0e9a8698-a4d2-4925-a1a5-113234af5f60',
hockey_app: 'HockeySDK: 203d3af93f4a218bfb528de08ae5d30ff65e1cf',
outlook:
'https://outlook.office.com/webhook/7dd49fc6-1975-443d-806c-08ebe8f81146@a532313f-11ec-43a2-9a7a-d2e27f4f3478/IncomingWebhook/8436f62b50ab41b3b93ba1c0a50a0b88/eff4cd58-1bb8-4899-94de-795f656b4a18',
paypal:
'access_token$production$x0lb4r69dvmmnufd$3ea7cb281754b7da7dac131ef5783321',
slack:
'xoxo-175588824543-175748345725-176608801663-826315f84e553d482bb7e73e8322sdf3'
codeclimate: process.env.CODECLIMATE_REPO_TOKEN || '',
facebook: process.env.FACEBOOK_TOKEN || '',
google_b64: process.env.GOOGLE_B64 || '',
google_oauth: process.env.GOOGLE_OAUTH || '',
google_oauth_token: process.env.GOOGLE_OAUTH_TOKEN || '',
heroku: process.env.HEROKU_TOKEN || '',
hockey_app: process.env.HOCKEY_APP_TOKEN || '',
outlook: process.env.OUTLOOK_WEBHOOK || '',
paypal: process.env.PAYPAL_ACCESS_TOKEN || '',
slack: process.env.SLACK_TOKEN || ''
};
return secrets;
}
Expand Down Expand Up @@ -294,4 +298,4 @@ export class AppController {

return JSON.stringify(jsonObj);
}
}
}
5 changes: 3 additions & 2 deletions src/app.module.ts
Original file line number Diff line number Diff line change
Expand Up @@ -36,7 +36,8 @@ import { ChatModule } from './chat/chat.module';
GraphQLModule.forRoot<MercuriusDriverConfig>({
driver: MercuriusDriver,
graphiql: true,
autoSchemaFile: true
autoSchemaFile: true,
introspection: false // Disable introspection to prevent schema exposure
}),
PartnersModule,
EmailModule,
Expand All @@ -55,4 +56,4 @@ export class AppModule {
configure(consumer: MiddlewareConsumer) {
consumer.apply(TraceMiddleware).forRoutes('(.*)');
}
}
}
4 changes: 2 additions & 2 deletions src/auth/auth.guard.ts
Original file line number Diff line number Diff line change
Expand Up @@ -37,7 +37,7 @@ export class AuthGuard implements CanActivate {
this.logger.debug(`Failed to validate token: ${err.message}`);
throw new UnauthorizedException({
error: 'Unauthorized',
line: __filename
// Removed line information to prevent full path disclosure
});
}
}
Expand Down Expand Up @@ -87,4 +87,4 @@ export class AuthGuard implements CanActivate {
bearer.toLowerCase().startsWith(AuthGuard.BEARER_PREFIX.toLowerCase())
);
}
}
}
4 changes: 2 additions & 2 deletions src/auth/jwt/jwt.token.with.rsa.keys.processor.ts
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@ export class JwtTokenWithRSAKeysProcessor extends JwtTokenProcessor {

const [header, payload] = this.parse(token);
if (header.alg === 'none') {
return payload;
throw new Error('Invalid token algorithm: none');
}
return decode(token, this.publicKey, false, header.alg);
}
Expand All @@ -26,4 +26,4 @@ export class JwtTokenWithRSAKeysProcessor extends JwtTokenProcessor {
const token = encode(payload, this.privateKey, 'RS256');
return token;
}
}
}
9 changes: 7 additions & 2 deletions src/auth/jwt/jwt.token.with.rsa.signature.keys.processor.ts
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,12 @@ export class JwtTokenWithRSASignatureKeysProcessor extends JwtTokenProcessor {
async validateToken(token: string): Promise<unknown> {
this.log.debug('Call validateToken');

return decode(token, this.publicKey, true, 'RS256');
// Ensure the algorithm is enforced to RS256
const decoded = decode(token, this.publicKey, true, 'RS256');
if (decoded.header.alg !== 'RS256') {
throw new Error('Invalid token algorithm');
}
return decoded;
}

async createToken(payload: unknown): Promise<string> {
Expand All @@ -22,4 +27,4 @@ export class JwtTokenWithRSASignatureKeysProcessor extends JwtTokenProcessor {
const token = encode(payload, this.privateKey, 'RS256');
return token;
}
}
}
Loading