diff --git a/src/.env.example b/ansible/env rename from src/.env.example rename to ansible/env --- a/src/.env.example +++ b/ansible/env @@ -1,12 +1,12 @@ APP_NAME=Kolab APP_ENV=local -APP_KEY= +APP_KEY=base64:FG6ECzyAMSmyX+eYwO/FW3bwnarbKkBhqtO65vlMb1E= APP_DEBUG=true -APP_URL=https://kolab.local -#APP_PASSPHRASE= -APP_PUBLIC_URL=https://kolab.local -APP_DOMAIN=kolab.local -APP_WEBSITE_DOMAIN=kolab.local +APP_URL=https://{{ host }} +APP_PASSPHRASE=simple123 +APP_PUBLIC_URL=https://{{ host }} +APP_DOMAIN={{ host }} +APP_WEBSITE_DOMAIN={{ host }} APP_THEME=default APP_TENANT_ID=5 APP_LOCALE=en @@ -18,6 +18,7 @@ APP_WITH_FILES=1 APP_LDAP=1 +APP_IMAP=0 APP_HEADER_CSP="connect-src 'self'; child-src 'self'; font-src 'self'; form-action 'self' data:; frame-ancestors 'self'; img-src blob: data: 'self' *; media-src 'self'; object-src 'self'; script-src 'self' 'unsafe-inline' 'unsafe-eval'; style-src 'self' 'unsafe-eval' 'unsafe-inline'; default-src 'self';" APP_HEADER_XFO=sameorigin @@ -25,7 +26,8 @@ SIGNUP_LIMIT_EMAIL=0 SIGNUP_LIMIT_IP=0 -ASSET_URL=https://kolab.local +ASSET_URL=https://{{ host }} + WEBMAIL_URL=/roundcubemail/ SUPPORT_URL=/support @@ -51,8 +53,6 @@ SESSION_DRIVER=file SESSION_LIFETIME=120 -OPENEXCHANGERATES_API_KEY="from openexchangerates.org" - MFA_DSN=mysql://roundcube:Welcome2KolabSystems@mariadb/roundcube MFA_TOTP_DIGITS=6 MFA_TOTP_INTERVAL=30 @@ -84,17 +84,17 @@ LDAP_HOSTED_BIND_PW="Welcome2KolabSystems" LDAP_HOSTED_ROOT_DN="dc=hosted,dc=com" -COTURN_PUBLIC_IP='172.18.0.1' +COTURN_PUBLIC_IP='{{ public_ip }}' COTURN_STATIC_SECRET="Welcome2KolabSystems" MEET_WEBHOOK_TOKEN=Welcome2KolabSystems MEET_SERVER_TOKEN=Welcome2KolabSystems -MEET_SERVER_URLS=https://kolab.local/meetmedia/api/ +MEET_SERVER_URLS=https://{{ host }}/meetmedia/api/ MEET_SERVER_VERIFY_TLS=false -MEET_WEBRTC_LISTEN_IP='172.18.0.1' -MEET_PUBLIC_DOMAIN=kolab.local -MEET_TURN_SERVER='turn:172.18.0.1:3478' +MEET_WEBRTC_LISTEN_IP='{{ public_ip }}' +MEET_PUBLIC_DOMAIN={{ host }} +MEET_TURN_SERVER='turn:{{ public_ip }}:3478' MEET_LISTENING_HOST=172.18.0.1 @@ -113,7 +113,7 @@ REDIS_PASSWORD=null REDIS_PORT=6379 -OCTANE_HTTP_HOST=127.0.0.1 +OCTANE_HTTP_HOST={{ host }} SWOOLE_PACKAGE_MAX_LENGTH=10485760 PAYMENT_PROVIDER= @@ -154,13 +154,13 @@ MIX_PUSHER_APP_KEY="${PUSHER_APP_KEY}" MIX_PUSHER_APP_CLUSTER="${PUSHER_APP_CLUSTER}" -# Generate with ./artisan passport:client --password -#PASSPORT_PROXY_OAUTH_CLIENT_ID= -#PASSPORT_PROXY_OAUTH_CLIENT_SECRET= +#Generated by php artisan passport:client --password, but can be left hardcoded (the seeder will pick it up) +PASSPORT_PROXY_OAUTH_CLIENT_ID=942edef5-3dbd-4a14-8e3e-d5d59b727bee +PASSPORT_PROXY_OAUTH_CLIENT_SECRET=L6L0n56ecvjjK0cJMjeeV1pPAeffUBO0YSSH63wf -# Generate with ./artisan passport:client --password -#PASSPORT_COMPANIONAPP_OAUTH_CLIENT_ID= -#PASSPORT_COMPANIONAPP_OAUTH_CLIENT_SECRET= +#Generated by php artisan passport:client --password, but can be left hardcoded (the seeder will pick it up) +PASSPORT_COMPANIONAPP_OAUTH_CLIENT_ID=9566e018-f05d-425c-9915-420cdb9258bb +PASSPORT_COMPANIONAPP_OAUTH_CLIENT_SECRET=XjgV6SU9shO0QFKaU6pQPRC5rJpyRezDJTSoGLgz PASSPORT_PRIVATE_KEY= PASSPORT_PUBLIC_KEY= @@ -181,9 +181,13 @@ KB_ACCOUNT_SUSPENDED= KB_PAYMENT_SYSTEM= -KOLAB_SSL_CERTIFICATE=/etc/pki/tls/certs/kolab.hosted.com.cert -KOLAB_SSL_CERTIFICATE_FULLCHAIN=/etc/pki/tls/certs/kolab.hosted.com.chain.pem -KOLAB_SSL_CERTIFICATE_KEY=/etc/pki/tls/certs/kolab.hosted.com.key +KOLAB_SSL_CERTIFICATE=/etc/letsencrypt/live/{{ host }}/cert.pem +KOLAB_SSL_CERTIFICATE_FULLCHAIN=/etc/letsencrypt/live/{{ host }}/fullchain.pem +KOLAB_SSL_CERTIFICATE_KEY=/etc/letsencrypt/live/{{ host }}/privkey.pem + +PROXY_SSL_CERTIFICATE=/etc/letsencrypt/live/{{ host }}/fullchain.pem +PROXY_SSL_CERTIFICATE_KEY=/etc/letsencrypt/live/{{ host }}/privkey.pem + +OPENEXCHANGERATES_API_KEY={{ openexchangerates_api_key }} +FIREBASE_API_KEY={{ firebase_api_key }} -PROXY_SSL_CERTIFICATE=/etc/certs/imap.hosted.com.cert -PROXY_SSL_CERTIFICATE_KEY=/etc/certs/imap.hosted.com.key diff --git a/ansible/env.local b/ansible/env.local deleted file mode 100644 --- a/ansible/env.local +++ /dev/null @@ -1,43 +0,0 @@ -APP_DOMAIN={{ host }} -APP_WEBSITE_DOMAIN={{ host }} -APP_KEY=base64:FG6ECzyAMSmyX+eYwO/FW3bwnarbKkBhqtO65vlMb1E= -APP_PUBLIC_URL=https://{{ host }} -COTURN_STATIC_SECRET=uzYguvIl9tpZFMuQOE78DpOi6Jc7VFSD0UAnvgMsg5n4e74MgIf6vQvbc6LWzZjz -COTURN_PUBLIC_IP='{{ public_ip }}' -MEET_TURN_SERVER='turn:{{ public_ip }}:3478' -MEET_WEBRTC_LISTEN_IP='{{ public_ip }}' -MEET_PUBLIC_DOMAIN={{ host }} -MEET_SERVER_URLS=https://{{ host }}/meetmedia/api/ -APP_URL=https://{{ host }} -ASSET_URL=https://{{ host }} - -DB_HOST=mariadb -REDIS_HOST=redis -IMAP_URI=ssl://kolab:11993 -LDAP_HOSTS=kolab - -MOLLIE_KEY= -STRIPE_KEY= -STRIPE_PUBLIC_KEY= -STRIPE_WEBHOOK_SECRET= - -OCTANE_HTTP_HOST={{ host }} -OPENEXCHANGERATES_API_KEY={{ openexchangerates_api_key }} -FIREBASE_API_KEY={{ firebase_api_key }} - -#Generated by php artisan passport:client --password, but can be left hardcoded (the seeder will pick it up) -PASSPORT_PROXY_OAUTH_CLIENT_ID=942edef5-3dbd-4a14-8e3e-d5d59b727bee -PASSPORT_PROXY_OAUTH_CLIENT_SECRET=L6L0n56ecvjjK0cJMjeeV1pPAeffUBO0YSSH63wf - -#Generated by php artisan passport:client --password, but can be left hardcoded (the seeder will pick it up) -PASSPORT_COMPANIONAPP_OAUTH_CLIENT_ID=9566e018-f05d-425c-9915-420cdb9258bb -PASSPORT_COMPANIONAPP_OAUTH_CLIENT_SECRET=XjgV6SU9shO0QFKaU6pQPRC5rJpyRezDJTSoGLgz - -APP_PASSPHRASE=simple123 - -KOLAB_SSL_CERTIFICATE=/etc/letsencrypt/live/{{ host }}/cert.pem -KOLAB_SSL_CERTIFICATE_FULLCHAIN=/etc/letsencrypt/live/{{ host }}/fullchain.pem -KOLAB_SSL_CERTIFICATE_KEY=/etc/letsencrypt/live/{{ host }}/privkey.pem - -PROXY_SSL_CERTIFICATE=/etc/letsencrypt/live/{{ host }}/fullchain.pem -PROXY_SSL_CERTIFICATE_KEY=/etc/letsencrypt/live/{{ host }}/privkey.pem diff --git a/ansible/setup.yml b/ansible/setup.yml --- a/ansible/setup.yml +++ b/ansible/setup.yml @@ -46,15 +46,22 @@ version: "{{ git_branch }}" force: yes - - name: "kolab env.local" + - name: Run bin/configure + become: true + become_user: kolab + ansible.builtin.command: bin/configure.sh config.local + args: + chdir: /home/kolab/kolab + + - name: "Adjusting config" vars: host: "{{ hostname }}" openexchangerates_api_key: "{{ openexchangerates_api_key }}" firebase_api_key: "{{ firebase_api_key }}" public_ip: "{{ public_ip }}" ansible.builtin.template: - src: env.local - dest: /home/kolab/kolab/src/env.local + src: env + dest: /home/kolab/kolab/src/.env owner: kolab group: kolab mode: '0766' diff --git a/bin/configure.sh b/bin/configure.sh new file mode 100755 --- /dev/null +++ b/bin/configure.sh @@ -0,0 +1,32 @@ +#!/bin/bash + +if [ ! -d $1 ]; then + echo "Failed to find the configuration folder, please pass one as argument (e.g. config.local)." + exit 1 +fi + +# Uninstall the old config +if [ -d config ]; then + find -L config/ -type f | while read file; do + file=$(echo $file | sed -e 's|^config||g') + file="./$file" + + rm -v $file + done +fi + +# Link new config +rm config +ln -s $1 config + +# Install new config +find -L config/ -type f | while read file; do + dir=$(dirname $file | sed -e 's|^config||g') + dir="./$dir" + + if [ ! -d $dir ]; then + mkdir -p $dir + fi + + cp -av $file $dir/ +done diff --git a/bin/quickstart.sh b/bin/quickstart.sh --- a/bin/quickstart.sh +++ b/bin/quickstart.sh @@ -16,14 +16,7 @@ base_dir=$(dirname $(dirname $0)) -# Always reset .env with .env.example -cp src/.env.example src/.env -if [ -f "src/env.local" ]; then - # Ensure there's a line ending - echo "" >> src/.env - cat src/env.local >> src/.env -fi export DOCKER_BUILDKIT=0 @@ -37,16 +30,12 @@ docker volume rm kolab_imap || : docker volume rm kolab_ldap || : -if [ "$1" != "--nodev" ]; then - src/artisan octane:stop >/dev/null 2>&1 || : - src/artisan horizon:terminate >/dev/null 2>&1 || : -else - # If we switch from an existing development setup to a compose deployment, - # we don't have a nice way to terminate octane/horizon. - # We can't use the artisan command because it will just block if redis is, - # no longer available, so we just kill all artisan processes running. - pkill -9 -f artisan || : -fi +# We can't use the following artisan commands because it will just block if redis is unavailable: +# src/artisan octane:stop >/dev/null 2>&1 || : +# src/artisan horizon:terminate >/dev/null 2>&1 || : +# we therefore just kill all artisan processes running. +pkill -9 -f artisan || : +pkill -9 -f swoole || : bin/regen-certs docker-compose build coturn kolab mariadb meet pdns proxy redis haproxy diff --git a/ci/Makefile b/ci/Makefile --- a/ci/Makefile +++ b/ci/Makefile @@ -7,11 +7,12 @@ configure: cd .. ; \ - cp ci/env.local src/env.local ; \ - sed -i 's/{{ host }}/${HOSTNAME}/g' src/env.local ; \ - sed -i 's/{{ public_ip }}/${PUBLIC_IP}/g' src/env.local ; \ - sed -i 's/{{ openexchangerates_api_key }}/${OPENEXCHANGERATES_API_KEY}/g' src/env.local ; \ - sed -i 's/{{ firebase_api_key }}/${FIREBASE_API_KEY}/g' src/env.local ; + bin/configure.sh config.local ; \ + cp ci/env src/.env ; \ + sed -i 's/{{ host }}/${HOSTNAME}/g' src/.env ; \ + sed -i 's/{{ public_ip }}/${PUBLIC_IP}/g' src/.env ; \ + sed -i 's/{{ openexchangerates_api_key }}/${OPENEXCHANGERATES_API_KEY}/g' src/.env ; \ + sed -i 's/{{ firebase_api_key }}/${FIREBASE_API_KEY}/g' src/.env ; setup: cd .. && bin/quickstart.sh --nodev diff --git a/ci/env.local b/ci/env.local deleted file mode 100644 --- a/ci/env.local +++ /dev/null @@ -1,49 +0,0 @@ -MFA_DSN=mysql://root:Welcome2KolabSystems@mariadb/roundcube -APP_DOMAIN={{ host }} -APP_WEBSITE_DOMAIN={{ host }} -APP_KEY=base64:FG6ECzyAMSmyX+eYwO/FW3bwnarbKkBhqtO65vlMb1E= -APP_PUBLIC_URL=https://{{ host }} -COTURN_STATIC_SECRET=uzYguvIl9tpZFMuQOE78DpOi6Jc7VFSD0UAnvgMsg5n4e74MgIf6vQvbc6LWzZjz -COTURN_PUBLIC_IP='{{ public_ip }}' -MEET_TURN_SERVER='turn:{{ public_ip }}:3478' -MEET_WEBRTC_LISTEN_IP='{{ public_ip }}' -MEET_PUBLIC_DOMAIN={{ host }} -MEET_SERVER_URLS=https://{{ host }}/meetmedia/api/ -MEET_LISTENING_HOST=172.18.0.1 -WEBMAIL_URL=/roundcubemail -APP_URL=https://{{ host }} -ASSET_URL=https://{{ host }} - -DB_HOST=mariadb -REDIS_HOST=redis -IMAP_URI=ssl://kolab:11993 -LDAP_HOSTS=kolab - -MOLLIE_KEY= -STRIPE_KEY= -STRIPE_PUBLIC_KEY= -STRIPE_WEBHOOK_SECRET= - -OCTANE_HTTP_HOST={{ host }} -OPENEXCHANGERATES_API_KEY={{ openexchangerates_api_key }} -FIREBASE_API_KEY={{ firebase_api_key }} - -#Generated by php artisan passport:client --password, but can be left hardcoded (the seeder will pick it up) -PASSPORT_PROXY_OAUTH_CLIENT_ID=942edef5-3dbd-4a14-8e3e-d5d59b727bee -PASSPORT_PROXY_OAUTH_CLIENT_SECRET=L6L0n56ecvjjK0cJMjeeV1pPAeffUBO0YSSH63wf - -#Generated by php artisan passport:client --password, but can be left hardcoded (the seeder will pick it up) -PASSPORT_COMPANIONAPP_OAUTH_CLIENT_ID=9566e018-f05d-425c-9915-420cdb9258bb -PASSPORT_COMPANIONAPP_OAUTH_CLIENT_SECRET=XjgV6SU9shO0QFKaU6pQPRC5rJpyRezDJTSoGLgz - -APP_TENANT_ID=42 -APP_PASSPHRASE=simple123 - -MAIL_DRIVER=log - -KOLAB_SSL_CERTIFICATE=/etc/pki/tls/certs/kolab.hosted.com.cert -KOLAB_SSL_CERTIFICATE_FULLCHAIN=/etc/pki/tls/certs/kolab.hosted.com.chain.pem -KOLAB_SSL_CERTIFICATE_KEY=/etc/pki/tls/certs/kolab.hosted.com.key - -PROXY_SSL_CERTIFICATE=/etc/certs/imap.hosted.com.cert -PROXY_SSL_CERTIFICATE_KEY=/etc/certs/imap.hosted.com.key diff --git a/src/.env.example b/config.local/src/.env copy from src/.env.example copy to config.local/src/.env --- a/src/.env.example +++ b/config.local/src/.env @@ -3,7 +3,7 @@ APP_KEY= APP_DEBUG=true APP_URL=https://kolab.local -#APP_PASSPHRASE= +APP_PASSPHRASE=simple123 APP_PUBLIC_URL=https://kolab.local APP_DOMAIN=kolab.local APP_WEBSITE_DOMAIN=kolab.local @@ -18,6 +18,7 @@ APP_WITH_FILES=1 APP_LDAP=1 +APP_IMAP=0 APP_HEADER_CSP="connect-src 'self'; child-src 'self'; font-src 'self'; form-action 'self' data:; frame-ancestors 'self'; img-src blob: data: 'self' *; media-src 'self'; object-src 'self'; script-src 'self' 'unsafe-inline' 'unsafe-eval'; style-src 'self' 'unsafe-eval' 'unsafe-inline'; default-src 'self';" APP_HEADER_XFO=sameorigin @@ -113,7 +114,7 @@ REDIS_PASSWORD=null REDIS_PORT=6379 -OCTANE_HTTP_HOST=127.0.0.1 +OCTANE_HTTP_HOST=0.0.0.0 SWOOLE_PACKAGE_MAX_LENGTH=10485760 PAYMENT_PROVIDER= @@ -187,3 +188,23 @@ PROXY_SSL_CERTIFICATE=/etc/certs/imap.hosted.com.cert PROXY_SSL_CERTIFICATE_KEY=/etc/certs/imap.hosted.com.key + +APP_KEY=base64:FG6ECzyAMSmyX+eYwO/FW3bwnarbKkBhqtO65vlMb1E= +COTURN_STATIC_SECRET=uzYguvIl9tpZFMuQOE78DpOi6Jc7VFSD0UAnvgMsg5n4e74MgIf6vQvbc6LWzZjz + +MOLLIE_KEY="from mollie" +STRIPE_KEY="from stripe" +STRIPE_PUBLIC_KEY="from stripe" +STRIPE_WEBHOOK_SECRET="from stripe" + +OX_API_KEY="from openexchange" +FIREBASE_API_KEY="from firebase" + +#Generated by php artisan passport:client --password, but can be left hardcoded (the seeder will pick it up) +PASSPORT_PROXY_OAUTH_CLIENT_ID=942edef5-3dbd-4a14-8e3e-d5d59b727bee +PASSPORT_PROXY_OAUTH_CLIENT_SECRET=L6L0n56ecvjjK0cJMjeeV1pPAeffUBO0YSSH63wf + +#Generated by php artisan passport:client --password, but can be left hardcoded (the seeder will pick it up) +PASSPORT_COMPANIONAPP_OAUTH_CLIENT_ID=9566e018-f05d-425c-9915-420cdb9258bb +PASSPORT_COMPANIONAPP_OAUTH_CLIENT_SECRET=XjgV6SU9shO0QFKaU6pQPRC5rJpyRezDJTSoGLgz + diff --git a/src/database/migrations/2021_01_26_150000_change_sku_descriptions.php b/config.local/src/database/migrations/2021_01_26_150000_change_sku_descriptions.php rename from src/database/migrations/2021_01_26_150000_change_sku_descriptions.php rename to config.local/src/database/migrations/2021_01_26_150000_change_sku_descriptions.php diff --git a/src/database/migrations/2021_02_19_100000_transaction_amount_fix.php b/config.local/src/database/migrations/2021_02_19_100000_transaction_amount_fix.php rename from src/database/migrations/2021_02_19_100000_transaction_amount_fix.php rename to config.local/src/database/migrations/2021_02_19_100000_transaction_amount_fix.php diff --git a/src/database/migrations/2021_12_15_100000_rename_beta_skus.php b/config.local/src/database/migrations/2021_12_15_100000_rename_beta_skus.php rename from src/database/migrations/2021_12_15_100000_rename_beta_skus.php rename to config.local/src/database/migrations/2021_12_15_100000_rename_beta_skus.php diff --git a/config.local/src/database/migrations/2022_05_13_090000_permissions_and_room_subscriptions.php b/config.local/src/database/migrations/2022_05_13_090000_permissions_and_room_subscriptions.php new file mode 100644 --- /dev/null +++ b/config.local/src/database/migrations/2022_05_13_090000_permissions_and_room_subscriptions.php @@ -0,0 +1,57 @@ + 'group-room', + 'name' => 'Group conference room', + 'description' => 'Shareable audio & video conference room', + 'cost' => 0, + 'units_free' => 0, + 'period' => 'monthly', + 'handler_class' => 'App\Handlers\GroupRoom', + 'active' => true, + ]); + + \App\Sku::create([ + 'title' => 'room', + 'name' => 'Standard conference room', + 'description' => 'Audio & video conference room', + 'cost' => 0, + 'units_free' => 0, + 'period' => 'monthly', + 'handler_class' => 'App\Handlers\Room', + 'active' => true, + ]); + } + + /** + * Reverse the migrations. + */ + public function down(): void + { + \App\Sku::where('title', 'room')->delete(); + \App\Sku::where('title', 'group-room')->delete(); + + \App\Sku::create([ + 'title' => 'meet', + 'name' => 'Voice & Video Conferencing (public beta)', + 'description' => 'Video conferencing tool', + 'cost' => 0, + 'units_free' => 0, + 'period' => 'monthly', + 'handler_class' => 'App\Handlers\Meet', + 'active' => true, + ]); + } +}; diff --git a/src/database/migrations/2022_07_08_100000_fix_group_sku_name.php b/config.local/src/database/migrations/2022_07_08_100000_fix_group_sku_name.php rename from src/database/migrations/2022_07_08_100000_fix_group_sku_name.php rename to config.local/src/database/migrations/2022_07_08_100000_fix_group_sku_name.php diff --git a/config.local/src/database/migrations/2022_09_08_100001_plans_free_months.php b/config.local/src/database/migrations/2022_09_08_100001_plans_free_months.php new file mode 100644 --- /dev/null +++ b/config.local/src/database/migrations/2022_09_08_100001_plans_free_months.php @@ -0,0 +1,26 @@ +update(['free_months' => 1]); + } + + /** + * Reverse the migrations. + * + * @return void + */ + public function down() + { + } +}; diff --git a/config.local/src/database/seeds/DatabaseSeeder.php b/config.local/src/database/seeds/DatabaseSeeder.php new file mode 100644 --- /dev/null +++ b/config.local/src/database/seeds/DatabaseSeeder.php @@ -0,0 +1,32 @@ +call([ + Local\IP4NetSeeder::class, + Local\TenantSeeder::class, + Local\DiscountSeeder::class, + Local\DomainSeeder::class, + Local\SkuSeeder::class, + Local\PackageSeeder::class, + Local\PlanSeeder::class, + Local\PowerDNSSeeder::class, + Local\UserSeeder::class, + Local\OauthClientSeeder::class, + Local\ResourceSeeder::class, + Local\SharedFolderSeeder::class, + Local\MeetRoomSeeder::class, + ]); + } +} diff --git a/src/database/seeds/local/DiscountSeeder.php b/config.local/src/database/seeds/DiscountSeeder.php rename from src/database/seeds/local/DiscountSeeder.php rename to config.local/src/database/seeds/DiscountSeeder.php diff --git a/src/database/seeds/local/DomainSeeder.php b/config.local/src/database/seeds/DomainSeeder.php rename from src/database/seeds/local/DomainSeeder.php rename to config.local/src/database/seeds/DomainSeeder.php diff --git a/src/database/seeds/local/IP4NetSeeder.php b/config.local/src/database/seeds/IP4NetSeeder.php rename from src/database/seeds/local/IP4NetSeeder.php rename to config.local/src/database/seeds/IP4NetSeeder.php diff --git a/src/database/seeds/local/MeetRoomSeeder.php b/config.local/src/database/seeds/MeetRoomSeeder.php rename from src/database/seeds/local/MeetRoomSeeder.php rename to config.local/src/database/seeds/MeetRoomSeeder.php diff --git a/src/database/seeds/local/OauthClientSeeder.php b/config.local/src/database/seeds/OauthClientSeeder.php rename from src/database/seeds/local/OauthClientSeeder.php rename to config.local/src/database/seeds/OauthClientSeeder.php diff --git a/src/database/seeds/local/PackageSeeder.php b/config.local/src/database/seeds/PackageSeeder.php rename from src/database/seeds/local/PackageSeeder.php rename to config.local/src/database/seeds/PackageSeeder.php diff --git a/src/database/seeds/local/PlanSeeder.php b/config.local/src/database/seeds/PlanSeeder.php rename from src/database/seeds/local/PlanSeeder.php rename to config.local/src/database/seeds/PlanSeeder.php diff --git a/src/database/seeds/local/PowerDNSSeeder.php b/config.local/src/database/seeds/PowerDNSSeeder.php rename from src/database/seeds/local/PowerDNSSeeder.php rename to config.local/src/database/seeds/PowerDNSSeeder.php diff --git a/src/database/seeds/local/ResourceSeeder.php b/config.local/src/database/seeds/ResourceSeeder.php rename from src/database/seeds/local/ResourceSeeder.php rename to config.local/src/database/seeds/ResourceSeeder.php diff --git a/src/database/seeds/local/SharedFolderSeeder.php b/config.local/src/database/seeds/SharedFolderSeeder.php rename from src/database/seeds/local/SharedFolderSeeder.php rename to config.local/src/database/seeds/SharedFolderSeeder.php diff --git a/src/database/seeds/local/SkuSeeder.php b/config.local/src/database/seeds/SkuSeeder.php rename from src/database/seeds/local/SkuSeeder.php rename to config.local/src/database/seeds/SkuSeeder.php diff --git a/src/database/seeds/local/TenantSeeder.php b/config.local/src/database/seeds/TenantSeeder.php rename from src/database/seeds/local/TenantSeeder.php rename to config.local/src/database/seeds/TenantSeeder.php diff --git a/src/database/seeds/local/UserSeeder.php b/config.local/src/database/seeds/UserSeeder.php rename from src/database/seeds/local/UserSeeder.php rename to config.local/src/database/seeds/UserSeeder.php diff --git a/src/.env.example b/config.localhost/src/.env rename from src/.env.example rename to config.localhost/src/.env --- a/src/.env.example +++ b/config.localhost/src/.env @@ -1,9 +1,9 @@ APP_NAME=Kolab APP_ENV=local -APP_KEY= +APP_KEY=base64:FG6ECzyAMSmyX+eYwO/FW3bwnarbKkBhqtO65vlMb1E= APP_DEBUG=true APP_URL=https://kolab.local -#APP_PASSPHRASE= +APP_PASSPHRASE=simple123 APP_PUBLIC_URL=https://kolab.local APP_DOMAIN=kolab.local APP_WEBSITE_DOMAIN=kolab.local @@ -38,7 +38,7 @@ DB_CONNECTION=mysql DB_DATABASE=kolabdev -DB_HOST=mariadb +DB_HOST=127.0.0.1 DB_PASSWORD=kolab DB_PORT=3306 DB_USERNAME=kolabdev @@ -53,13 +53,13 @@ OPENEXCHANGERATES_API_KEY="from openexchangerates.org" -MFA_DSN=mysql://roundcube:Welcome2KolabSystems@mariadb/roundcube +MFA_DSN=mysql://root:Welcome2KolabSystems@127.0.0.1/roundcube MFA_TOTP_DIGITS=6 MFA_TOTP_INTERVAL=30 MFA_TOTP_DIGEST=sha1 -IMAP_URI=ssl://kolab:11993 -IMAP_HOST=172.18.0.5 +IMAP_URI=ssl://127.0.0.1:11993 +IMAP_HOST=127.0.0.1 IMAP_ADMIN_LOGIN=cyrus-admin IMAP_ADMIN_PASSWORD=Welcome2KolabSystems IMAP_VERIFY_HOST=false @@ -67,7 +67,7 @@ LDAP_BASE_DN="dc=mgmt,dc=com" LDAP_DOMAIN_BASE_DN="ou=Domains,dc=mgmt,dc=com" -LDAP_HOSTS=kolab +LDAP_HOSTS=127.0.0.1 LDAP_PORT=389 LDAP_SERVICE_BIND_DN="uid=kolab-service,ou=Special Users,dc=mgmt,dc=com" LDAP_SERVICE_BIND_PW="Welcome2KolabSystems" @@ -84,18 +84,18 @@ LDAP_HOSTED_BIND_PW="Welcome2KolabSystems" LDAP_HOSTED_ROOT_DN="dc=hosted,dc=com" -COTURN_PUBLIC_IP='172.18.0.1' +COTURN_PUBLIC_IP='127.0.0.1' COTURN_STATIC_SECRET="Welcome2KolabSystems" MEET_WEBHOOK_TOKEN=Welcome2KolabSystems MEET_SERVER_TOKEN=Welcome2KolabSystems -MEET_SERVER_URLS=https://kolab.local/meetmedia/api/ -MEET_SERVER_VERIFY_TLS=false -MEET_WEBRTC_LISTEN_IP='172.18.0.1' +MEET_TURN_SERVER='turn:127.0.0.1:3478' +MEET_WEBRTC_LISTEN_IP='127.0.0.1' +MEET_LISTENING_HOST=127.0.0.1 MEET_PUBLIC_DOMAIN=kolab.local -MEET_TURN_SERVER='turn:172.18.0.1:3478' -MEET_LISTENING_HOST=172.18.0.1 +MEET_SERVER_URLS=https://127.0.0.1/meetmedia/api/ +MEET_SERVER_VERIFY_TLS=false PGP_ENABLE=true @@ -109,7 +109,7 @@ WOAT_NS1=ns01.domain.tld WOAT_NS2=ns02.domain.tld -REDIS_HOST=redis +REDIS_HOST=127.0.0.1 REDIS_PASSWORD=null REDIS_PORT=6379 @@ -187,3 +187,14 @@ PROXY_SSL_CERTIFICATE=/etc/certs/imap.hosted.com.cert PROXY_SSL_CERTIFICATE_KEY=/etc/certs/imap.hosted.com.key + +OX_API_KEY= +FIREBASE_API_KEY= + +#Generated by php artisan passport:client --password, but can be left hardcoded (the seeder will pick it up) +PASSPORT_PROXY_OAUTH_CLIENT_ID=942edef5-3dbd-4a14-8e3e-d5d59b727bee +PASSPORT_PROXY_OAUTH_CLIENT_SECRET=L6L0n56ecvjjK0cJMjeeV1pPAeffUBO0YSSH63wf + +#Generated by php artisan passport:client --password, but can be left hardcoded (the seeder will pick it up) +PASSPORT_COMPANIONAPP_OAUTH_CLIENT_ID=9566e018-f05d-425c-9915-420cdb9258bb +PASSPORT_COMPANIONAPP_OAUTH_CLIENT_SECRET=XjgV6SU9shO0QFKaU6pQPRC5rJpyRezDJTSoGLgz diff --git a/config.localhost/src/database b/config.localhost/src/database new file mode 120000 --- /dev/null +++ b/config.localhost/src/database @@ -0,0 +1 @@ +../../config.local/src/database/ \ No newline at end of file diff --git a/docker/tests/init.sh b/docker/tests/init.sh --- a/docker/tests/init.sh +++ b/docker/tests/init.sh @@ -1,5 +1,6 @@ #!/bin/bash #set -e +rm -rf /src/kolabsrc sudo cp -a /src/kolabsrc.orig /src/kolabsrc sudo chmod 777 -R /src/kolabsrc cd /src/kolabsrc diff --git a/src/.gitignore b/src/.gitignore --- a/src/.gitignore +++ b/src/.gitignore @@ -24,4 +24,6 @@ composer.lock resources/countries.php resources/build/js/ +database/seeds/ +src/public/themes/active cache diff --git a/src/.s2i/bin/assemble b/src/.s2i/bin/assemble --- a/src/.s2i/bin/assemble +++ b/src/.s2i/bin/assemble @@ -20,13 +20,6 @@ fix-permissions ./ -if [ -f ".env.local" ]; then - # Ensure there's a line ending - echo "---->> Append .env.local" - echo "" >> .env - cat .env.local >> .env -fi - if [ -f "composer.json" ]; then echo "--->> Detected composer.json, running install" composer_install diff --git a/src/database/migrations/2021_04_08_150000_signup_code_headers.php b/src/database/migrations/2021_04_08_150000_signup_code_headers.php --- a/src/database/migrations/2021_04_08_150000_signup_code_headers.php +++ b/src/database/migrations/2021_04_08_150000_signup_code_headers.php @@ -2,7 +2,6 @@ use Illuminate\Database\Migrations\Migration; use Illuminate\Database\Schema\Blueprint; -use Illuminate\Support\Facades\DB; use Illuminate\Support\Facades\Schema; // phpcs:ignore diff --git a/src/database/migrations/2021_07_12_100000_create_tenant_settings_table.php b/src/database/migrations/2021_07_12_100000_create_tenant_settings_table.php --- a/src/database/migrations/2021_07_12_100000_create_tenant_settings_table.php +++ b/src/database/migrations/2021_07_12_100000_create_tenant_settings_table.php @@ -2,7 +2,6 @@ use Illuminate\Database\Migrations\Migration; use Illuminate\Database\Schema\Blueprint; -use Illuminate\Support\Facades\DB; use Illuminate\Support\Facades\Schema; // phpcs:ignore diff --git a/src/database/migrations/2022_05_13_100000_permissions_and_room_subscriptions.php b/src/database/migrations/2022_05_13_100000_permissions_and_room_subscriptions.php --- a/src/database/migrations/2022_05_13_100000_permissions_and_room_subscriptions.php +++ b/src/database/migrations/2022_05_13_100000_permissions_and_room_subscriptions.php @@ -38,54 +38,32 @@ ); // Create the new SKUs - if (!\App\Sku::where('title', 'room')->first()) { - $sku = \App\Sku::create([ - 'title' => 'group-room', - 'name' => 'Group conference room', - 'description' => 'Shareable audio & video conference room', - 'cost' => 0, - 'units_free' => 0, - 'period' => 'monthly', - 'handler_class' => 'App\Handlers\GroupRoom', - 'active' => true, - ]); + $sku = \App\Sku::where('title', 'room')->first(); - $sku = \App\Sku::create([ - 'title' => 'room', - 'name' => 'Standard conference room', - 'description' => 'Audio & video conference room', - 'cost' => 0, - 'units_free' => 0, - 'period' => 'monthly', - 'handler_class' => 'App\Handlers\Room', - 'active' => true, - ]); + // Create the entitlement for every existing room + foreach (\App\Meet\Room::get() as $room) { + $user = \App\User::find($room->user_id); // @phpstan-ignore-line + if (!$user) { + $room->forceDelete(); + continue; + } - // Create the entitlement for every existing room - foreach (\App\Meet\Room::get() as $room) { - $user = \App\User::find($room->user_id); // @phpstan-ignore-line - if (!$user) { - $room->forceDelete(); - continue; - } - - // Set tenant_id - if ($user->tenant_id) { - $room->tenant_id = $user->tenant_id; - $room->save(); - } - - $wallet = $user->wallets()->first(); - - \App\Entitlement::create([ - 'wallet_id' => $wallet->id, - 'sku_id' => $sku->id, - 'cost' => 0, - 'fee' => 0, - 'entitleable_id' => $room->id, - 'entitleable_type' => \App\Meet\Room::class - ]); + // Set tenant_id + if ($user->tenant_id) { + $room->tenant_id = $user->tenant_id; + $room->save(); } + + $wallet = $user->wallets()->first(); + + \App\Entitlement::create([ + 'wallet_id' => $wallet->id, + 'sku_id' => $sku->id, + 'cost' => 0, + 'fee' => 0, + 'entitleable_id' => $room->id, + 'entitleable_type' => \App\Meet\Room::class + ]); } // Remove 'meet' SKU/entitlements @@ -137,19 +115,6 @@ ); \App\Entitlement::where('entitleable_type', \App\Meet\Room::class)->forceDelete(); - \App\Sku::where('title', 'room')->delete(); - \App\Sku::where('title', 'group-room')->delete(); - - \App\Sku::create([ - 'title' => 'meet', - 'name' => 'Voice & Video Conferencing (public beta)', - 'description' => 'Video conferencing tool', - 'cost' => 0, - 'units_free' => 0, - 'period' => 'monthly', - 'handler_class' => 'App\Handlers\Meet', - 'active' => true, - ]); Schema::dropIfExists('permissions'); } diff --git a/src/database/migrations/2022_09_08_100000_plans_free_months.php b/src/database/migrations/2022_09_08_100000_plans_free_months.php --- a/src/database/migrations/2022_09_08_100000_plans_free_months.php +++ b/src/database/migrations/2022_09_08_100000_plans_free_months.php @@ -2,7 +2,6 @@ use Illuminate\Database\Migrations\Migration; use Illuminate\Database\Schema\Blueprint; -use Illuminate\Support\Facades\DB; use Illuminate\Support\Facades\Schema; return new class extends Migration @@ -20,8 +19,6 @@ $table->tinyInteger('free_months')->unsigned()->default(0); } ); - - DB::table('plans')->update(['free_months' => 1]); } /** diff --git a/src/database/seeds/DatabaseSeeder.php b/src/database/seeds/DatabaseSeeder.php deleted file mode 100644 --- a/src/database/seeds/DatabaseSeeder.php +++ /dev/null @@ -1,44 +0,0 @@ - $name) { - $class = "Database\\Seeds\\$env\\$name"; - $seeders[$idx] = class_exists($class) ? $class : null; - } - - $seeders = array_filter($seeders); - - $this->call($seeders); - } -} diff --git a/src/database/seeds/production/DiscountSeeder.php b/src/database/seeds/production/DiscountSeeder.php deleted file mode 100644 --- a/src/database/seeds/production/DiscountSeeder.php +++ /dev/null @@ -1,33 +0,0 @@ - 'Free Account', - 'discount' => 100, - 'active' => true, - ] - ); - - Discount::create( - [ - 'description' => 'Student or Educational Institution', - 'discount' => 30, - 'active' => true, - ] - ); - } -} diff --git a/src/database/seeds/production/DomainSeeder.php b/src/database/seeds/production/DomainSeeder.php deleted file mode 100644 --- a/src/database/seeds/production/DomainSeeder.php +++ /dev/null @@ -1,52 +0,0 @@ - $domain, - 'status' => Domain::STATUS_CONFIRMED + Domain::STATUS_ACTIVE, - 'type' => Domain::TYPE_PUBLIC - ] - ); - } - } -} diff --git a/src/database/seeds/production/PackageSeeder.php b/src/database/seeds/production/PackageSeeder.php deleted file mode 100644 --- a/src/database/seeds/production/PackageSeeder.php +++ /dev/null @@ -1,86 +0,0 @@ - 'activesync']); - $skuGroupware = Sku::firstOrCreate(['title' => 'groupware']); - $skuMailbox = Sku::firstOrCreate(['title' => 'mailbox']); - $skuStorage = Sku::firstOrCreate(['title' => 'storage']); - - $package = Package::create( - [ - 'title' => 'kolab', - 'name' => 'Groupware Account', - 'description' => 'A fully functional groupware account.', - 'discount_rate' => 0 - ] - ); - - $skus = [ - $skuMailbox, - $skuGroupware, - $skuStorage, - $skuActiveSync - ]; - - $package->skus()->saveMany($skus); - - // This package contains 2 units of the storage SKU, which just so happens to also - // be the number of SKU free units. - $package->skus()->updateExistingPivot( - $skuStorage, - ['qty' => 2], - false - ); - - $package = Package::create( - [ - 'title' => 'lite', - 'name' => 'Lite Account', - 'description' => 'Just mail and no more.', - 'discount_rate' => 0 - ] - ); - - $skus = [ - $skuMailbox, - $skuStorage - ]; - - $package->skus()->saveMany($skus); - - $package->skus()->updateExistingPivot( - Sku::firstOrCreate(['title' => 'storage']), - ['qty' => 2], - false - ); - - $package = Package::create( - [ - 'title' => 'domain-hosting', - 'name' => 'Domain Hosting', - 'description' => 'Use your own, existing domain.', - 'discount_rate' => 0 - ] - ); - - $skus = [ - Sku::firstOrCreate(['title' => 'domain-hosting']) - ]; - - $package->skus()->saveMany($skus); - } -} diff --git a/src/database/seeds/production/PlanSeeder.php b/src/database/seeds/production/PlanSeeder.php deleted file mode 100644 --- a/src/database/seeds/production/PlanSeeder.php +++ /dev/null @@ -1,76 +0,0 @@ -Everything you need to get started or try Kolab Now, including:

- -EOD; - - $plan = Plan::create( - [ - 'title' => 'individual', - 'name' => 'Individual Account', - 'description' => $description, - 'free_months' => 1, - 'discount_qty' => 0, - 'discount_rate' => 0 - ] - ); - - $packages = [ - Package::firstOrCreate(['title' => 'kolab']) - ]; - - $plan->packages()->saveMany($packages); - - $description = <<<'EOD' -

All the features of the Individual Account, with the following extras:

- -EOD; - - $plan = Plan::create( - [ - 'title' => 'group', - 'name' => 'Group Account', - 'description' => $description, - 'free_months' => 1, - 'discount_qty' => 0, - 'discount_rate' => 0 - ] - ); - - $packages = [ - Package::firstOrCreate(['title' => 'domain-hosting']), - Package::firstOrCreate(['title' => 'kolab']), - ]; - - $plan->packages()->saveMany($packages); - } -} diff --git a/src/database/seeds/production/SkuSeeder.php b/src/database/seeds/production/SkuSeeder.php deleted file mode 100644 --- a/src/database/seeds/production/SkuSeeder.php +++ /dev/null @@ -1,172 +0,0 @@ - 'mailbox', - 'name' => 'User Mailbox', - 'description' => 'Just a mailbox', - 'cost' => 444, - 'units_free' => 0, - 'period' => 'monthly', - 'handler_class' => 'App\Handlers\Mailbox', - 'active' => true, - ], - [ - 'title' => 'domain', - 'name' => 'Hosted Domain', - 'description' => 'Somewhere to place a mailbox', - 'cost' => 100, - 'period' => 'monthly', - 'handler_class' => 'App\Handlers\Domain', - 'active' => false, - ], - [ - 'title' => 'domain-registration', - 'name' => 'Domain Registration', - 'description' => 'Register a domain with us', - 'cost' => 101, - 'period' => 'yearly', - 'handler_class' => 'App\Handlers\DomainRegistration', - 'active' => false, - ], - [ - 'title' => 'domain-hosting', - 'name' => 'External Domain', - 'description' => 'Host a domain that is externally registered', - 'cost' => 100, - 'units_free' => 1, - 'period' => 'monthly', - 'handler_class' => 'App\Handlers\DomainHosting', - 'active' => true, - ], - [ - 'title' => 'domain-relay', - 'name' => 'Domain Relay', - 'description' => 'A domain you host at home, for which we relay email', - 'cost' => 103, - 'period' => 'monthly', - 'handler_class' => 'App\Handlers\DomainRelay', - 'active' => false, - ], - [ - 'title' => 'storage', - 'name' => 'Storage Quota', - 'description' => 'Some wiggle room', - 'cost' => 50, - 'units_free' => 2, - 'period' => 'monthly', - 'handler_class' => 'App\Handlers\Storage', - 'active' => true, - ], - [ - 'title' => 'groupware', - 'name' => 'Groupware Features', - 'description' => 'Groupware functions like Calendar, Tasks, Notes, etc.', - 'cost' => 555, - 'units_free' => 0, - 'period' => 'monthly', - 'handler_class' => 'App\Handlers\Groupware', - 'active' => true, - ], - [ - 'title' => 'resource', - 'name' => 'Resource', - 'description' => 'Reservation taker', - 'cost' => 0, - 'period' => 'monthly', - 'handler_class' => 'App\Handlers\Resource', - 'active' => true, - ], - [ - 'title' => 'shared-folder', - 'name' => 'Shared Folder', - 'description' => 'A shared folder', - 'cost' => 89, - 'period' => 'monthly', - 'handler_class' => 'App\Handlers\SharedFolder', - 'active' => false, - ], - [ - 'title' => '2fa', - 'name' => '2-Factor Authentication', - 'description' => 'Two factor authentication for webmail and administration panel', - 'cost' => 0, - 'units_free' => 0, - 'period' => 'monthly', - 'handler_class' => 'App\Handlers\Auth2F', - 'active' => true, - ], - [ - 'title' => 'activesync', - 'name' => 'Activesync', - 'description' => 'Mobile synchronization', - 'cost' => 100, - 'units_free' => 0, - 'period' => 'monthly', - 'handler_class' => 'App\Handlers\Activesync', - 'active' => true, - ], - [ - 'title' => 'beta', - 'name' => 'Private Beta (invitation only)', - 'description' => 'Access to the private beta program subscriptions', - 'cost' => 0, - 'units_free' => 0, - 'period' => 'monthly', - 'handler_class' => 'App\Handlers\Beta', - 'active' => false, - ], - [ - 'title' => 'group', - 'name' => 'Distribution list', - 'description' => 'Mail distribution list', - 'cost' => 0, - 'units_free' => 0, - 'period' => 'monthly', - 'handler_class' => 'App\Handlers\Group', - 'active' => true, - ], - [ - 'title' => 'group-room', - 'name' => 'Group conference room', - 'description' => 'Shareable audio & video conference room', - 'cost' => 0, - 'units_free' => 0, - 'period' => 'monthly', - 'handler_class' => 'App\Handlers\GroupRoom', - 'active' => true, - ], - [ - 'title' => 'room', - 'name' => 'Standard conference room', - 'description' => 'Audio & video conference room', - 'cost' => 0, - 'units_free' => 0, - 'period' => 'monthly', - 'handler_class' => 'App\Handlers\Room', - 'active' => true, - ], - ]; - - foreach ($skus as $sku) { - // Check existence because migration might have added this already - if (!Sku::where('title', $sku['title'])->first()) { - Sku::create($sku); - } - } - } -}