Merge pull request #2 from trufflesecurity/deployment-changes

deployment changes
This commit is contained in:
Dustin Decker 2023-01-27 14:55:01 -08:00 committed by GitHub
commit 14738e5eea
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
16 changed files with 2068 additions and 910 deletions

58
.github/ISSUE_TEMPLATE/bug_report.md vendored Normal file
View file

@ -0,0 +1,58 @@
---
name: Bug report
about: Create a report to help us improve
title: ""
labels: bug, needs triage
assignees: trufflesecurity/skunkworks
---
### Community Note
* Please vote on this issue by adding a 👍 [reaction](https://blog.github.com/2016-03-10-add-reactions-to-pull-requests-issues-and-comments/) to the original issue to help the community and maintainers prioritize this request
* Please do not leave "+1" or other comments that do not add relevant new information or questions, they generate extra noise for issue followers and do not help prioritize the request
* If you are interested in working on this issue or have submitted a pull request, please leave a comment
### TruffleHog Version
<!--- Please run `trufflehog --version` to show the version. If you are not running the latest version, please upgrade because your issue may have already been fixed. --->
### Trace Output
<!---
Please provide a link to a GitHub Gist containing the complete debug output. Please do NOT paste the debug output in the issue; just paste a link to the Gist.
To obtain the trace output, run trufflehog with the --trace flag.
--->
### Expected Behavior
<!--- What should have happened? --->
### Actual Behavior
<!--- What actually happened? --->
### Steps to Reproduce
<!--- Please list the steps required to reproduce the issue. --->
1. Go to '...'
2. Click on '....'
3. Scroll down to '....'
4. See error
## Environment
* OS: [e.g. iOS]
* Version [e.g. 22]
## Additional Context
<!--- Add any other context about the problem here. --->
### References
<!---
Information about referencing Github Issues: https://help.github.com/articles/basic-writing-and-formatting-syntax/#referencing-issues-and-pull-requests
Are there any other GitHub issues (open or closed) or pull requests that should be linked here? Vendor documentation? For example:
--->
* #0000

View file

@ -0,0 +1,38 @@
---
name: Feature request
about: Suggest an idea for this project
title: ""
labels: enhancement, needs triage
assignees: trufflesecurity/skunkworks
---
### Community Note
* Please vote on this issue by adding a 👍 [reaction](https://blog.github.com/2016-03-10-add-reactions-to-pull-requests-issues-and-comments/) to the original issue to help the community and maintainers prioritize this request
* Please do not leave "+1" or other comments that do not add relevant new information or questions, they generate extra noise for issue followers and do not help prioritize the request
* If you are interested in working on this issue or have submitted a pull request, please leave a comment
### Description
<!--- Please leave a helpful description of the feature request here. --->
## Problem to be Addressed
<!--- A clear and concise description of what the problem is. Ex. I'm always frustrated when [...] --->
## Description of the Preferred Solution
<!--- A clear and concise description of what you want to happen. What
information may be required and what would be the preferred way to provide it?
What should the output include? --->
## Additional Context
<!--- Add any other context or screenshots about the feature request here. --->
### References
<!---
Information about referencing Github Issues: https://help.github.com/articles/basic-writing-and-formatting-syntax/#referencing-issues-and-pull-requests
Are there any other GitHub issues (open or closed) or pull requests that should be linked here? Vendor blog posts or documentation? For example:
--->
* #0000

4
.github/PULL_REQUEST_TEMPLATE.md vendored Normal file
View file

@ -0,0 +1,4 @@
<!--
Please create an issue to collect feedback prior to feature additions. Please also reference that issue in any PRs.
If possible try to keep PRs scoped to one feature, and add tests for new features.
-->

16
.github/dependabot.yml vendored Normal file
View file

@ -0,0 +1,16 @@
# To get started with Dependabot version updates, you'll need to specify which
# package ecosystems to update and where the package manifests are located.
# Please see the documentation for all configuration options:
# https://help.github.com/github/administering-a-repository/configuration-options-for-dependency-updates
version: 2
updates:
- package-ecosystem: "npm" # See documentation for possible values
directory: "/" # Location of package manifests
schedule:
interval: "weekly"
- package-ecosystem: "github-actions"
directory: "/"
schedule:
# Check for updates to GitHub Actions every weekday
interval: "weekly"

70
.github/workflows/codeql-analysis.yml vendored Normal file
View file

@ -0,0 +1,70 @@
# For most projects, this workflow file will not need changing; you simply need
# to commit it to your repository.
#
# You may wish to alter this file to override the set of languages analyzed,
# or to provide custom queries or build logic.
#
# ******** NOTE ********
# We have attempted to detect the languages in your repository. Please check
# the `language` matrix defined below to confirm you have the correct set of
# supported CodeQL languages.
#
name: "CodeQL"
on:
push:
branches: [ main ]
pull_request:
# The branches below must be a subset of the branches above
branches: [ main ]
schedule:
- cron: '35 11 * * 2'
jobs:
analyze:
name: Analyze
runs-on: ubuntu-latest
permissions:
actions: read
contents: read
security-events: write
strategy:
fail-fast: false
matrix:
language: [ 'javascript' ]
# CodeQL supports [ 'cpp', 'csharp', 'go', 'java', 'javascript', 'python', 'ruby' ]
# Learn more about CodeQL language support at https://git.io/codeql-language-support
steps:
- name: Checkout repository
uses: actions/checkout@v3
# Initializes the CodeQL tools for scanning.
- name: Initialize CodeQL
uses: github/codeql-action/init@v2
with:
languages: ${{ matrix.language }}
# If you wish to specify custom queries, you can do so here or in a config file.
# By default, queries listed here will override any specified in a config file.
# Prefix the list here with "+" to use these queries and those in the config file.
# queries: ./path/to/local/query, your-org/your-repo/queries@main
# Autobuild attempts to build any compiled languages (C/C++, C#, or Java).
# If this step fails, then you should remove it and run the build manually (see below)
- name: Autobuild
uses: github/codeql-action/autobuild@v2
# Command-line programs to run using the OS shell.
# 📚 https://git.io/JvXDl
# ✏️ If the Autobuild fails above, remove it and uncomment the following three lines
# and modify them (or add more) to build your code if your project
# uses a compiled language
#- run: |
# make bootstrap
# make release
- name: Perform CodeQL Analysis
uses: github/codeql-action/analyze@v2

29
.github/workflows/secrets.yml vendored Normal file
View file

@ -0,0 +1,29 @@
name: Scan for secrets
on:
push:
tags:
- v*
branches:
- main
jobs:
test:
runs-on: ubuntu-latest
steps:
- name: Install Go
uses: actions/setup-go@v3
with:
go-version: '1.18'
- name: Checkout code
uses: actions/checkout@v3
with:
fetch-depth: 0
ref: ${{ github.head_ref }}
- name: TruffleHog
uses: ./
with:
path: ./
base: ${{ github.event.repository.default_branch }}
head: HEAD

1
.gitignore vendored
View file

@ -12,3 +12,4 @@ ssldata/*
config.env config.env
payload-fire-images/*.gz payload-fire-images/*.gz
payload-fire-images/*.png payload-fire-images/*.png
deploy.sh

View file

@ -1,10 +1,8 @@
FROM node:12 FROM node:16
# Set up directory for the server
RUN mkdir /app/ RUN mkdir /app/
WORKDIR /app/ WORKDIR /app/
# Copy front-end over
COPY front-end/ /app/front-end/ COPY front-end/ /app/front-end/
WORKDIR /app/front-end/ WORKDIR /app/front-end/
RUN npm install RUN npm install
@ -27,9 +25,7 @@ COPY docker-entrypoint.sh /app/
RUN chmod +x /app/docker-entrypoint.sh RUN chmod +x /app/docker-entrypoint.sh
COPY templates /app/templates COPY templates /app/templates
# Expose both HTTP and HTTPS ports USER 1111
EXPOSE 80
EXPOSE 443
# Start the server # Start the server
ENTRYPOINT ["/app/docker-entrypoint.sh"] ENTRYPOINT ["/app/docker-entrypoint.sh"]

8
api.js
View file

@ -5,7 +5,7 @@ const cors = require('cors');
const path = require('path'); const path = require('path');
const uuid = require('uuid'); const uuid = require('uuid');
const asyncfs = require('fs').promises; const asyncfs = require('fs').promises;
const sessions = require('@nvanexan/node-client-sessions'); const sessions = require('@truffledustin/node-client-sessions');
const favicon = require('serve-favicon'); const favicon = require('serve-favicon');
const database = require('./database.js'); const database = require('./database.js');
const Users = database.Users; const Users = database.Users;
@ -24,7 +24,7 @@ const {OAuth2Client} = require('google-auth-library');
const SCREENSHOTS_DIR = path.resolve(process.env.SCREENSHOTS_DIR); const SCREENSHOTS_DIR = path.resolve(process.env.SCREENSHOTS_DIR);
const client = new OAuth2Client(process.env.CLIENT_ID, process.env.CLIENT_SECRET, `https://${process.env.HOSTNAME}/oauth-login`); const client = new OAuth2Client(process.env.CLIENT_ID, process.env.CLIENT_SECRET, process.env.NODE_ENV == 'production' ? `https://${process.env.HOSTNAME}/oauth-login` : `http://${process.env.HOSTNAME}/oauth-login`);
const SCREENSHOT_FILENAME_REGEX = new RegExp(/^[0-9A-F]{8}-[0-9A-F]{4}-4[0-9A-F]{3}-[89AB][0-9A-F]{3}-[0-9A-F]{12}\.png$/i); const SCREENSHOT_FILENAME_REGEX = new RegExp(/^[0-9A-F]{8}-[0-9A-F]{4}-4[0-9A-F]{3}-[89AB][0-9A-F]{3}-[0-9A-F]{12}\.png$/i);
@ -35,7 +35,7 @@ var sessions_settings_object = {
activeDuration: 1000 * 60 * 5, // Extend for five minutes if actively used activeDuration: 1000 * 60 * 5, // Extend for five minutes if actively used
cookie: { cookie: {
httpOnly: true, httpOnly: true,
secure: true secureProxy: process.env.NODE_ENV == 'production'
} }
} }
@ -153,7 +153,7 @@ async function set_up_api_server(app) {
app.get('/login', (req, res) => { app.get('/login', (req, res) => {
const authUrl = client.generateAuthUrl({ const authUrl = client.generateAuthUrl({
redirect_uri: `https://${process.env.HOSTNAME}/oauth-login`, redirect_uri: process.env.NODE_ENV == 'production' ? `https://${process.env.HOSTNAME}/oauth-login` : `http://${process.env.HOSTNAME}/oauth-login`,
access_type: 'offline', access_type: 'offline',
scope: ['email', 'profile'], scope: ['email', 'profile'],
prompt: 'select_account' prompt: 'select_account'

2
app.js
View file

@ -51,6 +51,8 @@ const SCREENSHOT_FILENAME_REGEX = new RegExp(/^[0-9A-F]{8}-[0-9A-F]{4}-4[0-9A-F]
async function get_app_server() { async function get_app_server() {
const app = express(); const app = express();
app.set('trust proxy', true);
app.disable('x-powered-by');
// I have a question for Express: // I have a question for Express:
// https://youtu.be/ZtjFsQBuJWw?t=4 // https://youtu.be/ZtjFsQBuJWw?t=4

View file

@ -13,7 +13,10 @@ const sequelize = new Sequelize(
host: process.env.DATABASE_HOST, host: process.env.DATABASE_HOST,
dialect: 'postgres', dialect: 'postgres',
benchmark: true, benchmark: true,
logging: true logging: false,
dialectOptions: {
socketPath: process.env.NODE_ENV == 'production' ? process.env.DATABASE_HOST : null,
},
}, },
); );
@ -357,36 +360,6 @@ InjectionRequests.init({
] ]
}); });
function get_banner() {
return `
============================================================================
vvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvv
Hi. I love you.
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
============================================================================
`;
}
async function print_banner() {
console.log(get_banner());
}
async function database_init() { async function database_init() {
const force = false; const force = false;
@ -398,11 +371,6 @@ async function database_init() {
CollectedPages.sync({ force: force }), CollectedPages.sync({ force: force }),
InjectionRequests.sync({ force: force }), InjectionRequests.sync({ force: force }),
]); ]);
await Promise.all([
// Set up admin panel user if not already set up.
print_banner(),
]);
} }
module.exports = { module.exports = {

View file

@ -3,86 +3,28 @@ services:
# XSS Hunter Express service # XSS Hunter Express service
xsshunterexpress: xsshunterexpress:
build: . build: .
environment: env_file:
# [REQUIRED] The hostname/domain pointed to - dev.env
# the IP of the server running this service.
# SSL will automatically be set up and
# renewed with LetsEncrypt.
- HOSTNAME=your.host.name
# THis hostname is where your JS is served out of
- XSS_HOSTNAME=your.xss.domain
# [REQUIRED] Email for SSL
- SSL_CONTACT_EMAIL=YourEmail@gmail.com
# Maximum XSS callback payload size
# This includes the webpage screenshot, DOM HTML,
# page text, and other metadata. Note that if the
# payload is above this limit, you won't be notified
# of the XSS firing.
- MAX_PAYLOAD_UPLOAD_SIZE_MB=50
# Whether or not to enable the web control panel
# Set to "false" or remove to disable the web UI.
# Useful for minimizing attack surface.
- CONTROL_PANEL_ENABLED=true
# Whether or not to enable email notifications via
# SMTP for XSS payload fires.
- SMTP_EMAIL_NOTIFICATIONS_ENABLED=true
- SMTP_HOST=smtp.gmail.com
- SMTP_PORT=465
- SMTP_USE_TLS=true
- SMTP_USERNAME=YourEmail@gmail.com
- SMTP_PASSWORD=YourEmailPassword
- SMTP_FROM_EMAIL=YourEmail@gmail.com
- SMTP_RECEIVER_EMAIL=YourEmail@gmail.com
# CLIENT ID FOR OAUTH LOGIN
- CLIENT_ID=your_client_id
- CLIENT_SECRET=your_client_secret
# GENERATE A RANDOM LONG STRING FOR THIS
- SESSION_SECRET_KEY=
# THERE IS NO NEED TO MODIFY BELOW THIS LINE
# ------------------------------------------
# FEEL FREE, BUT KNOW WHAT YOU'RE DOING.
# Where XSS screenshots are stored
- SCREENSHOTS_DIR=/app/payload-fire-images
- DATABASE_NAME=xsshunterexpress
- DATABASE_USER=xsshunterexpress
- DATABASE_PASSWORD=xsshunterexpress
- DATABASE_HOST=postgresdb
- NODE_ENV=production
- USE_CLOUD_STORAGE=true
- BUCKET_NAME=YourBucket
ports: ports:
- "80:80" - "127.0.0.1:8080:8080"
- "443:443"
volumes: volumes:
# Stores the SSL/TLS certificates and keys
# in the "ssldata" directory.
# Your certificates are automatically renewed
# via LetsEncrypt, no extra work needed!
- ./ssldata:/app/greenlock.d
# Directory where payload fire images are stored. # Directory where payload fire images are stored.
- ./payload-fire-images:/app/payload-fire-images - ./payload-fire-images:/app/payload-fire-images
# Comment out if you're using an external SQL
# server and have commented out the DB section.
depends_on: depends_on:
- postgresdb postgresdb:
# Postgres server to store injection data (not including condition: service_healthy
# screenshots which are stored separately).
# NOTE: If you're using an external SQL server, you can comment
# out this service.
# WARNING: This database gives the "postgres" user admin priveleges
# with a default password of "xsshunterexpress". Do not expose it
# externally. If you do, be sure to change the password.
postgresdb: postgresdb:
image: postgres image: postgres
restart: always restart: always
user: postgres
environment: environment:
# This is a volume mounted into the container
# (see the directory ./postgres-db-data)
# So the database will be persisted across
# container deletion.
PGDATA: /var/lib/postgresql/data/pgdata PGDATA: /var/lib/postgresql/data/pgdata
POSTGRES_USER: xsshunterexpress POSTGRES_PASSWORD: postgres
POSTGRES_DB: xsshunterexpress POSTGRES_HOST_AUTH_METHOD: trust
POSTGRES_PASSWORD: xsshunterexpress healthcheck:
test: ["CMD-SHELL", "pg_isready"]
interval: 3s
timeout: 5s
retries: 5
volumes: volumes:
- ./postgres-db-data:/var/lib/postgresql/data/pgdata - ./postgres-db-data:/var/lib/postgresql/data/pgdata

View file

@ -1,9 +1,4 @@
#!/usr/bin/env bash #!/usr/bin/env bash
echo "Initializing SSL/TLS..."
# Set up Greenlock
# Test if --maintainer-email is required, we can set it via environment variables...
npx greenlock init --config-dir /app/greenlock.d --maintainer-email $SSL_CONTACT_EMAIL
npx greenlock add --subject $HOSTNAME --altnames "$HOSTNAME,$XSS_HOSTNAME"
echo "Starting server..." echo "Starting server..."
node server.js node server.js

2481
package-lock.json generated

File diff suppressed because it is too large Load diff

View file

@ -11,17 +11,19 @@
"license": "MIT", "license": "MIT",
"dependencies": { "dependencies": {
"@deveodk/vue-toastr": "^1.1.0", "@deveodk/vue-toastr": "^1.1.0",
"@nvanexan/node-client-sessions": "^0.8.0", "@truffledustin/node-client-sessions": "^0.8.0",
"bcrypt": "^5.0.1", "bcrypt": "^5.0.1",
"body-parser": "^1.20.1",
"cors": "^2.8.5", "cors": "^2.8.5",
"@google-cloud/storage": "^6.9.0", "@google-cloud/storage": "^6.9.0",
"express": "^4.17.1", "express": "^4.17.1",
"express-jsonschema": "^1.1.6", "express-jsonschema": "^1.1.6",
"greenlock-express": "^4.0.3", "google-auth-library": "^8.7.0",
"googleapis": "^110.0.0",
"keygrip": "^1.1.0", "keygrip": "^1.1.0",
"memorystore": "^1.6.6", "memorystore": "^1.6.6",
"moment": "^2.29.1", "moment": "^2.29.1",
"multer": "^1.4.2", "multer": "^1.4.5-lts.1",
"mustache": "^4.1.0", "mustache": "^4.1.0",
"nodemailer": "^6.5.0", "nodemailer": "^6.5.0",
"pg": "^8.5.1", "pg": "^8.5.1",
@ -29,9 +31,6 @@
"sequelize": "^6.5.0", "sequelize": "^6.5.0",
"serve-favicon": "^2.5.0", "serve-favicon": "^2.5.0",
"uuid": "^8.3.2", "uuid": "^8.3.2",
"vue-moment": "^4.1.0", "vue-moment": "^4.1.0"
"body-parser": "^1.20.1",
"google-auth-library": "^8.7.0",
"googleapis": "^110.0.0"
} }
} }

View file

@ -16,10 +16,9 @@ if(!process.env.SSL_CONTACT_EMAIL) {
const app = await get_app_server(); const app = await get_app_server();
require('greenlock-express').init({ const port = process.env.PORT;
packageRoot: __dirname,
configDir: './greenlock.d', app.listen(port, () => {
cluster: false, console.log(`XSS Hunter listening on port ${port}`)
maintainerEmail: process.env.SSL_CONTACT_EMAIL, });
}).serve(app);
})(); })();