diff --git a/DOCS/coding-style-guide/form-layouts-and-design.mdx b/DOCS/coding-style-guide/form-layouts-and-design.mdx
index fa52aaa91..c4e26cd1e 100644
--- a/DOCS/coding-style-guide/form-layouts-and-design.mdx
+++ b/DOCS/coding-style-guide/form-layouts-and-design.mdx
@@ -16,13 +16,13 @@ If created correctly, the form can be added to a template with two lines:
```json
- {% load crispy_forms_tags %}
- {% crispy form form.helper %}
+{% load crispy_forms_tags %}
+{% crispy form form.helper %}
```
Read about Crispy's `FormHelper()` and `Layout()` objects:
-
+
## Creating a Form
diff --git a/DOCS/coding-style-guide/style-guide.mdx b/DOCS/coding-style-guide/style-guide.mdx
index 6a912632a..f84e77f3a 100644
--- a/DOCS/coding-style-guide/style-guide.mdx
+++ b/DOCS/coding-style-guide/style-guide.mdx
@@ -29,13 +29,12 @@ Black is "opinionated" and automatically changes things to keep code consistent
```json
-
- "editor.formatOnSave": true,
- "python.formatting.provider": "black",
- "python.formatting.blackArgs": [
- "--line-length",
- "90"
- ],
+"editor.formatOnSave": true,
+"python.formatting.provider": "black",
+"python.formatting.blackArgs": [
+ "--line-length",
+ "90"
+],
```
VSCode will now use Black to format all Python files on save actions.
@@ -44,8 +43,7 @@ VSCode will now use Black to format all Python files on save actions.
Black will not automatically delete trailing whitespace or whitespace on otherwise empty lines. Trailing whitespace will be identified by the linter (below). Add this line to VSCode's _settings.json_ file to automatically delete trailing whitespace on save:
```json
-
- "files.trimTrailingWhitespace": true
+"files.trimTrailingWhitespace": true
```
## Managing Imports
@@ -56,18 +54,18 @@ The Ghostwriter project also uses `Isort` which is part of the Python extensions
This tool sorts imports by library types (FUTURE, STDLIB, THIRDPARTY, FIRSTPARTY, LOCALFOLDER) and then alphabetically. It is customizable to generate comments and sort by line length. Ghostwriter code repository includes an _.isort.cfg_ file. Ghostwriter's current configuration contains:
```json
-
- [settings]
- profile=ghostwriter
- src_paths=isort,test
- atomic=True
- line_length=90
- use_parentheses=True
- ensure_newline_before_comments=True
- import_heading_stdlib=Standard Libraries
- import_heading_firstparty=Ghostwriter Libraries
- import_heading_thirdparty=Django & Other 3rd Party Libraries
+[settings]
+profile=ghostwriter
+src_paths=isort,test
+atomic=True
+line_length=90
+use_parentheses=True
+ensure_newline_before_comments=True
+import_heading_stdlib=Standard Libraries
+import_heading_firstparty=Ghostwriter Libraries
+import_heading_thirdparty=Django & Other 3rd Party Libraries
```
+
This configuration enforces the use of parentheses, adds newlines between sections, and keeps the line length /\<= 90 characters. It also adds custom comments before standard libraries, third-party libraries, and Ghostwriter's local first-party libraries.
Here is an example:
@@ -101,6 +99,7 @@ Here is an example:
ProjectObjective
)
```
+
Once the Python extension is installed, run `isort` by pressing SHIFT+CMD+P and selecting `Python Refactor: Sort Imports`.
## Line Length
@@ -150,6 +149,7 @@ A good view docstring looks like this:
:template:`rolodex/client_detail.html`
"""
```
+
Note the newline after the opening `"""` which deviates from standard practice (per PEP-8). Further, the use of grave accents, asterisks ( * ), and colons ( : ). are all purposeful and important. Django and `docutils` convert these symbols into formatting for the auto-generated documentation in the admin panel.
The above example is rendered like this:
@@ -168,22 +168,22 @@ Finally, docstrings should have newlines between sections and section headers. T
Setup VSCode snippets to create templates for repeated code snippets, like docstrings.
```json
-
- "UpdateView Docstring": {
- "prefix": "update",
- "body": [
- "\"\"\"",
- "Update an individual :model:`${1:model}`.",
- "",
- "**Template**",
- "",
- ":template:`${2:template}`",
- "\"\"\"",
- ],
- "description": "A docstring template for an UpdateView"
- },
+"UpdateView Docstring": {
+ "prefix": "update",
+ "body": [
+ "\"\"\"",
+ "Update an individual :model:`${1:model}`.",
+ "",
+ "**Template**",
+ "",
+ ":template:`${2:template}`",
+ "\"\"\"",
+ ],
+ "description": "A docstring template for an UpdateView"
+},
```
+
## Linting
@@ -219,25 +219,24 @@ Once the file is in place, run `pre-commit install` to hook future git commits.
```json
- exclude: 'docs|node_modules|migrations|.git|.tox'
- default_stages: [commit]
- fail_fast: true
- repos:
- - repo: https://github.com/pre-commit/pre-commit-hooks
- rev: master
- hooks:
- - id: trailing-whitespace
- - id: end-of-file-fixer
- - id: check-yaml
- - repo: https://github.com/psf/black
- rev: 19.10b0
- hooks:
- - id: black
- - repo: https://gitlab.com/pycqa/flake8
- rev: 3.8.3
- hooks:
- - id: flake8
- args: ['--config=setup.cfg']
- additional_dependencies: [flake8-isort]
-
+exclude: 'docs|node_modules|migrations|.git|.tox'
+default_stages: [commit]
+fail_fast: true
+repos:
+ - repo: https://github.com/pre-commit/pre-commit-hooks
+ rev: master
+ hooks:
+ - id: trailing-whitespace
+ - id: end-of-file-fixer
+ - id: check-yaml
+ - repo: https://github.com/psf/black
+ rev: 19.10b0
+ hooks:
+ - id: black
+ - repo: https://gitlab.com/pycqa/flake8
+ rev: 3.8.3
+ hooks:
+ - id: flake8
+ args: ['--config=setup.cfg']
+ additional_dependencies: [flake8-isort]
```
diff --git a/DOCS/configuring-global-settings/configuring-apis/configuring-namecheap.mdx b/DOCS/configuring-global-settings/configuring-apis/configuring-namecheap.mdx
index 9a0443924..71536580d 100644
--- a/DOCS/configuring-global-settings/configuring-apis/configuring-namecheap.mdx
+++ b/DOCS/configuring-global-settings/configuring-apis/configuring-namecheap.mdx
@@ -11,7 +11,6 @@ Fill-in the configuration values in accordance with your API configuration. All
Namecheap.com
-
diff --git a/DOCS/configuring-global-settings/configuring-apis/configuring-virustotal.mdx b/DOCS/configuring-global-settings/configuring-apis/configuring-virustotal.mdx
index c21cdf5cf..5045a9fc0 100644
--- a/DOCS/configuring-global-settings/configuring-apis/configuring-virustotal.mdx
+++ b/DOCS/configuring-global-settings/configuring-apis/configuring-virustotal.mdx
@@ -7,7 +7,7 @@ Ghostwriter can use VirusTotal's API to look up domain names in your Domain Libr
The blocklist is maintained inside of the *review\.py* module:
-```bash
+```python Domain Blocklist
class DomainReview(object
« snip »
diff --git a/DOCS/development/contributing-to-the-project/pre-release-checklist.mdx b/DOCS/development/contributing-to-the-project/pre-release-checklist.mdx
index 0b580f0e5..34fb7f718 100644
--- a/DOCS/development/contributing-to-the-project/pre-release-checklist.mdx
+++ b/DOCS/development/contributing-to-the-project/pre-release-checklist.mdx
@@ -60,5 +60,3 @@ The following sections walk you through what to do to prepare for a new release
5. Wait some time (usually \~25 minutes) and review the results of the GitHub Actions
6. If required Actions succeeded, the code may be merged and Ghostwriter team members will review the code prior to a release
-
-[PreviousContributing to the Project](/development/contributing-to-the-project)[NextDatabase Models](/development/database-models)
diff --git a/DOCS/development/expected-services-and-processes.mdx b/DOCS/development/expected-services-and-processes.mdx
index 1cfbba9cc..b03ae6c33 100644
--- a/DOCS/development/expected-services-and-processes.mdx
+++ b/DOCS/development/expected-services-and-processes.mdx
@@ -10,7 +10,7 @@ If you would like to monitor or check the various processes and services running
Manually list processes with `docker-compose` and these commands:
-```
+```log
docker-compose -f local.yml top django
docker-compose -f local.yml top postgres
docker-compose -f local.yml top queue
diff --git a/DOCS/development/modifying-code.mdx b/DOCS/development/modifying-code.mdx
index 303cb6cad..a886abb77 100644
--- a/DOCS/development/modifying-code.mdx
+++ b/DOCS/development/modifying-code.mdx
@@ -30,7 +30,7 @@ Most errors will be displayed in your web browser thanks to the verbose error ou
Of course, there will be no visible output in your browser if an error prevents Django from starting the server. To view logging output from Redis, PostgreSQL, and Django, use the Docker `logs` command:
-```
+```log
docker-compose -f local.yml logs
docker-compose -f local.yml logs django
docker-compose -f local.yml logs queue
@@ -41,6 +41,7 @@ docker-compose -f local.yml logs postgres
Logs are handy for performing dry runs of scheduled tasks. Anything you \`print\` will be output to the logs.
+
Add the name of the container after \`logs\` to get logs just from that service.
### Cleaning Up Containers
@@ -51,7 +52,7 @@ If you break something or want to start from scratch, stop all of your container
The following assumes only Ghostwriter container and volumes are present on your system. Proceed with caution if you use Docker for other things on your development system.
-```
+```log
docker system prune -a
docker volume rm -f $(docker volume ls)
```
diff --git a/DOCS/development/modifying-code/modifying-environment-variables.mdx b/DOCS/development/modifying-code/modifying-environment-variables.mdx
index a04ba2488..9396c1dd5 100644
--- a/DOCS/development/modifying-code/modifying-environment-variables.mdx
+++ b/DOCS/development/modifying-code/modifying-environment-variables.mdx
@@ -11,7 +11,7 @@ Some of the variables influence the Docker builds. The majority of the variables
For example, the `DJANGO_SUPERUSER_PASSWORD` variable has the `DJANGO_` prefix to signify it is tied to the Django service and container. It is declared in the YAML files like this:
-```
+```yaml
- DJANGO_SUPERUSER_PASSWORD=${DJANGO_SUPERUSER_PASSWORD}
```
@@ -35,14 +35,16 @@ You may need to do one additional thing if adding a new variable to the Django c
Add your new variable in the same manner as the other variables already in these files. Looking at `DJANGO_DATE_FORMAT` again, add the variable like this with `env()`:
-```
+```python
DATE_FORMAT = env(
"DJANGO_DATE_FORMAT",
default="d M Y"
)
```
+
It's a good idea to provide a default value if your custom variable is missing from your DotEnv file.
+
Finally, you can also modify Ghostwriter CLI to include your new variable. After building a new binary, you can set the value via Ghostwriter CLI's commands.
diff --git a/DOCS/development/stack-overview.mdx b/DOCS/development/stack-overview.mdx
index d1bae7c4d..124de2a14 100644
--- a/DOCS/development/stack-overview.mdx
+++ b/DOCS/development/stack-overview.mdx
@@ -34,5 +34,3 @@ Trying to move code updates to a production server can be messy when migrations
### Background Tasking — AQMP
Finally, Django Q and Redis handle automated queue management processing (AQMP). Ghostwriter automates a number of things like updating domain categorization data and DNS records. These tasks are handed off to Redis for background processing.
-
-[PreviousCustom Layout Objects](/coding-style-guide/form-layouts-and-design/custom-layout-objects)[NextBehind the Scenes](/development/stack-overview/behind-the-scenes)
diff --git a/DOCS/development/testing-code.mdx b/DOCS/development/testing-code.mdx
index a50382c93..837ed8b64 100644
--- a/DOCS/development/testing-code.mdx
+++ b/DOCS/development/testing-code.mdx
@@ -28,14 +28,14 @@ Tests are run through Django's _manage.py_ and the `test` command. You can run a
```
A successful run of all unit tests may still display errors. Many of the unit tests intentionally trigger errors by passing invalid data to the server. The logger output can be disabled but this is generally unnecessary. A successful run will output something like this at the end:
-```json
-
- ----------------------------------------------------------------------
- Ran 488 tests in 45.331s
+```log
+----------------------------------------------------------------------
+Ran 488 tests in 45.331s
- OK
- Destroying test database for alias 'default'...
+OK
+Destroying test database for alias 'default'...
```
+
A test run with failures or errors will report the number of each at the end. Review the test output to see which test(s) failed to determine what needs to be fixed.
### Test Coverage
diff --git a/DOCS/features/access-authentication-and-session-controls/single-sign-on.mdx b/DOCS/features/access-authentication-and-session-controls/single-sign-on.mdx
index 729d4d458..32c034955 100644
--- a/DOCS/features/access-authentication-and-session-controls/single-sign-on.mdx
+++ b/DOCS/features/access-authentication-and-session-controls/single-sign-on.mdx
@@ -23,19 +23,19 @@ For example, you might make _1-sso-provider.py_ to hold your SSO configuration a
Your new config file must contain these settings at a minimum. We'll use Microsoft as an example for these steps.
-```json
- # Provider(s) configuration
- SOCIALACCOUNT_PROVIDERS = {
- "microsoft": {
- "APP": {
- "client_id": "CLIENT ID",
- "secret": "SECRET",
- }
- },
- }
- # Extend the installed apps with the SSO app for your provider(s)
- SSO_PROVIDERS = ["allauth.socialaccount.providers.microsoft"]
- INSTALLED_APPS = INSTALLED_APPS + SSO_PROVIDERS
+```python SSO Provider Config
+# Provider(s) configuration
+SOCIALACCOUNT_PROVIDERS = {
+ "microsoft": {
+ "APP": {
+ "client_id": "CLIENT ID",
+ "secret": "SECRET",
+ }
+ },
+}
+# Extend the installed apps with the SSO app for your provider(s)
+SSO_PROVIDERS = ["allauth.socialaccount.providers.microsoft"]
+INSTALLED_APPS = INSTALLED_APPS + SSO_PROVIDERS
```
The above lines add our provider (Microsoft for this example) to Ghostwriter's installed apps and provide the information necessary for the SSO handshake. You can find the values you need for your provider(s) at the above link.
@@ -63,12 +63,13 @@ Set `DJANGO_SOCIAL_ACCOUNT_DOMAIN_ALLOWLIST` with Ghostwriter CLI or `SOCIAL_ACC
Here is what this might look like in your config file:
-```json
- # Enable or disable registration
- SOCIAL_ACCOUNT_ALLOW_REGISTRATION = True
- # Allow only these email domains
- SOCIAL_ACCOUNT_DOMAIN_ALLOWLIST = ["specterops.io"]
+```python SSO Domain Allowlist
+# Enable or disable registration
+SOCIAL_ACCOUNT_ALLOW_REGISTRATION = True
+# Allow only these email domains
+SOCIAL_ACCOUNT_DOMAIN_ALLOWLIST = ["specterops.io"]
```
+
These settings allow registration via an SSO provider, but only if the account's email address has the _specterops.io_ domain.
If a local account with a matching email address already exists, the user will be prompted to enter a different address for their new account. This will most likely arise when transitioning from local accounts to a new SSO provider. You will probably want to link the accounts in these cases.
@@ -76,21 +77,22 @@ If a local account with a matching email address already exists, the user will b
An error is raised if multiple existing accounts share the same email address. Rather than trying to connect one of them, the user will see a message encouraging them to contact an administrator.
-You can link accounts by enabling your provider to authenticate via the account's email address. By default, email authentication is disabled, and the provider must have pre-verified the email address. Use the following settings if you trust the provider and want to consider email addresses as verified.
+You can link accounts by enabling your provider to authenticate via the account's email address. By default, email authentication is disabled, and the provider must have pre-verified the email address. Use the following settings if you trust the provider and want to consider email addresses as verified.
-```json
- SOCIALACCOUNT_PROVIDERS = {
- "microsoft": {
- "APP": {
- "client_id": "",
- "secret": "",
- },
- "EMAIL_AUTHENTICATION": True,
- "VERIFIED_EMAIL": True,
+```python SSO Email Authentication
+SOCIALACCOUNT_PROVIDERS = {
+ "microsoft": {
+ "APP": {
+ "client_id": "",
+ "secret": "",
},
- }
+ "EMAIL_AUTHENTICATION": True,
+ "VERIFIED_EMAIL": True,
+ },
+}
```
+
These settings enable Microsoft email authentication and consider all email addresses verified for automatic connection.
If someone were to authenticate with a Microsoft account, they would only be allowed to create or link an account if registration is enabled and the domain allowlist checks passed. If either check fails, the user will be redirected to a page like this.
@@ -105,4 +107,4 @@ Depending on your SSO provider, you may need to consider other configuration opt
If you wish to have users log in immediately when they click the provider button, set `DJANGO_SOCIAL_ACCOUNT_LOGIN_ON_GET` to `true` with Ghostwriter CLI. For information is available here:
-[Configuration - django-allauth](https://docs.allauth.org/en/latest/socialaccount/configuration.html)
+ docs.allauth.org
diff --git a/DOCS/features/graphql-api/authentication.mdx b/DOCS/features/graphql-api/authentication.mdx
index 85d49be10..2b179bba6 100644
--- a/DOCS/features/graphql-api/authentication.mdx
+++ b/DOCS/features/graphql-api/authentication.mdx
@@ -24,6 +24,7 @@ The JWT secret key is defined in the environment variables, `GRAPHQL_JWT_SECRET_
"typ": "JWT"
}
```
+
@@ -52,7 +53,7 @@ The tokens follow the JWT open standard ([RFC7519](https://datatracker.ietf.org/
User JWTs are generated with a `Login` action. The resulting JWT holds the same privileges as the authenticated user. The user JWTs are valid for 15 minutes.
-```
+```json
mutation Login {
login(password: "password", username: "username") {
token
@@ -60,9 +61,11 @@ mutation Login {
}
}
```
+
The `Login` action is disabled for accounts with 2FA configured. An account with 2FA should use a generated API token (see below).
+
### API Tokens
You can also generate tokens by visiting their profile page and scrolling down to the "API Tokens" section. In this section, you can create new tokens, see all existing tokens, and revoke tokens you no longer need.
@@ -91,7 +94,7 @@ If the token passes the above checks and your user's role is authorized (see [Au
If the token is not accepted, the authorization webhook will return a `401 Unauthorized` response with an error like this:
-```
+```json
{
"errors": [
{
diff --git a/DOCS/features/graphql-api/common-api-actions.mdx b/DOCS/features/graphql-api/common-api-actions.mdx
index c35bc7c92..35763023e 100644
--- a/DOCS/features/graphql-api/common-api-actions.mdx
+++ b/DOCS/features/graphql-api/common-api-actions.mdx
@@ -64,6 +64,7 @@ Both of these queries return the same result:
}
}
```
+
### Special Queries and Mutations
Some queries and mutations have to break away from the above rules. These are special actions that trigger additional business logic before or after the action is completed.
@@ -92,6 +93,7 @@ You can use the `generateReport` mutation to get report data for a given report
}
}
```
+
For more explicit examples and ideas, see this section:
diff --git a/DOCS/features/graphql-api/graphql-api.mdx b/DOCS/features/graphql-api/graphql-api.mdx
index 0ac2ad573..777cf2562 100644
--- a/DOCS/features/graphql-api/graphql-api.mdx
+++ b/DOCS/features/graphql-api/graphql-api.mdx
@@ -26,7 +26,7 @@ Unlike a REST API, a GraphQL API does not have specific endpoints you must query
A standard query is submitted with `Content-Type: application/json` in the headers and a body like this:
-```
+```json SampleQuery.json
{
"query": "...",
"operationName": "...",
@@ -38,7 +38,7 @@ The `query` and `operationName` keys are required. The `operationName` tells Gra
The response will always come back in this form:
-```
+```json SampleResponse.json
{
"data": { ... },
"errors": [ ... ]
@@ -56,7 +56,7 @@ Some basic GraphQL knowledge, such as the difference between a query and a mutat
A basic query looks like this:
-```
+```json SampleClientQuery.json
query MyQuery {
client {
id
@@ -68,7 +68,7 @@ It identifies itself as a query with an arbitrary name, states which table it wa
The query can be modified to return additional data, like the `codename` and `note` fields:
-```
+```json SampleClientQuery.json
query MyQuery {
client {
id
@@ -82,7 +82,7 @@ Field names are often placed on separate lines in GraphQL examples and the Hasur
Queries can also request related data. For a client, you might request the contact information for all related points of contact:
-```
+```json SampleClientQuery.json
query MyQuery {
clients {
id
@@ -97,7 +97,7 @@ query MyQuery {
You can include multiple queries in a single request. Here we add a query to fetch the `id` and `title` of every finding in the database to get all our data back in a single request:
-```
+```json SampleClientQuery.json
query MyQuery {
clients {
id
@@ -120,7 +120,7 @@ In most cases, you can accomplish your goal with a single query. Always remember
For this final example, assume you want to get the title and severity of every finding ever associated with a particular client's projects where the `title` contains `SMB`. This can be accomplished with nested database relationships and the addition of a condition:
-```
+```json SampleClientQueryWithFilter.json
query MyQuery {
clients {
projects {
@@ -153,7 +153,7 @@ Here is an example query request in Python using the `gql` library. For more exa
-```
+```python SampleAPI.py
from gql import Client, gql
from gql.transport.aiohttp import AIOHTTPTransport
from gql.transport.exceptions import TransportQueryError
@@ -209,5 +209,3 @@ except GraphQLError as e:
# Do something...
pass
```
-
-[PreviousPrebuilt Tasks](/features/background-tasks/prebuilt-tasks)[NextAuthentication](/features/graphql-api/authentication)
diff --git a/DOCS/features/graphql-api/graphql-usage-examples.mdx b/DOCS/features/graphql-api/graphql-usage-examples.mdx
index 26cc09af4..322f6b762 100644
--- a/DOCS/features/graphql-api/graphql-usage-examples.mdx
+++ b/DOCS/features/graphql-api/graphql-usage-examples.mdx
@@ -92,5 +92,3 @@ You need three libraries to run the script:
aiohttp==3.10.5
```
-
-[PreviousUsing the Hasura Console](/features/graphql-api/using-the-hasura-console)[NextRecording Cloud Server Deployments](/features/graphql-api/graphql-usage-examples/recording-cloud-server-deployments)
diff --git a/DOCS/features/graphql-api/graphql-usage-examples/recording-cloud-server-deployments.mdx b/DOCS/features/graphql-api/graphql-usage-examples/recording-cloud-server-deployments.mdx
index b25fa5b8e..8c8f114e9 100644
--- a/DOCS/features/graphql-api/graphql-usage-examples/recording-cloud-server-deployments.mdx
+++ b/DOCS/features/graphql-api/graphql-usage-examples/recording-cloud-server-deployments.mdx
@@ -79,5 +79,3 @@ ghostwriter_response: dict[str, Any] = record_server(
provider_id=PROVIDER_ID_MAP.get("AWS", 1),
)
```
-
-[PreviousGraphQL Usage Examples](/features/graphql-api/graphql-usage-examples)[NextIntegrating with BloodHound for Reporting](/features/graphql-api/graphql-usage-examples/integrating-with-bloodhound-for-reporting)
diff --git a/DOCS/features/health-monitoring.mdx b/DOCS/features/health-monitoring.mdx
index 4ca276738..ccc937728 100644
--- a/DOCS/features/health-monitoring.mdx
+++ b/DOCS/features/health-monitoring.mdx
@@ -15,7 +15,7 @@ Docker automatically monitors the containers via `HEALTHCHECK` commands (see [Do
The results of these commands can be checked with this command:
-```
+```log
./ghostwriter-cli running
```
@@ -54,6 +54,7 @@ These tests are more thorough than the Docker health checks. For example, Docker
This endpoint can also return a JSON version of the test results if you set the `Accept: application/json` header.
+
Running these tests constantly could be a strain on the server, so the tests run on-demand when you visit this page.
You can visit the simplified endpoint, */status/simple/*, to run lightweight checks. This endpoint checks the web server, database status, and cache status and returns one of the following responses:
@@ -79,7 +80,7 @@ You can automate monitoring with something like Uptime Kuma or a similar tool. T
If the tool is capable of triggering a secondary action, you could have the tool pull the JSON data from */status/*:
-```
+```log
$ curl -k https://ghostwriter.local/status/ -H "Accept: application/json"
{"Cache backend: default": "working", "DatabaseBackend": "working", "DefaultFileStorageHealthCheck": "working", "DiskUsage": "working", "MemoryUsage": "working", "MigrationsHealthCheck": "working", "RedisHealthCheck": "working"}
```
diff --git a/DOCS/features/reporting/jinja2-tips-and-tricks.mdx b/DOCS/features/reporting/jinja2-tips-and-tricks.mdx
index f9bdab898..0efe628f1 100644
--- a/DOCS/features/reporting/jinja2-tips-and-tricks.mdx
+++ b/DOCS/features/reporting/jinja2-tips-and-tricks.mdx
@@ -44,5 +44,3 @@ You can customize this example to change the ID string or start ID values at zer
{{ finding_id }}
{% endfor %}
```
-
-[PreviousTemplating and Rich Text Fields](/features/reporting/templating-and-rich-text-fields)[NextBackground Tasks](/features/background-tasks)
diff --git a/DOCS/features/reporting/report-types.mdx b/DOCS/features/reporting/report-types.mdx
index c9fa61754..b96136d10 100644
--- a/DOCS/features/reporting/report-types.mdx
+++ b/DOCS/features/reporting/report-types.mdx
@@ -34,117 +34,116 @@ The JSON output is the foundation of every other report type. It is surfaced as
Example Report JSON
-```json
-
- {
- "client": {
+```json ExampleJSONReport.json
+{
+ "client": {
+ "id": 1,
+ "full_name": "Kabletown",
+ "short_name": "KT",
+ "codename": "SCHEMING RANGER",
+ "poc": {
+ "1": {
"id": 1,
- "full_name": "Kabletown",
- "short_name": "KT",
- "codename": "SCHEMING RANGER",
- "poc": {
- "1": {
- "id": 1,
- "name": "John Francis Donaghy",
- "job_title": "Vice President of East Coast Television and Microwave Oven Programming",
- "email": "jack@nbc.com",
- "phone": "555-123-4556",
- "note": "Goes by \"Jack.\""
- },
- }
+ "name": "John Francis Donaghy",
+ "job_title": "Vice President of East Coast Television and Microwave Oven Programming",
+ "email": "jack@nbc.com",
+ "phone": "555-123-4556",
+ "note": "Goes by \"Jack.\""
},
- "project": {
+ }
+ },
+ "project": {
+ "id": 1,
+ "name": "Kabletown Penetration Test (GREATER THUNDER)",
+ "start_date": "2019-07-29",
+ "end_date": "2019-08-09",
+ "codename": "GREATER THUNDER",
+ "project_type": "Penetration Test",
+ "note": ""
+ },
+ "findings": {
+ "SMBv1 Remote Code Execution (CVE-2017-0143)": {
+ "id": 1,
+ "title": "SMBv1 Remote Code Execution (CVE-2017-0143)",
+ "severity": "High",
+ "affected_entities": "...",
+ "description": "...",
+ "impact": "...",
+ "recommendation": "...",
+ "replication_steps": "...",
+ "host_detection_techniques": "...",
+ "network_detection_techniques": "...",
+ "references": "...",
+ "evidence": {
+ "Enigma": {
+ "id": 5,
+ "friendly_name": "Enigma",
+ "uploaded_by": "admin",
+ "upload_date": "2019-08-04",
+ "description": "Captured while he was discovering a new 0-day, probably.",
+ "caption": "Matt Nelson, OSCP in the zone",
+ "url": "/media/evidence/1/matt_nelson.png",
+ "file_path": "evidence/1/matt_nelson.png"
+ }
+ }
+ },
+ },
+ "infrastructure": {
+ "domains": {
+ "1": {
"id": 1,
- "name": "Kabletown Penetration Test (GREATER THUNDER)",
- "start_date": "2019-07-29",
+ "name": "getghostwriter.io",
+ "activity": "Command and Control",
+ "operator": "admin",
+ "start_date": "2019-07-15",
"end_date": "2019-08-09",
- "codename": "GREATER THUNDER",
- "project_type": "Penetration Test",
- "note": ""
- },
- "findings": {
- "SMBv1 Remote Code Execution (CVE-2017-0143)": {
+ "note": "Used with Covenant C2."
+ }
+ },
+ "servers": {
+ "static": {
+ "1": {
"id": 1,
- "title": "SMBv1 Remote Code Execution (CVE-2017-0143)",
- "severity": "High",
- "affected_entities": "...",
- "description": "...",
- "impact": "...",
- "recommendation": "...",
- "replication_steps": "...",
- "host_detection_techniques": "...",
- "network_detection_techniques": "...",
- "references": "...",
- "evidence": {
- "Enigma": {
- "id": 5,
- "friendly_name": "Enigma",
- "uploaded_by": "admin",
- "upload_date": "2019-08-04",
- "description": "Captured while he was discovering a new 0-day, probably.",
- "caption": "Matt Nelson, OSCP in the zone",
- "url": "/media/evidence/1/matt_nelson.png",
- "file_path": "evidence/1/matt_nelson.png"
- }
- }
- },
- },
- "infrastructure": {
- "domains": {
- "1": {
- "id": 1,
- "name": "getghostwriter.io",
- "activity": "Command and Control",
- "operator": "admin",
- "start_date": "2019-07-15",
- "end_date": "2019-08-09",
- "note": "Used with Covenant C2."
- }
- },
- "servers": {
- "static": {
- "1": {
- "id": 1,
- "ip_address": "159.89.234.80",
- "activity": "Command and Control",
- "role": "Team Server / C2 Server",
- "operator": "benny",
- "start_date": "2019-07-29",
- "end_date": "2019-08-09",
- "note": "Used for Covenant C2."
- }
- },
- "cloud": {
- "1": {
- "id": 1,
- "ip_address": "255.255.255.123",
- "activity": "Phishing",
- "role": "SMTP",
- "operator": "benny",
- "note": ""
- },
- },
- },
- "domains_and_servers": {
- "1": {
- "domain": "code.getghostwriter.io",
- "servers": "255.255.255.123",
- "cdn_endpoint": "ghost-cdn.azureedge.net"
- },
+ "ip_address": "159.89.234.80",
+ "activity": "Command and Control",
+ "role": "Team Server / C2 Server",
+ "operator": "benny",
+ "start_date": "2019-07-29",
+ "end_date": "2019-08-09",
+ "note": "Used for Covenant C2."
}
},
- "team": {
+ "cloud": {
"1": {
"id": 1,
- "name": "Benny Ghostwriter",
- "project_role": "Assessment Lead",
- "email": "benny@ghostwriter.wiki",
- "start_date": "2019-07-29",
- "end_date": "2019-08-09",
- "note": "..."
+ "ip_address": "255.255.255.123",
+ "activity": "Phishing",
+ "role": "SMTP",
+ "operator": "benny",
+ "note": ""
},
- }
+ },
+ },
+ "domains_and_servers": {
+ "1": {
+ "domain": "code.getghostwriter.io",
+ "servers": "255.255.255.123",
+ "cdn_endpoint": "ghost-cdn.azureedge.net"
+ },
}
+ },
+ "team": {
+ "1": {
+ "id": 1,
+ "name": "Benny Ghostwriter",
+ "project_role": "Assessment Lead",
+ "email": "benny@ghostwriter.wiki",
+ "start_date": "2019-07-29",
+ "end_date": "2019-08-09",
+ "note": "..."
+ },
+ }
+}
```
### Office Documents
diff --git a/DOCS/features/reporting/templating-and-rich-text-fields.mdx b/DOCS/features/reporting/templating-and-rich-text-fields.mdx
index 77ba3d4a9..ca178afc0 100644
--- a/DOCS/features/reporting/templating-and-rich-text-fields.mdx
+++ b/DOCS/features/reporting/templating-and-rich-text-fields.mdx
@@ -100,5 +100,3 @@ If you need to escape Jinja syntax so that you can emit text like "\{\{" in your
First, you can use `{{ "{{" }}`, `{{ "{%" }}`, etc., to emit a string literal. This is convenient for one-off replacements.
For larger blocks, you can use Jinja's `{% raw %} ... {% endraw %}` blocks. Content in the block will not be parsed as Jinja tags and will be emitted as-is.
-
-[PreviousTroubleshooting Word Templates](/features/reporting/report-templates/troubleshooting-word-templates)[NextJinja2 Tips & Tricks](/features/reporting/jinja2-tips-and-tricks)
diff --git a/DOCS/getting-help/faq.mdx b/DOCS/getting-help/faq.mdx
index 03ecde80f..fd7d9a8b0 100644
--- a/DOCS/getting-help/faq.mdx
+++ b/DOCS/getting-help/faq.mdx
@@ -11,21 +11,21 @@ You may encounter an issue with PostgreSQL while upgrading an existing installat
By default, Ghostwriter CLI generates a random password for a default `postgres` user. Update the configuration with your Postgres credentials by running these commands:
-```
+```log
./ghostwriter-cli config set POSTGRES_USER
./ghostwriter-cli config set POSTGRES_PASSWORD
```
If that does not work or you need to change the credentials, you may do so with the `psql` tool. First, start the containers even if initialization fails due to the bad password.
-```
+```log
docker exec -it ghostwriter_postgres_1 bash
psql -U postgres
```
Use the `\password` command to set a new password for the `postgres` user:
-```
+```log
postgres=# \password postgres
Enter new password:
Enter it again:
@@ -35,7 +35,7 @@ postgres=# \q
If `postgres` is not your username, change the command to use your chosen username. If you are not sure what the username is, run the `\du` command:
-```
+```log
postgres=# \du
List of roles
Role name | Attributes | Member of
@@ -45,7 +45,7 @@ postgres=# \du
That sets the new password and `\q` quits the `psql` console. Set your new password in Ghostwriter's config, and then bring the containers down and back up.
-```
+```log
./ghostwriter-cli containers down
./ghostwriter-cli config set POSTGRES_PASSWORD
./ghostwriter-cli containers up
@@ -61,14 +61,14 @@ If you are stuck waiting for Django to start, run this command and check file pe
If you see file permission errors, check the user and group permissions for some of the affected files like so:
-```
+```log
docker-compose -f production.yml run django ls -la /app
docker-compose -f production.yml run django ls -la /app/staticfiles
```
A properly configured listing will look like this:
-```
+```log
$ docker-compose -f production.yml run django ls -la /app
Creating ghostwriter_django_run ... done
PostgreSQL is available
@@ -95,13 +95,13 @@ drwxr-xr-x 4 django django 4096 Feb 18 00:34 css
If you see anything else, you may need to re-run the `chown` command that Docker is supposed to run during the build. It must be run as `root`. Use Docker Compose's `run` command like the above examples but add `-u root`:
-```
+```log
$ docker-compose -f production.yml run -u root django chown -R django:django /app
```
Once that runs, verify the `ls -la` command shows the proper permissions, and then try restarting the Ghostwriter services:
-```
+```log
./ghostwriter-cli containers down
./ghostwriter-cli containers up
```
diff --git a/DOCS/getting-help/reporting-a-security-issue.mdx b/DOCS/getting-help/reporting-a-security-issue.mdx
index d28070f25..f8331eb48 100644
--- a/DOCS/getting-help/reporting-a-security-issue.mdx
+++ b/DOCS/getting-help/reporting-a-security-issue.mdx
@@ -19,5 +19,5 @@ Fixed vulnerabilities will be closed and documented in release notes.
If a vulnerability is not fixed for any reason, the issue will be closed, and why the vulnerability will not or can not be fixed will be documented.
-If you need to disclose a vulnerability that may be sensitive, you may disclose the issue privately via email. Send such reports to *[\[email protected\]](/cdn-cgi/l/email-protection)*.
+If you need to disclose a vulnerability that may be sensitive, you may disclose the issue privately via email. Send such reports to *info@getghostwriter.io*.
diff --git a/DOCS/getting-started/managing-the-server-with-ghostwriter-cli.mdx b/DOCS/getting-started/managing-the-server-with-ghostwriter-cli.mdx
index a81519956..c417bbe75 100644
--- a/DOCS/getting-started/managing-the-server-with-ghostwriter-cli.mdx
+++ b/DOCS/getting-started/managing-the-server-with-ghostwriter-cli.mdx
@@ -13,6 +13,7 @@ The following sections explain some of the core functionality.
By default, all commands target a production environment. Provide the `--dev` if you're interacting with a development environment. Every command can accept the `--dev` flag.
+
### Managing the Server Configuration
The `config` command is your Swiss Army knife when managing your server configuration. If you don't provide any subcommands or arguments, the command prints your current configuration values (the contents of your server's DotEnv file).
@@ -50,17 +51,17 @@ Ghostwriter CLI's `containers` command contains the following subcommands:
If you need to check which containers are running, issue the `running` command. This command lists all running containers related to Ghostwriter. The output will look something like this (edited for easier display):
-```json
- $ ./ghostwriter-cli running
- [+] Collecting list of running Ghostwriter containers...
- [+] Found 4 running Ghostwriter containers
-
- Name Container ID Image Status Ports
- –––––––––––– –––––––––––– –––––––––––– –––––––––––– ––––––––––––
- ghostwriter_graphql d90e.... ghostwriter_local_graphql Up 43 hours (healthy) 0.0.0.0:9691:9691 » 9691/tcp, 0.0.0.0:8080:8080 » 8080/tcp
- ghostwriter_queue 0559.... ghostwriter_local_queue Up 43 hours (healthy)
- ghostwriter_django bf9b.... ghostwriter_local_django Up 43 hours (healthy) 0.0.0.0:8000:8000 » 8000/tcp
- ghostwriter_postgres 9992.... ghostwriter_production_postgres Up 43 hours (healthy) 0.0.0.0:5432:5432 » 5432/tcp
+```log Running Containers
+$ ./ghostwriter-cli running
+[+] Collecting list of running Ghostwriter containers...
+[+] Found 4 running Ghostwriter containers
+
+ Name Container ID Image Status Ports
+ –––––––––––– –––––––––––– –––––––––––– –––––––––––– ––––––––––––
+ ghostwriter_graphql d90e.... ghostwriter_local_graphql Up 43 hours (healthy) 0.0.0.0:9691:9691 » 9691/tcp, 0.0.0.0:8080:8080 » 8080/tcp
+ ghostwriter_queue 0559.... ghostwriter_local_queue Up 43 hours (healthy)
+ ghostwriter_django bf9b.... ghostwriter_local_django Up 43 hours (healthy) 0.0.0.0:8000:8000 » 8000/tcp
+ ghostwriter_postgres 9992.... ghostwriter_production_postgres Up 43 hours (healthy) 0.0.0.0:5432:5432 » 5432/tcp
```
@@ -69,39 +70,32 @@ The `Status` column shows the uptime and health of the service. If you see an `u
You can use the `logs` command to view a particular container's recent log events. The command requires the name of a running container. Valid container names are:
* all
-
* django
-
* graphql
-
* nginx
-
* postgres
-
* redis
-
With `all`, logs from all running containers will be returned. By default, `logs` will return up to 500 lines. You can use the `--lines` flag to adjust how many lines you want to retrieve.
-
-```json
- $ ./ghostwriter-cli logs django
-
- PostgreSQL is available
- No changes detected
- Operations to perform:
- Apply all migrations: account, admin, api, auth, commandcenter, contenttypes, django_q, home, oplog, reporting, rest_framework_api_key, rolodex, sessions, shepherd, sites, socialaccount, users
- Running migrations:
- No migrations to apply.
- INFO: Will watch for changes in these directories: ['/app']
- INFO: Uvicorn running on http://0.0.0.0:8000 (Press CTRL+C to quit)
- INFO: Started reloader process [18] using watchgod
- INFO: Started server process [20]
- INFO 2022-06-06 21:47:37,673 server 20 140231754545992 Started server process [20]
- INFO: Waiting for application startup.
- INFO 2022-06-06 21:47:37,673 on 20 140231754545992 Waiting for application startup.
- INFO: ASGI 'lifespan' protocol appears unsupported.
- INFO 2022-06-06 21:47:37,674 on 20 140231754545992 ASGI 'lifespan' protocol appears unsupported.
- INFO: Application startup complete.
- INFO 2022-06-06 21:47:37,674 on 20 140231754545992 Application startup complete.
+```log Viewing Django Logs
+$ ./ghostwriter-cli logs django
+
+PostgreSQL is available
+No changes detected
+Operations to perform:
+ Apply all migrations: account, admin, api, auth, commandcenter, contenttypes, django_q, home, oplog, reporting, rest_framework_api_key, rolodex, sessions, shepherd, sites, socialaccount, users
+Running migrations:
+ No migrations to apply.
+INFO: Will watch for changes in these directories: ['/app']
+INFO: Uvicorn running on http://0.0.0.0:8000 (Press CTRL+C to quit)
+INFO: Started reloader process [18] using watchgod
+INFO: Started server process [20]
+INFO 2022-06-06 21:47:37,673 server 20 140231754545992 Started server process [20]
+INFO: Waiting for application startup.
+INFO 2022-06-06 21:47:37,673 on 20 140231754545992 Waiting for application startup.
+INFO: ASGI 'lifespan' protocol appears unsupported.
+INFO 2022-06-06 21:47:37,674 on 20 140231754545992 ASGI 'lifespan' protocol appears unsupported.
+INFO: Application startup complete.
+INFO 2022-06-06 21:47:37,674 on 20 140231754545992 Application startup complete.
```
diff --git a/DOCS/getting-started/quickstart.mdx b/DOCS/getting-started/quickstart.mdx
index a7b351e71..1306ad14d 100644
--- a/DOCS/getting-started/quickstart.mdx
+++ b/DOCS/getting-started/quickstart.mdx
@@ -23,7 +23,7 @@ As of v1.26, Compose uses aPython's DotEnv parser, which understands quotations.
Older installations of Docker Compose use `docker-compose` as the command. If you have `docker-compose` in your PATH instead of `docker compose`, consider upgrading to the latest version.
-```bash
+```log Checking Docker Version
$ docker compose version
Docker Compose version v2.23.3 # Good; >=1.26.x
@@ -65,18 +65,21 @@ Ghostwriter can run on Windows, macOS, and Linux, so there are multiple builds o
You can rename these binaries without causing any issues. This wiki will always refer to it simply as `ghostwriter-cli` for commands.
+
### Installing Ghostwriter
You can install Ghostwriter with three basic commands:
-```
+```log Installing Ghostwriter
$ git clone https://github.com/GhostManager/Ghostwriter.git
$ cd Ghostwriter
$ ./ghostwriter-cli install
```
+
Ghostwriter will create self-signed TLS/SSL certificates. If you'd like to use your signed certificates, do that now to make things easier. If you don't have them ready, you can install them later.
+
There is more information below in [Customizing Your Installation](/getting-started/quickstart#customizing-your-installation).
The `install` command will take care of everything necessary to create a production environment for you. That command performs the following actions:
@@ -96,6 +99,7 @@ If you'd prefer to install a development (`dev`) environment, you can run:
A development environment is best if you want to change Ghostwriter's codebase or test functionality. Debug logging is enabled, which makes it easier to troubleshoot. The `dev` installation does not use TLS, so it skips creating certificates.
+
### Accessing Ghostwriter
The Ghostwriter server will now be accessible! Just visit *https\://127.0.0.1* and authenticate with the *admin* user. The password is displayed in the Ghostwriter CLI output at the end of the installation.
@@ -116,13 +120,14 @@ You may create users using the admin panel or ask users to sign-up using `/accou
Django usernames are *case-sensitive*, so all lowercase is recommended to avoid confusion later.
+
### Customizing Your Installation
You may wish to change some of the configuration options. The following sections outline common customizations.
If you make changes to the configuration, restart Ghostwriter for the changes to take effect:
-```
+```log Bouncing Containers
./ghostwriter-cli containers down
./ghostwriter-cli containers up
```
@@ -173,6 +178,7 @@ A `*` will allow any hostname or IP address.
Anything like `*.myserver.local` or `192.168.10.*` will not work to allow a host.
+
#### Configuring Access Through a Web Proxy
Similar to the HTTP `Host` header protections, Ghostwriter also checks the `Origin` and `Referer` headers. If you are accessing Ghostwriter through a proxy, configure Ghostwriter to trust the proxy with this command:
diff --git a/DOCS/getting-started/updating-ghostwriter.mdx b/DOCS/getting-started/updating-ghostwriter.mdx
index 587542a54..9685ffd45 100644
--- a/DOCS/getting-started/updating-ghostwriter.mdx
+++ b/DOCS/getting-started/updating-ghostwriter.mdx
@@ -8,7 +8,7 @@ How to check for updates and what to do when one is available
You can check for updates with Ghostwriter CLI and the `update` command. The output will look something like this:
-```
+```bash Checking for Updates
$ ./ghostwriter-cli update
Local Ghostwriter Version Ghostwriter v3.0.5 ( 23 September 2022 )
@@ -29,7 +29,7 @@ Updates are generally straightforward, but you should **strongly** consider taki
To perform an update:
-```bash
+```log Updating Ghostwriter
git pull
./ghostwriter-cli containers down
./ghostwriter-cli containers build
@@ -37,5 +37,3 @@ git pull
```
These commands pull the latest code, stop any running production containers, build the new containers, and then bring Ghostwriter back online.
-
-[PreviousQuickstart](/getting-started/quickstart)[NextManaging the Server with Ghostwriter CLI](/getting-started/managing-the-server-with-ghostwriter-cli)
diff --git a/DOCS/home.mdx b/DOCS/home.mdx
index 5a9446d6e..497d4835c 100644
--- a/DOCS/home.mdx
+++ b/DOCS/home.mdx
@@ -21,7 +21,8 @@ Ghostwriter is licensed under the **BSD-3** license.
-```
+
+```markdown LICENSE.md
Copyright (c) 2024, Christopher Maddalena
All rights reserved.
@@ -50,8 +51,8 @@ Copyright (c) 2024, Christopher Maddalena
OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
OF THE POSSIBILITY OF SUCH DAMAGE.
-
```
+
diff --git a/DOCS/mint.json b/DOCS/mint.json
index 516a7d04e..7162b47bd 100644
--- a/DOCS/mint.json
+++ b/DOCS/mint.json
@@ -20,6 +20,9 @@
"default": "light",
"isHidden": false
},
+ "codeBlock": {
+ "mode": "auto"
+ },
"font":{
"headings": {
"family": "Nunito Sans",
@@ -33,8 +36,12 @@
},
"topbarLinks": [
{
- "name": "GitHub",
- "url": "https://github.com/GhostManager/Ghostwriter"
+ "name": "Learn More",
+ "url": "https://blog.getghostwriter.io/"
+ },
+ {
+ "name": "Get the Code",
+ "url": "https://code.getghostwriter.io/"
}
],
"topbarCtaButton": {
@@ -108,7 +115,6 @@
{
"group": "Features",
"pages": [
- "features/access-authentication-and-session-controls",
{
"group": "Access, Authentication, & Session Controls",
"pages": [