Skip to content

Commit

Permalink
merged
Browse files Browse the repository at this point in the history
  • Loading branch information
JannikStreek committed Nov 11, 2024
2 parents 2cc548f + 5213ae2 commit fa2aa4b
Show file tree
Hide file tree
Showing 53 changed files with 340 additions and 191 deletions.
2 changes: 1 addition & 1 deletion .buildpacks
Original file line number Diff line number Diff line change
@@ -1,3 +1,3 @@
https://github.com/nwittstruck/heroku-buildpack-elixir#scalingo
https://github.com/gjaldon/heroku-buildpack-phoenix-static
https://github.com/gigalixir/gigalixir-buildpack-phoenix-static
https://github.com/chrismcg/heroku-buildpack-elixir-mix-release
2 changes: 1 addition & 1 deletion .credo.exs
Original file line number Diff line number Diff line change
Expand Up @@ -130,6 +130,7 @@
{Credo.Check.Refactor.NegatedConditionsInUnless, []},
{Credo.Check.Refactor.NegatedConditionsWithElse, []},
{Credo.Check.Refactor.Nesting, []},
{Credo.Check.Refactor.PassAsyncInTestCases, []},
{Credo.Check.Refactor.RedundantWithClauseResult, []},
{Credo.Check.Refactor.RejectReject, []},
{Credo.Check.Refactor.UnlessWithElse, []},
Expand Down Expand Up @@ -198,7 +199,6 @@
{Credo.Check.Refactor.MapMap, []},
{Credo.Check.Refactor.ModuleDependencies, []},
{Credo.Check.Refactor.NegatedIsNil, []},
{Credo.Check.Refactor.PassAsyncInTestCases, []},
{Credo.Check.Refactor.PipeChainStart, []},
{Credo.Check.Refactor.RejectFilter, []},
{Credo.Check.Refactor.VariableRebinding, []},
Expand Down
5 changes: 3 additions & 2 deletions .env.default
Original file line number Diff line number Diff line change
Expand Up @@ -16,10 +16,11 @@ DOCKER_COMPOSE_APP_MW_FEATURE_STORAGE_PROVIDER=local
DOCKER_COMPOSE_APP_MW_FEATURE_IDEA_FILE_UPLOAD=true
DOCKER_COMPOSE_APP_OBJECT_STORAGE_USER=
DOCKER_COMPOSE_APP_OBJECT_STORAGE_PASSWORD=
# This is an example key. Do not use in production!
# please generate a secure key before, e.g. by using the elixir console inside the container:
# iex
# iex> 32 |> :crypto.strong_rand_bytes() |> Base.encode64()
DOCKER_COMPOSE_APP_VAULT_ENCRYPTION_KEY_BASE64=
DOCKER_COMPOSE_APP_VAULT_ENCRYPTION_KEY_BASE64="gI6L07o3RTppqy+cfAxO4C8G8psYHWn2NYPbUymYI1o="
# This is an example secret key base that can be use in development
# NOTE: There are multiple commands you can use to generate a secret key base. Pick one command you like, e.g. `date +%s | sha256sum | base64 | head -c 64 ; echo`
# !!ATTENTION: DO NOT USE THIS FOR PRODUCTION!!
Expand All @@ -38,4 +39,4 @@ DOCKER_COMPOSE_POSTGRES_DB=mindwendel-dev
DOCKER_COMPOSE_POSTGRES_PASSWORD=mindwendel-user-password
DOCKER_COMPOSE_POSTGRES_PORT=5432
DOCKER_COMPOSE_POSTGRES_PORT_PUBLISHED=5432
DOCKER_COMPOSE_POSTGRES_USER=mindwendel-user
DOCKER_COMPOSE_POSTGRES_USER=mindwendel-user
4 changes: 2 additions & 2 deletions .tool-versions
Original file line number Diff line number Diff line change
@@ -1,2 +1,2 @@
elixir 1.13.1-otp-23
erlang 23.1.5
elixir 1.15.8-otp-26
erlang 26.2.5
73 changes: 42 additions & 31 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
# mindwendel

![Workflow Status Badge](https://github.com/mindwendel/mindwendel/workflows/ci_cd/badge.svg)
![Workflow Status Badge](https://github.com/b310-digital/mindwendel/actions/workflows/on_push_branch__execute_ci_cd.yml/badge.svg)

Create a challenge. Ready? Brainstorm. mindwendel helps you to easily brainstorm and upvote ideas and thoughts within your team. Built from scratch with [Phoenix](https://www.phoenixframework.org).

Expand All @@ -25,7 +25,7 @@ Create a challenge. Ready? Brainstorm. mindwendel helps you to easily brainstorm

- 5 minute setup (It is not a joke)
- Anonymously invite people to your brainstormings - no registration needed. Usernames are optional
- Easily create and upvote ideas, with live updates from your companions
- Easily create and upvote ideas, with live updates from your mindwendel members
- Cluster or filter your ideas with custom labels
- Preview of links to ease URL sharing
- Add automatically encrypted file attachments which are uploaded to an S3 compatible storage backend
Expand All @@ -48,29 +48,9 @@ Brainstorm ...

## Getting Started

mindwendel can be run just about anywhere. So checkout our [Installation Guides](./docs/installing_mindwendel.md) for detailed instructions for various deployments.
mindwendel can be run just about anywhere. So checkout our [Installation Guides](./docs/installing_mindwendel.md) for detailed instructions for various deployments. The easiest way to deploy and run mindwendel is using our own `docker-compose-prod.yml` file. For instructions, see [Setup for Production](#setup-for-production).
If you want to contribute, jump ahead to [Development](#development)!

Here's the TLDR:

- Run mindwendel via Docker and reference your postgres database

```bash
docker run -d --name mindwendel \
-p 127.0.0.1:80:4000 \
-e DATABASE_HOST="..." \
-e DATABASE_PORT="5432" \
-e DATABASE_SSL="false" \
-e DATABASE_NAME="mindwendel_prod" \
-e DATABASE_USER="mindwendel_db_user" \
-e DATABASE_USER_PASSWORD="mindwendel_db_user_password" \
-e SECRET_KEY_BASE="generate_your_own_secret_key_base_and_save_it" \
-e URL_HOST="your_domain_to_mindwendel" \
ghcr.io/mindwendel/mindwendel
```

NOTE: mindwendel requires a postgres database. You can use [our docker-compose file](./docs/installing_mindwendel.md#running-on-docker-compose) to also install the postgres.

## Contributing

To get started with a development installation of mindwendel, follow the instructions below.
Expand Down Expand Up @@ -144,7 +124,7 @@ mix gettext.extract --merge
docker compose exec app mix test
```

### Production
### Setup for Production

- Generate self-signed ssl sertificate for the postgres server on the host machine; the generated files are mounted into the docker container

Expand All @@ -157,7 +137,7 @@ mix gettext.extract --merge
test $(uname -s) = Linux && chown 70 ./ca/server.key
```

- Duplicate and rename `.env.default`
- Duplicate and rename `.env.prod.default`

```bash
cp .env.prod.default .env.prod
Expand All @@ -178,6 +158,7 @@ mix gettext.extract --merge
- The url has to match the env var `URL_HOST`; so http://localhost will not work when your `URL_HOST=0.0.0.0`
- The mindwendel production configuration is setup to enforce ssl, see Mindwendel.Endpoint configuration in `config/prod.exs`
- The mindwendel production configuration supports deployment behind a reverse porxy (load balancer) by parsing the proper protocol from the x-forwarded-\* header of incoming requests, see `config/prod.exs`
- If you are having troubles during setup, please raise an issue.

### Build release and production docker image

Expand All @@ -199,22 +180,48 @@ We are using Elixir's built-in formatter.
mix format
```

## Environment Variables
## Feature flags

### Privacy and automatic data removal
Mindwendel includes a job runner that deletes old brainstormings after a defined number of days. This can be controlled with the setting `MW_FEATURE_BRAINSTORMING_REMOVAL_AFTER_DAYS`, which can be set to for instance to `30`.

### File Storage
Attached files are stored by default on the server in an upload directory. For a production setup, it is recommended to use a s3 compatible object storage.
File storage is available through an s3 compatible object storage backend. An encryption key (`VAULT_ENCRYPTION_KEY_BASE64`) needs to be generated before, e.g.:

```
iex
32 |> :crypto.strong_rand_bytes() |> Base.encode64()
```

or

```
DOCKER_COMPOSE_APP_MW_FEATURE_STORAGE_PROVIDER=s3
DOCKER_COMPOSE_APP_OBJECT_STORAGE_USER=...
DOCKER_COMPOSE_APP_OBJECT_STORAGE_PASSWORD=...
openssl rand -base64 32
```

Then, object storage and the vault key need to be set:

```
OBJECT_STORAGE_BUCKET: mindwendel
OBJECT_STORAGE_SCHEME: "http://"
OBJECT_STORAGE_HOST: minio
OBJECT_STORAGE_PORT: 9000
OBJECT_STORAGE_REGION: local
OBJECT_STORAGE_USER: ...
OBJECT_STORAGE_PASSWORD: ...
VAULT_ENCRYPTION_KEY_BASE64: ...
```

There is an example given inside the `docker-compose.yml` with a docker compose minio setup.

To deactivate file storage, use `MW_FEATURE_IDEA_FILE_UPLOAD` (defaults to `true`) and set it to `false`.

### Brainstorming teasers
If you want to display some teasers and help for your brainstorming, use `MW_FEATURE_BRAINSTORMING_TEASER` and set it to `true`.

### Localization

Currently, there are two language files available, german ("de") and english ("en"). To set the default_locale, you can set `MW_DEFAULT_LOCALE`. The default is english.
Currently, there are two language files available, german (`de`) and english (`en`). To set the default_locale, you can set `MW_DEFAULT_LOCALE`. The default is english.

## Testimonials

Expand All @@ -236,3 +243,7 @@ Logos and text provided with courtesy of kits.
- https://github.com/gerardo-navarro
- https://github.com/nwittstruck
- Lightbulb stock image by LED Supermarket at Pexels: https://www.pexels.com/de-de/foto/die-gluhbirne-577514/

## Image Licenses
- Lightbulb, Pexels / CC0: https://www.pexels.com/license/, https://www.pexels.com/terms-of-service/
- GitHub Logo: https://github.com/logos
2 changes: 1 addition & 1 deletion assets/scss/app.scss
Original file line number Diff line number Diff line change
Expand Up @@ -46,7 +46,7 @@ a .bi {
}

.bg-mindwendel {
background-image: url("/images/mindwendel.jpg");
background-image: url("/images/mindwendel.png");
background-repeat: no-repeat;
background-size: cover;
}
Expand Down
68 changes: 47 additions & 21 deletions config/runtime.exs
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,6 @@ import Config
require Logger

if config_env() == :prod do
# configure logging:
config :logger, :default_handler,
formatter: {
LoggerJSON.Formatters.Basic,
Expand Down Expand Up @@ -49,13 +48,28 @@ if config_env() != :test do
# disable on prod, because logger_json will take care of this. set to :debug for test and dev
ecto_log_level = if config_env() == :prod, do: false, else: :debug

ssl_config =
if System.get_env("DATABASE_SSL", "true") == "true",
do: [cacerts: :public_key.cacerts_get()],
else: nil
# default ssl_opts:
ssl_opts = [
verify: :verify_peer,
depth: 3,
versions: [:"tlsv1.3"],
server_name_indication: String.to_charlist(System.get_env("DATABASE_HOST")),
customize_hostname_check: [
match_fun: :public_key.pkix_verify_hostname_match_fun(:https)
]
]

# either use system certificates or specify files:
ssl_opts =
if System.get_env("DATABASE_CERT_FILE") do
Logger.info("Loading DATABASE_CERT_FILE")
ssl_opts ++ [cacertfile: System.get_env("DATABASE_CERT_FILE")]
else
Logger.info("Loading System Certificates")
ssl_opts ++ [cacerts: :public_key.cacerts_get()]
end

config :mindwendel, Mindwendel.Repo,
start_apps_before_migration: [:logger_json],
database: System.get_env("DATABASE_NAME"),
hostname: System.get_env("DATABASE_HOST"),
password: System.get_env("DATABASE_USER_PASSWORD"),
Expand All @@ -65,7 +79,8 @@ if config_env() != :test do
url: System.get_env("DATABASE_URL"),
timeout: String.to_integer(System.get_env("DATABASE_TIMEOUT", "15000")),
log: ecto_log_level,
ssl: ssl_config
ssl: System.get_env("DATABASE_SSL", "true") == "true",
ssl_opts: ssl_opts

secret_key_base =
System.get_env("SECRET_KEY_BASE") ||
Expand Down Expand Up @@ -156,19 +171,28 @@ delete_brainstormings_after_days =
30
end

feature_file_upload =
Enum.member?(
["", "true"],
String.trim(System.get_env("MW_FEATURE_IDEA_FILE_UPLOAD") || "")
)

feature_privacy_imprint_enabled =
Enum.member?(
["true"],
String.trim(System.get_env("MW_FEATURE_LEGAL_PRIVACY_LINKS") || "")
)

# enable/disable brainstorming teasers and configure delete brainstormings option:
config :mindwendel, :options,
feature_brainstorming_teasers:
Enum.member?(
["", "true"],
String.trim(System.get_env("MW_FEATURE_BRAINSTORMING_TEASER") || "")
),
feature_file_upload:
Enum.member?(
["", "true"],
String.trim(System.get_env("MW_FEATURE_IDEA_FILE_UPLOAD") || "")
),
feature_file_upload: feature_file_upload,
feature_brainstorming_removal_after_days: delete_brainstormings_after_days,
feature_privacy_imprint_enabled: feature_privacy_imprint_enabled,
# use a strict csp everywhere except in development. we need to relax the setting a bit for webpack
csp_relax: config_env() == :dev

Expand All @@ -188,17 +212,19 @@ end
config :mindwendel, max_upload_length: System.get_env("MW_FILE_UPLOAD_MAX_FILE_SIZE", "2666666")

# configure cloak:
config :mindwendel, Mindwendel.Services.Vault,
ciphers: [
default:
{Cloak.Ciphers.AES.GCM,
tag: "AES.GCM.V1",
key: Base.decode64!(System.fetch_env!("VAULT_ENCRYPTION_KEY_BASE64")),
iv_length: 12}
]
if feature_file_upload do
config :mindwendel, Mindwendel.Services.Vault,
ciphers: [
default:
{Cloak.Ciphers.AES.GCM,
tag: "AES.GCM.V1",
key: Base.decode64!(System.fetch_env!("VAULT_ENCRYPTION_KEY_BASE64")),
iv_length: 12}
]
end

# check all object storage system envs at once:
if config_env() == :prod || config_env() == :dev do
if feature_file_upload and (config_env() == :prod || config_env() == :dev) do
config(:ex_aws, :s3,
scheme: System.fetch_env!("OBJECT_STORAGE_SCHEME"),
host: System.fetch_env!("OBJECT_STORAGE_HOST"),
Expand Down
Loading

0 comments on commit fa2aa4b

Please sign in to comment.