diff --git a/.github/update-composer-json.php b/.github/update-composer-json.php
new file mode 100644
index 000000000..2144c54fb
--- /dev/null
+++ b/.github/update-composer-json.php
@@ -0,0 +1,137 @@
+ 'package', // The type is at the root level of the repository entry
+ 'package' => [
+ 'name' => $packageName,
+ 'version' => $packageVersionRange,
+ 'type' => 'library', // Default type, you can adjust this if needed
+ 'dist' => [
+ 'url' => $repositoryUrl,
+ 'type' => $distType, // Use the dynamically derived dist type
+ 'reference' => $packageHash // Adding the hash (reference) if available
+ ]
+ ]
+ ];
+ // Track pinned package
+ $pinnedPackages[] = $packageName;
+ }
+}
+
+// Write the updated composer.json back to the file
+if (file_put_contents($composerJsonPath, json_encode($composerJson, JSON_PRETTY_PRINT | JSON_UNESCAPED_SLASHES) . PHP_EOL)) {
+ echo "composer.json has been updated with the versions from composer.lock.\n";
+ if (count($pinnedPackages) > 0) {
+ echo "The following packages were pinned to repositories:\n";
+ foreach ($pinnedPackages as $packageName) {
+ echo " - $packageName\n";
+ }
+ }
+} else {
+ echo "Failed to update composer.json.\n";
+ exit(1);
+}
diff --git a/.github/workflows/auto-assign-pr.yml b/.github/workflows/auto-assign-pr.yml
new file mode 100644
index 000000000..fecb812bc
--- /dev/null
+++ b/.github/workflows/auto-assign-pr.yml
@@ -0,0 +1,24 @@
+name: Auto-Assign PR
+
+on:
+ pull_request_target:
+ types: [opened]
+
+permissions:
+ issues: write
+
+jobs:
+ assign:
+ runs-on: ubuntu-latest
+ steps:
+ - name: Assign PR to repo owner
+ uses: actions/github-script@v8
+ with:
+ github-token: ${{ secrets.GH_ADMIN_TOKEN }}
+ script: |
+ await github.rest.issues.addAssignees({
+ owner: context.repo.owner,
+ repo: context.repo.repo,
+ issue_number: context.issue.number,
+ assignees: ["proditis"]
+ });
diff --git a/.markdownlint.yaml b/.markdownlint.yaml
index 7ace1f4be..6a7d02cde 100644
--- a/.markdownlint.yaml
+++ b/.markdownlint.yaml
@@ -3,4 +3,6 @@ MD012: false
MD013: false
# Disable required empty line after heading
MD022: false
-MD033: false
\ No newline at end of file
+MD033: false
+MD040: false
+MD043: false
\ No newline at end of file
diff --git a/ansible/Dockerfiles/sanitycheck/variables.yml b/ansible/Dockerfiles/sanitycheck/variables.yml
index 9766edd51..1762de0cb 100644
--- a/ansible/Dockerfiles/sanitycheck/variables.yml
+++ b/ansible/Dockerfiles/sanitycheck/variables.yml
@@ -12,6 +12,7 @@ writeup_allowed: 0
headshot_spin: 0
instance_allowed: 0
TargetOndemand: false
+dynamic_treasures: 0
container:
name: "{{hostname}}"
hostname: "{{fqdn}}"
diff --git a/ansible/files/login.conf.d/memcached b/ansible/files/login.conf.d/memcached
new file mode 100644
index 000000000..6c6704d35
--- /dev/null
+++ b/ansible/files/login.conf.d/memcached
@@ -0,0 +1,5 @@
+memcached:\
+ :datasize=2048M:\
+ :openfiles-cur=6144:\
+ :openfiles-max=20480:\
+ :tc=daemon:
diff --git a/ansible/files/login.conf.d/mysqld b/ansible/files/login.conf.d/mysqld
new file mode 100644
index 000000000..ec90ada63
--- /dev/null
+++ b/ansible/files/login.conf.d/mysqld
@@ -0,0 +1,5 @@
+mysqld:\
+ :datasize=8192M:\
+ :openfiles-cur=6144:\
+ :openfiles-max=20480:\
+ :tc=daemon:
diff --git a/ansible/files/login.conf.d/supervisord b/ansible/files/login.conf.d/supervisord
new file mode 100644
index 000000000..a91739203
--- /dev/null
+++ b/ansible/files/login.conf.d/supervisord
@@ -0,0 +1,8 @@
+supervisord:\
+ :ignorenologin:\
+ :datasize=4096M:\
+ :maxproc=infinity:\
+ :openfiles-max=10024:\
+ :openfiles-cur=2560:\
+ :stacksize-cur=18M:\
+ :tc=default:
diff --git a/ansible/files/login.conf.d/watchdoger b/ansible/files/login.conf.d/watchdoger
new file mode 100644
index 000000000..23fab3b31
--- /dev/null
+++ b/ansible/files/login.conf.d/watchdoger
@@ -0,0 +1,8 @@
+watchdoger:\
+ :ignorenologin:\
+ :datasize=512M:\
+ :maxproc=infinity:\
+ :openfiles-max=4096:\
+ :openfiles-cur=1024:\
+ :stacksize-cur=8M:\
+ :tc=default:
diff --git a/ansible/files/pui.service.conf b/ansible/files/pui.service.conf
index fb1fa8ea0..9dd62ce24 100644
--- a/ansible/files/pui.service.conf
+++ b/ansible/files/pui.service.conf
@@ -1,6 +1,8 @@
# Allow users to connect to port 80/443
pass in quick on egress inet proto tcp from {, } to (egress:0) port 8888 rdr-to 127.0.0.1
+pass in quick on interconnect inet proto tcp from (interconnect:network) to (interconnect:0) port 8888 rdr-to 127.0.0.1
+
pass quick from label "administrators"
pass quick inet proto tcp from to (egress:0) port { 80 , 443 } label "www-moderators"
@@ -8,9 +10,7 @@ pass quick inet proto tcp from to (egress:0) port { 80 , 443 } labe
# FOR DT OPERATIONS
pass in quick inet proto tcp from to port 80 rdr-to 127.0.0.1 port 8080 label "maintenance"
pass in quick inet proto tcp from to port 443 rdr-to 127.0.0.1 port 8443 label "maintenance"
-block in quick on egress inet proto tcp from to (egress:0) port 8888
pass in on egress inet proto tcp from to port { 80, 443 } label "www-normal"
pass in on egress inet proto tcp to port { 80, 443 } label "www-normal"
-pass in quick on egress inet proto tcp to (egress:0) port 8888 rdr-to 127.0.0.1
diff --git a/ansible/inventories/servers/host_vars/registry.yml b/ansible/inventories/servers/host_vars/registry.yml
index 87ad4d3cc..37fa85f1e 100644
--- a/ansible/inventories/servers/host_vars/registry.yml
+++ b/ansible/inventories/servers/host_vars/registry.yml
@@ -5,7 +5,7 @@ registry_storage: "/storage"
registry_bind_ip: "0.0.0.0"
registry_bind_port: "5000"
registry_targets_if: if0
-registry_targets_cidr: 10.0.100.0/24
+registry_targets_cidr: 10.0.0.100/24
backups:
- { tgz: "/altroot/root.tgz", src: '/root' }
- { tgz: "/altroot/etc.tgz", src: '/etc' }
diff --git a/ansible/maintenance/authorized_keys.yml b/ansible/maintenance/authorized_keys.yml
new file mode 100644
index 000000000..cda89202b
--- /dev/null
+++ b/ansible/maintenance/authorized_keys.yml
@@ -0,0 +1,33 @@
+---
+- name: Update authorized SSH keys for a user
+ hosts: all
+ become: true
+
+ vars:
+ target_user: root
+
+ pre_tasks:
+ - name: Ensure ssh_keys_source is provided
+ ansible.builtin.fail:
+ msg: "You must provide ssh_keys_source (file path or URL)"
+ when: ssh_keys_source is not defined
+
+ - name: Load SSH public keys from file or URL
+ ansible.builtin.set_fact:
+ ssh_public_keys: >-
+ {{
+ lookup(
+ ssh_keys_source is match('^https?://')
+ | ternary('url', 'file'),
+ ssh_keys_source
+ )
+ }}
+
+ tasks:
+ - name: Update authorized_keys for user
+ ansible.posix.authorized_key:
+ user: "{{ target_user }}"
+ key: "{{ ssh_public_keys }}"
+ manage_dir: true
+ state: present
+ # exclusive: true # uncomment to replace all existing keys
diff --git a/ansible/maintenance/sync-github.yml b/ansible/maintenance/sync-github.yml
new file mode 100644
index 000000000..e413658f2
--- /dev/null
+++ b/ansible/maintenance/sync-github.yml
@@ -0,0 +1,32 @@
+#!/usr/bin/env ansible-playbook
+---
+- name: Update deployed application from Git
+ hosts: all
+ tasks:
+ - name: Ensure repository is up to date
+ git:
+ repo: "{{ GITHUB_REPO }}"
+ dest: "{{ REPO }}"
+ version: "{{ GITHUB_REPO_BRANCH }}"
+ force: yes
+ accept_hostkey: yes
+ update: yes
+ notify: restart applications
+ register: git_result
+
+ - name: Clean untracked files (preserving paths)
+ shell: git clean -fd {{ '-n' if ansible_check_mode else '' }} {% for p in PRESERVE_PATHS %}-e {{ p }} {% endfor %}
+ args:
+ chdir: "{{ REPO }}"
+ register: clean_result
+ changed_when: clean_result.stdout != ""
+ when: git_result.changed and PRESERVE_PATHS is defined
+ notify: restart applications
+
+ handlers:
+ - name: restart applications
+ when: APP_SERVICES is defined
+ service:
+ name: "{{ item }}"
+ state: restarted
+ loop: "{{ APP_SERVICES }}"
diff --git a/ansible/runonce/db.yml b/ansible/runonce/db.yml
index 3409ab90d..2e087e5d2 100755
--- a/ansible/runonce/db.yml
+++ b/ansible/runonce/db.yml
@@ -411,6 +411,27 @@
group: wheel
mode: '0555'
+ - name: copy watchdoger script
+ copy:
+ src: ../../contrib/watchdoger.py
+ dest: /usr/local/bin/watchdoger
+ owner: root
+ group: wheel
+ mode: '0555'
+
+ - name: Install watchdoger.ini for supervisord
+ copy:
+ dest: /etc/supervisord.d/watchdoger.ini
+ content: |
+ [program:watchdoger]
+ user = root
+ command = su -fm -c watchdoger -s /usr/local/bin/python3 root /usr/local/bin/watchdoger --file_path /tmp/event_finished --url {{ wsserver.url | default("http://10.7.0.200:8888/broadcast") }} --token {{ wsserver.token | default("server123token") }}
+ autorestart = false
+ startretries = 0
+ stdout_logfile=/var/log/watchdoger.log
+ stdout_logfile_maxbytes=0
+ redirect_stderr=true
+
- name: Setting up sysctl.conf
sysctl:
name: "{{ item.key }}"
@@ -473,6 +494,16 @@
- { name: "events checker", minute: "*/1", job: "-ns /usr/local/sbin/mysql-events-checker" }
- { name: "daily database backups", minute: "0",hour: "23", job: "-ns /usr/local/sbin/database_backup" }
+ - name: copy login.conf.d login classes
+ copy:
+ src: "../files/login.conf.d/{{item}}"
+ dest: "/etc/login.conf.d/{{item}}"
+ with_items:
+ - memcached
+ - mysqld
+ - supervisord
+ - watchdoger
+
- name: Execute fw_update
command: fw_update -a
diff --git a/ansible/runonce/docker-registry.yml b/ansible/runonce/docker-registry.yml
index 547330003..49b150e46 100755
--- a/ansible/runonce/docker-registry.yml
+++ b/ansible/runonce/docker-registry.yml
@@ -137,7 +137,7 @@
content: "{{item.content|default(omit)}}"
with_items:
- { dest: "/etc/pf.conf", src: "../files/pf.conf"}
- - { dest: "/etc/service.pf.conf", content: "anchor \"dynamic\"\npass quick inet proto tcp from to port {{registry_bind_port}} label \"service_clients\"\n"}
+ - { dest: "/etc/service.pf.conf", content: "pass quick from label \"administrators\"\nanchor \"dynamic\"\npass quick inet proto tcp from to port {{registry_bind_port}} label \"service_clients\"\n"}
- { dest: "/etc/service_clients.conf", content: "{{registry_targets_cidr}}\n"}
- name: Dump administrators PF table (if exists)
diff --git a/ansible/runonce/docker-servers.yml b/ansible/runonce/docker-servers.yml
index af2024e10..1b9d3e404 100755
--- a/ansible/runonce/docker-servers.yml
+++ b/ansible/runonce/docker-servers.yml
@@ -1,40 +1,17 @@
#!/usr/bin/env ansible-playbook
---
-- name: Configure docker servers for echoCTF
+- name: Bootstrap docker servers for echoCTF
hosts: all
gather_facts: true
become: true
become_method: su
+ remote_user: sysadmin
tasks:
+
- name: Set timezone to UTC
timezone:
name: UTC
- - name: Kill any running pm2
- shell: pm2 kill
- no_log: true
- ignore_errors: true
-
- - name: Ensure docker services are stopped
- command: service docker stop
- no_log: true
- ignore_errors: true
-
- - name: Ensure existing docker service overrides are removed
- ansible.builtin.file:
- path: "{{item}}"
- state: absent
- with_items:
- - /etc/systemd/system/docker.service.d/dockerd-service-override.conf
- - /etc/systemd/system/docker.service.d/override.conf
- - /etc/systemd/system/pm2-root.service.d/pm2-root-service-override.conf
- - /etc/systemd/system/pm2-root.service.d/override.conf
-
- - name: Remove any existing /etc/docker/daemon.json
- ansible.builtin.file:
- path: /etc/docker/daemon.json
- state: absent
-
- name: Set hostname based on host_var
hostname:
name: "{{fqdn}}"
@@ -61,29 +38,6 @@
pkg: "{{pre_apt}}"
when: pre_apt is defined and pre_apt|length > 0
- - name: Add apt keys
- when: aptKeys is defined
- apt_key:
- url: "{{item.key}}"
- state: "{{item.state}}"
- with_items: "{{aptKeys}}"
-
- - name: Add apt repositories
- when: aptRepos is defined
- apt_repository:
- repo: "{{item.repo}}"
- state: "{{item.state}}"
- with_items: "{{aptRepos}}"
-
- - name: Update package cache
- apt:
- update_cache: yes
-
- - name: Update all packages to the latest version
- no_log: "{{DEBUG|default(true)}}"
- apt:
- upgrade: dist
-
- name: Adding defined users (optional)
when: users is defined
user:
@@ -109,16 +63,73 @@
key: "https://github.com/{{item}}.keys"
with_items: "{{sshkeys}}"
- - name: Make sure sysadmin has sudo access
- lineinfile:
- path: /etc/sudoers.d/90_sysadmin
- line: 'sysadmin ALL=(ALL) NOPASSWD:ALL'
- create: yes
-
- name: Ensure /home/sysadmin is owned by sysadmin user (recursive)
shell: chown -R sysadmin /home/sysadmin
when: users is defined
+ - name: Allow user to have passwordless sudo
+ copy:
+ dest: "/etc/sudoers.d/90_sysadmin"
+ content: "sysadmin ALL=(ALL) NOPASSWD:ALL\n"
+ owner: root
+ group: root
+ mode: '0440'
+
+- name: Configure docker servers for echoCTF
+ hosts: all
+ gather_facts: true
+ become: false
+ remote_user: root
+ tasks:
+
+ - name: Kill any running pm2
+ shell: pm2 kill
+ no_log: true
+ ignore_errors: true
+
+ - name: Ensure docker services are stopped
+ command: service docker stop
+ no_log: true
+ ignore_errors: true
+
+ - name: Ensure existing docker service overrides are removed
+ ansible.builtin.file:
+ path: "{{item}}"
+ state: absent
+ with_items:
+ - /etc/systemd/system/docker.service.d/dockerd-service-override.conf
+ - /etc/systemd/system/docker.service.d/override.conf
+ - /etc/systemd/system/pm2-root.service.d/pm2-root-service-override.conf
+ - /etc/systemd/system/pm2-root.service.d/override.conf
+
+ - name: Remove any existing /etc/docker/daemon.json
+ ansible.builtin.file:
+ path: /etc/docker/daemon.json
+ state: absent
+
+ - name: Add apt keys
+ when: aptKeys is defined
+ apt_key:
+ url: "{{item.key}}"
+ state: "{{item.state}}"
+ with_items: "{{aptKeys}}"
+
+ - name: Add apt repositories
+ when: aptRepos is defined
+ apt_repository:
+ repo: "{{item.repo}}"
+ state: "{{item.state}}"
+ with_items: "{{aptRepos}}"
+
+ - name: Update package cache
+ apt:
+ update_cache: yes
+
+ - name: Update all packages to the latest version
+ no_log: "{{DEBUG|default(true)}}"
+ apt:
+ upgrade: dist
+
- name: Install post install packages
apt:
state: latest
diff --git a/ansible/runonce/mui.yml b/ansible/runonce/mui.yml
index b3c247965..4f27b56e5 100755
--- a/ansible/runonce/mui.yml
+++ b/ansible/runonce/mui.yml
@@ -272,7 +272,7 @@
dest: "{{item.dest}}"
with_items:
- { src: '{{playbook_dir}}/../templates/httpd.conf.j2', dest: '/etc/httpd.conf', domain: '{{hostname}}' }
- - { src: '{{playbook_dir}}/../templates/acme-client.conf.j2', dest: '/etc/acme-client.conf', domain: '{{hostname}}', challenge_dir: "/home/moderatortUI/acme/.well-known/acme-challenge/" }
+ - { src: '{{playbook_dir}}/../templates/acme-client.conf.j2', dest: '/etc/acme-client.conf', domain: '{{hostname}}', challenge_dir: "/home/moderatorUI/acme/.well-known/acme-challenge/" }
- name: Generate pf tables files
command: "{{item.cmd}}"
@@ -425,8 +425,8 @@
- name: configure folders and perms
command: "{{item}}"
with_items:
- - "mkdir -p /home/moderatorUI/{{domain_name}}/backend/web/assets"
- - "chown -R moderatorUI /home/moderatorUI/{{domain_name}}/backend/web/assets"
+ - "install -d -o moderatorUI /home/moderatorUI/{{domain_name}}/backend/web/assets"
+ - "install -d -o moderatorUI /home/moderatorUI/{{domain_name}}/backend/web/identifcationFiles"
- "mkdir -p /var/log/cron"
- "ln -sf /home/moderatorUI/{{domain_name}}/backend/yii /usr/local/bin/backend"
diff --git a/ansible/runonce/pui.yml b/ansible/runonce/pui.yml
index 9a1ed2bf4..cb439619a 100755
--- a/ansible/runonce/pui.yml
+++ b/ansible/runonce/pui.yml
@@ -270,6 +270,7 @@
- { src: '{{playbook_dir}}/../files/pui.service.conf', dest: '/etc/service.pf.conf' }
- { src: '{{playbook_dir}}/../../contrib/unbound.conf', dest: '/var/unbound/etc/unbound.conf' }
- { src: '{{playbook_dir}}/../../contrib/downtime.html', dest: '/home/participantUI/htdocs/index.html' }
+ - { src: '{{playbook_dir}}/../../contrib/downtime.html', dest: '/home/participantUI/{{domain_name}}/frontend/web/dt.html' }
- name: "Process templates"
template:
@@ -417,7 +418,7 @@
src: ../templates/dt.conf.j2
dest: /etc/nginx/dt.conf
with_items:
- - { user: 'www', domain: '{{domain_name}}', root: "/htdocs" }
+ - { user: 'participantUI', domain: '{{domain_name}}', root: "/htdocs" }
tags:
- nginx
@@ -460,12 +461,13 @@
- { section: PHP, option: "expose_php", value: "Off" }
- { section: PHP, option: "log_errors_max_len", value: 4096 }
- { section: PHP, option: "html_errors", value: "Off" }
- - { section: PHP, option: "max_execution_time", value: "60" }
+ - { section: PHP, option: "max_execution_time", value: "180" }
- { section: PHP, option: "max_input_time", value: "120" }
- { section: PHP, option: "memory_limit", value: "256M" }
- { section: PHP, option: "error_reporting", value: "E_NONE" }
- { section: PHP, option: "post_max_size", value: "180M" }
- { section: PHP, option: "upload_max_filesize", value: "120M" }
+ - { section: PHP, option: "allow_url_fopen", value: "On"}
- { section: Session, option: "session.save_handler", value: "memcached"}
- { section: Session, option: "session.save_path", value: "{{db_ip}}:11211"}
- { section: Session, option: "session.gc_maxlifetime", value: "43200" }
@@ -487,13 +489,10 @@
- name: configure folders and permissions
command: "{{item}}"
with_items:
- - mkdir -p /home/participantUI/{{domain_name}}/frontend/web/assets
- - mkdir -p /home/participantUI/{{domain_name}}/frontend/web/identificationFiles
- - mkdir -p /home/participantUI/{{domain_name}}/frontend/web/images/avatars/team
+ - install -d -o participantUI /home/participantUI/{{domain_name}}/frontend/web/assets
+ - install -d -o participantUI /home/participantUI/{{domain_name}}/frontend/web/identificationFiles
+ - install -d -o participantUI /home/participantUI/{{domain_name}}/frontend/web/images/avatars/team
- mkdir -p /var/log/cron
- - chown -R participantUI /home/participantUI/{{domain_name}}/frontend/web/assets
- - chown -R participantUI /home/participantUI/{{domain_name}}/frontend/web/images/avatars/
- - chown -R participantUI /home/participantUI/{{domain_name}}/frontend/web/identificationFiles
- ln -sf /home/participantUI/{{domain_name}}/frontend/yii /usr/local/bin/frontend
- name: configure participant rc.d
@@ -635,10 +634,12 @@
redirect_stderr=true
- name: "Update frontend/config/params.php"
- replace:
- path: "/home/participantUI/{{domain_name}}/frontend/config/params.php"
- regexp: 'ws://localhost:8888/ws'
- replace: 'wss://{{domain_name}}/ws'
+ ansible.builtin.lineinfile:
+ path: "/home/participantUI/{{ domain_name }}/frontend/config/params.php"
+ search_string: 'ws://localhost:8888/ws'
+ line: 'wss://{{ domain_name }}/ws'
+ insertafter: null
+ insertbefore: null
- name: copy nstables script
copy:
diff --git a/ansible/runonce/vpngw.yml b/ansible/runonce/vpngw.yml
index 495bcef33..d2c3902ac 100755
--- a/ansible/runonce/vpngw.yml
+++ b/ansible/runonce/vpngw.yml
@@ -252,6 +252,19 @@
- name: Activate install php modules
shell: "cp /etc/php-{{versions.PHP}}.sample/*.ini /etc/php-{{versions.PHP}}/"
+ - name: Fixing /etc/php.ini
+ ini_file: dest=/etc/php-{{versions.PHP}}.ini section={{item.section}} option={{item.option}} value={{item.value}} mode=0644 owner=root group=wheel
+ with_items:
+ - { section: PHP, option: "expose_php", value: "Off" }
+ - { section: PHP, option: "log_errors_max_len", value: 4096 }
+ - { section: PHP, option: "html_errors", value: "Off" }
+ - { section: PHP, option: "max_execution_time", value: "60" }
+ - { section: PHP, option: "max_input_time", value: "120" }
+ - { section: PHP, option: "memory_limit", value: "256M" }
+ - { section: PHP, option: "error_reporting", value: "E_NONE" }
+ - { section: PHP, option: "post_max_size", value: "180M" }
+ - { section: PHP, option: "upload_max_filesize", value: "120M" }
+ - { section: PHP, option: "allow_url_fopen", value: "On"}
- name: Update my.cnf
ini_file:
@@ -686,6 +699,28 @@
stdout_logfile_maxbytes=0
redirect_stderr=true
+ - name: copy watchdog-action script
+ copy:
+ src: ../../contrib/watchdog-action.py
+ dest: /usr/local/bin/watchdog-action
+ owner: root
+ group: wheel
+ mode: '0555'
+
+ - name: copy event_shutdown script
+ copy:
+ src: ../../contrib/event_shutdown.sh
+ dest: /usr/local/sbin/event_shutdown
+ owner: root
+ group: wheel
+ mode: '0555'
+
+ - name: Add watchdog-action to rc.local
+ lineinfile:
+ path: "/etc/rc.local"
+ line: "nohup /usr/local/bin/watchdog-action --file_path /tmp/event_finished --action /usr/local/sbin/event_shutdown >/tmp/watchdog.log 2>&1 &"
+ insertafter: EOF
+
- name: create user for openvpn up/down scripts
mysql_user:
name: "openvpn"
diff --git a/ansible/templates/dt.conf.j2 b/ansible/templates/dt.conf.j2
index 17f7650b4..5a3699bdc 100644
--- a/ansible/templates/dt.conf.j2
+++ b/ansible/templates/dt.conf.j2
@@ -43,7 +43,15 @@ http {
ssl_prefer_server_ciphers on;
ssl_dhparam /etc/ssl/private/dhparam.pem;
- return 503;
+ # ACME challenge must bypass maintenance
+ location ^~ /.well-known/acme-challenge/ {
+ root /acme;
+ try_files $uri =404;
+ }
+
+ location / {
+ return 503;
+ }
error_page 503 @maintenance;
location @maintenance {
add_header Strict-Transport-Security "max-age=63072000; includeSubDomains";
diff --git a/ansible/templates/nginx.conf.j2 b/ansible/templates/nginx.conf.j2
index f2584dcc6..5bd6c159c 100644
--- a/ansible/templates/nginx.conf.j2
+++ b/ansible/templates/nginx.conf.j2
@@ -22,6 +22,8 @@ http {
fastcgi_temp_path /cache/fastcgi_temp 1 2;
proxy_temp_path /cache/proxy_temp 1 2;
+ client_max_body_size 32M;
+
limit_req_zone $binary_remote_addr zone=Api:1m rate=10r/s;
limit_req_zone $binary_remote_addr zone=ResendVerificationEmail:1m rate=10r/s;
limit_req_zone $binary_remote_addr zone=RequestPasswordReset:1m rate=10r/s;
@@ -35,6 +37,8 @@ http {
#tcp_nopush on;
keepalive_timeout 65;
+ fastcgi_send_timeout 180s;
+ fastcgi_read_timeout 180s;
gzip on;
gzip_static on;
gzip_proxied expired no-cache no-store private auth;
@@ -206,27 +210,13 @@ http {
}
# disable direct access to dt.html
- location = /dt.html {
- return 404;
- }
- location = /429.html {
- return 404;
- }
- location = /500.html {
- return 404;
- }
- location = /501.html {
- return 404;
- }
- location = /504.html {
- return 404;
- }
- location = /505.html {
- return 404;
- }
- location ~ /\.ht {
- return 404;
- }
+ location = /dt.html { return 404; }
+ location = /429.html { return 404; }
+ location = /500.html { return 404; }
+ location = /501.html { return 404; }
+ location = /504.html { return 404; }
+ location = /505.html { return 404; }
+ location ~ /\.ht { return 404; }
location /contrib/ {
autoindex on;
@@ -252,6 +242,15 @@ http {
set $yii_bootstrap "/index.php";
{% if "mui" not in inventory_hostname %}
+ {% if mui_ext_ip is defined %}
+ location ^~ /identificationFiles/ {
+ allow {{ mui_ext_ip }};
+ deny all;
+
+ try_files $uri $uri/ =404;
+ }
+ {% endif %}
+ {% if enable_rate_limit is defined %}
# Rate limit /api to 10 requests/sec
# This is way too loose
location /api {
@@ -325,6 +324,7 @@ http {
index index.php;
try_files $uri $uri/ /index.php$is_args$args;
}
+ {% endif %}
{% endif %}
location / {
index index.html index.php;
@@ -336,18 +336,18 @@ http {
return 404;
}
{% endif %}
- location /ws {
- proxy_pass http://127.0.0.1:8888/ws;
-
- # WebSocket-specific headers
- proxy_http_version 1.1;
- proxy_set_header Upgrade $http_upgrade;
- proxy_set_header Connection "Upgrade";
-
- # Optional: increase timeout for long-lived connections
- proxy_read_timeout 86400s;
- proxy_send_timeout 86400s;
- }
+ location /ws {
+ proxy_pass http://127.0.0.1:8888/ws;
+
+ # WebSocket-specific headers
+ proxy_http_version 1.1;
+ proxy_set_header Upgrade $http_upgrade;
+ proxy_set_header Connection "Upgrade";
+
+ # Optional: increase timeout for long-lived connections
+ proxy_read_timeout 86400s;
+ proxy_send_timeout 86400s;
+ }
{% if captcha is defined %}
# Check for requests to /profile/
location ~ ^/profile/\d+$ {
@@ -372,10 +372,10 @@ http {
# let yii catch the calls to non-existing PHP files
set $fsn /$yii_bootstrap;
set $yiiargs r=$request_uri;
- if (-f $document_root$fastcgi_script_name){
- set $fsn $fastcgi_script_name;
+ #if (-f $document_root$fastcgi_script_name){
+ # set $fsn $fastcgi_script_name;
set $yiiargs $query_string;
- }
+ #}
fastcgi_pass {{item.fpm}};
include fastcgi_params;
@@ -399,10 +399,10 @@ http {
# let yii catch the calls to non-existing PHP files
set $fsn /$yii_bootstrap;
set $yiiargs r=$request_uri;
- if (-f $document_root$fastcgi_script_name){
- set $fsn $fastcgi_script_name;
- set $yiiargs $query_string;
- }
+ #if (-f $document_root$fastcgi_script_name){
+ # set $fsn $fastcgi_script_name;
+ # set $yiiargs $query_string;
+ #}
fastcgi_pass {{item.fpm}};
include fastcgi_params;
diff --git a/backend/commands/CronController.php b/backend/commands/CronController.php
index ec16a5bc0..dda45d3bf 100644
--- a/backend/commands/CronController.php
+++ b/backend/commands/CronController.php
@@ -15,6 +15,7 @@
use app\modules\infrastructure\models\TargetInstanceAudit;
use app\modules\infrastructure\models\NetworkTargetSchedule as NTS;
use app\modules\gameplay\models\NetworkTarget;
+use app\components\helpers\ArrayHelperExtended;
/**
* @method docker_connect()
@@ -159,11 +160,7 @@ public function actionInstancePf($before = 60)
case SELF::ACTION_START:
case SELF::ACTION_RESTART:
if (($val->team_allowed === true || \Yii::$app->sys->team_visible_instances === true) && $val->player->teamPlayer !== null && $val->player->teamPlayer->approved === 1) {
- foreach ($val->player->teamPlayer->team->approvedMembers as $teamPlayer) {
- if ((int)$teamPlayer->player->last->vpn_local_address !== 0) {
- $ips[] = long2ip($teamPlayer->player->last->vpn_local_address);
- }
- }
+ $ips = $val->player->teamPlayer->team->approvedMemberIPs;
} else if ((int)$val->player->last->vpn_local_address !== 0) {
$ips[] = long2ip($val->player->last->vpn_local_address);
}
@@ -200,15 +197,9 @@ public function actionInstancePfTables($dopf = false)
}
$team_visible_instances = \Yii::$app->sys->team_visible_instances;
if ($val->team_allowed == true || $team_visible_instances === true) {
- // get team members
if ($val->player->teamPlayer) {
$team = $val->player->teamPlayer->team;
- foreach ($team->approvedMembers as $member) {
- // get IP's of connected players
- if (($pIP = $member->player->last->vpn_local_address) !== null) {
- $IPs[] = long2ip($pIP);
- }
- }
+ $IPs = ArrayHelperExtended::mergeUnique($IPs, $team->approvedMemberIPs);
}
}
@@ -224,8 +215,16 @@ public function actionInstancePfTables($dopf = false)
/**
* Process player private instances
+ *
+ * This command updates the last updated_at field for active instances
+ * and processes instances that are pending action (eg. reboot, destroy, powerup)
+ * and updates the PF according to currently online players.
+ *
+ * @param bool $pfonly Perform PF operations and skip instance docker actions (default: false)
+ * @param int $expired_ago Filter instances based that haven't been updated X seconds ago (default: 2400 seconds = 40 minutes)
+ * @return int Exit code
*/
- public function actionInstances($pfonly = false)
+ public function actionInstances(bool $pfonly = false, int $expired_ago = 2400)
{
if (file_exists("/tmp/cron-instances.lock")) {
echo date("Y-m-d H:i:s ") . "Instances: /tmp/cron-instances.lock exists, skipping execution\n";
@@ -233,21 +232,13 @@ public function actionInstances($pfonly = false)
}
touch("/tmp/cron-instances.lock");
$action = SELF::ACTION_EXPIRED;
- // Get powered instances
- $t = TargetInstance::find()->active();
- foreach ($t->all() as $instance) {
- if ($instance->player->last->vpn_local_address !== null && $pfonly === false) {
- printf("Updating heartbeat [%d: %s for %d: %s]\n", $instance->target_id, $instance->target->name, $instance->player_id, $instance->player->username);
- $instance->touch('updated_at');
- }
- }
-
- $t = TargetInstance::find()->pending_action(40);
+ $t = TargetInstance::find()->pending_action($expired_ago);
foreach ($t->all() as $val) {
try {
$ips = [];
$dc = new DockerContainer($val->target);
- $dc->timeout = ($val->server->timeout ? $val->server->timeout : 2000);
+ $dc->timeout = ($val->server->timeout ? $val->server->timeout : 10000);
+
if ($val->target->targetVolumes !== null)
$dc->targetVolumes = $val->target->targetVolumes;
@@ -279,17 +270,18 @@ public function actionInstances($pfonly = false)
$dc->server = $val->server->connstr;
$dc->net = $val->server->network;
- if ($val->ip == null) {
- echo date("Y-m-d H:i:s ") . "Starting";
- $action = SELF::ACTION_START;
+ if ($val->reboot === 2) {
+ echo date("Y-m-d H:i:s ") . "Destroying";
+ $action = SELF::ACTION_DESTROY;
} else if ($val->reboot === 1) {
echo date("Y-m-d H:i:s ") . "Restarting";
$action = SELF::ACTION_RESTART;
- } else if ($val->reboot === 2) {
- echo date("Y-m-d H:i:s ") . "Destroying";
- $action = SELF::ACTION_DESTROY;
+ } else if ($val->ip == null && $val->reboot == 0) {
+ echo date("Y-m-d H:i:s ") . "Starting";
+ $action = SELF::ACTION_START;
} else {
echo date("Y-m-d H:i:s ") . "Expiring";
+ $action = SELF::ACTION_EXPIRED;
}
printf(" %s for %s (%s) at %s\n", $val->target->name, $val->player->username, $dc->name, $val->server->name);
switch ($action) {
@@ -298,17 +290,14 @@ public function actionInstances($pfonly = false)
if ($pfonly === false) {
try {
$dc->destroy();
- } catch (\Exception $e) {
+ } catch (\Throwable $e) {
}
$dc->pull();
+ usleep(100);
$dc->spin();
}
if (($val->team_allowed === true || \Yii::$app->sys->team_visible_instances === true) && $val->player->teamPlayer && $val->player->teamPlayer->approved === 1) {
- foreach ($val->player->teamPlayer->team->approvedMembers as $teamPlayer) {
- if ((int)$teamPlayer->player->last->vpn_local_address !== 0) {
- $ips[] = long2ip($teamPlayer->player->last->vpn_local_address);
- }
- }
+ $ips = $val->player->teamPlayer->team->approvedMemberIPs;
} else if ((int)$val->player->last->vpn_local_address !== 0) {
$ips[] = long2ip($val->player->last->vpn_local_address);
}
@@ -317,8 +306,10 @@ public function actionInstances($pfonly = false)
$val->ipoctet = $dc->container->getNetworkSettings()->getNetworks()->{$val->server->network}->getIPAddress();
Pf::add_table_ip($dc->name, $val->ipoctet, true);
$val->reboot = 0;
- if ($pfonly === false)
+ if ($pfonly === false) {
+ $val->updated_at = new \yii\db\Expression('NOW()');
$val->save();
+ }
break;
case SELF::ACTION_EXPIRED:
@@ -337,14 +328,32 @@ public function actionInstances($pfonly = false)
default:
printf("Error: Unknown action\n");
}
- } catch (\Exception $e) {
+ } catch (\Throwable $e) {
if (method_exists($e, 'getErrorResponse'))
- echo "Instances:", $e->getErrorResponse()->getMessage(), "\n";
+ echo "Instances: ", $e->getErrorResponse()->getMessage(), "\n";
else
- echo "Instances:", $e->getMessage(), "\n";
+ echo "Instances: ", $e->getMessage(), "\n";
+ if (getenv('DEBUG', true) !== false)
+ \Yii::error($e);
}
+ unset($dc);
+ usleep(200);
+ $publisher = new \app\services\ServerPublisher(\Yii::$app->params['serverPublisher']);
+ $publisher->publish($val->player_id, 'target', ['id' => $val->target_id]);
} // end foreach
$this->actionInstancePfTables(true);
+
+ if ($pfonly === false) {
+ try {
+ $t = TargetInstance::find()->active()->withApprovedMemberHeartbeat()->last_updated(round($expired_ago / 2));
+ foreach ($t->all() as $instance) {
+ printf("Updating heartbeat [%d: %s for %d: %s]\n", $instance->target_id, $instance->target->name, $instance->player_id, $instance->player->username);
+ $instance->touch('updated_at');
+ }
+ } catch (\Throwable $e) {
+ echo "Instrances: Error while touching updated_at. ", $e->getMessage();
+ }
+ }
@unlink("/tmp/cron-instances.lock");
}
diff --git a/backend/commands/PlayerController.php b/backend/commands/PlayerController.php
index 586d94869..f01f531df 100644
--- a/backend/commands/PlayerController.php
+++ b/backend/commands/PlayerController.php
@@ -182,7 +182,7 @@ public function actionMail($active = false, $email = false, $status = 9, $approv
/*
Register Users and generate OpenVPN keys and settings
*/
- public function actionRegister($username, $email, $fullname, $password = false, $player_type = "offense", $active = false, $academic = false, $team_name = false, $approved = 0)
+ public function actionRegister($username, $email, $fullname, $password = false, $player_type = "offense", bool $active = true, int $status = 9, $academic = false, $team_name = false, $approved = 0)
{
echo "Registering: ", $email, "\n";
$trans = Yii::$app->db->beginTransaction();
@@ -196,7 +196,7 @@ public function actionRegister($username, $email, $fullname, $password = false,
$unique = Player::findOne(['username' => $username]);
}
$player->username = $username;
- echo 'Autogenerated username: ',$player->username,"\n";
+ echo 'Autogenerated username: ', $player->username, "\n";
} else
$player->username = trim(str_replace(array("\xc2\xa0", "\r\n", "\r"), "", $username));
@@ -210,16 +210,16 @@ public function actionRegister($username, $email, $fullname, $password = false,
$player->password = Yii::$app->security->generatePasswordHash($password);
$player->active = intval($active);
- $player->status = 10;
+ $player->status = $status;
$player->auth_key = Yii::$app->security->generateRandomString();
if (!$player->saveWithSsl()) {
- if (!$player->active && intval(\Yii::$app->sys->disable_mailer)==0) {
- $player->generateEmailVerificationToken();
- $player->status = 9;
- }
- throw new ConsoleException('Failed to save player:' . $player->username, "\n");
+ throw new ConsoleException('Failed to save player:' . $player->username . "\n");
+ }
+
+ if ((!$player->active || $player->status === 9) && intval(\Yii::$app->sys->disable_mailer) == 0) {
+ $player->generateEmailVerificationToken();
}
$player->createTeam($team_name, $approved);
@@ -366,23 +366,23 @@ public function actionCheckDupips($skip_uids = false)
}
}
- public function actionFailValidation($delete = false,$extended=false,$csv=false)
+ public function actionFailValidation($delete = false, $extended = false, $csv = false)
{
$allRecords = Player::find()->where(['status' => 10])->all();
foreach ($allRecords as $p) {
- if($extended!==false)
+ if ($extended !== false)
$p->scenario = 'extendedValidator';
else
$p->scenario = 'validator';
if (!$p->validate()) {
- echo boolval($csv)===true ? $p->id.",".$p->username : Table::widget([
- 'headers' => ['ID: ' . $p->id.' '.$p->username, 'Description'],
+ echo boolval($csv) === true ? $p->id . "," . $p->username : Table::widget([
+ 'headers' => ['ID: ' . $p->id . ' ' . $p->username, 'Description'],
'rows' => $this->getErrorRows($p),
]);
if (boolval($delete) !== false && $p->delete()) {
- echo boolval($csv)===true ? ",deleted" : $p->id." Deleted\n";
+ echo boolval($csv) === true ? ",deleted" : $p->id . " Deleted\n";
}
- echo boolval($csv)===true ? "\n" : "";
+ echo boolval($csv) === true ? "\n" : "";
}
}
}
@@ -470,8 +470,7 @@ public function actionFetchIdentification($filter = 'inactive', $scheme = 'https
foreach ($players->all() as $player) {
$baseDir = \Yii::getAlias('@app/web/identificationFiles/');
echo "processing ", $player->username;
- if(!$player->metadata)
- {
+ if (!$player->metadata) {
echo " no metadata\n";
continue;
}
@@ -486,13 +485,10 @@ public function actionFetchIdentification($filter = 'inactive', $scheme = 'https
curl_exec($ch);
$status = curl_getinfo($ch, CURLINFO_HTTP_CODE);
- if($status==200)
- {
+ if ($status == 200) {
echo " => grabbing ", $baseDir . $player->metadata->identificationFile, "\n";
file_put_contents($baseDir . $player->metadata->identificationFile, fopen("$scheme://" . Yii::$app->sys->offense_domain . '/identificationFiles/' . $player->metadata->identificationFile, 'r'));
- }
- else
- {
+ } else {
echo ", remote identification file not found\n";
}
}
diff --git a/backend/commands/TesterController.php b/backend/commands/TesterController.php
index 8f7e288e9..77f0c8bba 100644
--- a/backend/commands/TesterController.php
+++ b/backend/commands/TesterController.php
@@ -23,8 +23,8 @@ public function actionIndex()
echo Table::widget([
'headers' => ['Action', 'Usage', 'Description'],
'rows' => [
- ['Action' => 'tester/mail', 'Usage' => 'tester/mail email@example.com', 'Description' => 'Send a test mail with the current settings'],
-// ['Action' => 'docker', 'Usage' => 'tester/docker nginx:latest', 'Description' => 'Test the a given image to make sure it can be deployed on the configured docker servers of the platform.'],
+ ['Action' => 'tester/mail', 'Usage' => 'tester/mail email@example.com', 'Description' => 'Send a test mail with the current settings'],
+ ['Action' => 'tester/ws-notify', 'Usage' => 'tester/ws-notify player', 'Description' => 'Send a test websocket notification to the given player by id'],
],
]);
}
@@ -72,4 +72,17 @@ public function actionMail($to)
$this->stderr("❌ Error: " . $e->getMessage() . "\n");
}
}
+
+ public function actionWsNotify($player)
+ {
+ $player=\app\modules\frontend\models\Player::findOne($player);
+ $type = "info";
+ $title="title";
+ $body="body";
+ $cc = true;
+ $archive = true;
+ $apiOnly = false;
+ $player->notify($type, $title, $body, $cc, $archive, $apiOnly = false);
+ }
+
}
diff --git a/backend/commands/VpnController.php b/backend/commands/VpnController.php
index 0fa8fea47..ed837702a 100644
--- a/backend/commands/VpnController.php
+++ b/backend/commands/VpnController.php
@@ -120,8 +120,10 @@ public function actionLoad($filepath)
$ovpn->conf = file_get_contents($filepath);
$ovpn->name = $file;
$ovpn->server = gethostbyaddr(gethostbyname(gethostname()));
- if (preg_match('/status (.*)/', $conf, $matches) && count($matches) > 1) {
- $ovpn->status_log = trim($matches[1]);
+ if (preg_match('/^status\s+(.+)/', $conf, $matches) && count($matches) > 1) {
+ $parts = explode(' ', trim($matches[0]));
+ if(isset($parts[1]))
+ $ovpn->status_log = trim($parts[1]);
}
if (preg_match('/management (.*) (.*) (.*)/', $conf, $matches) && count($matches) > 1) {
$ovpn->management_ip_octet = $matches[1];
diff --git a/backend/components/OpenVPN.php b/backend/components/OpenVPN.php
index a31faf6cb..945de6157 100644
--- a/backend/components/OpenVPN.php
+++ b/backend/components/OpenVPN.php
@@ -81,7 +81,7 @@ static public function parseStatus(string $location)
{
if(!file_exists($location))
{
- throw new yii\base\UserException("Status file does not exist");
+ throw new \yii\base\UserException("Status file does not exist");
}
$statusLines=explode("\n",file_get_contents($location));
if(count($statusLines)==0)
diff --git a/backend/components/helpers/ArrayHelperExtended.php b/backend/components/helpers/ArrayHelperExtended.php
new file mode 100644
index 000000000..b170f8b48
--- /dev/null
+++ b/backend/components/helpers/ArrayHelperExtended.php
@@ -0,0 +1,27 @@
+db->createCommand($this->DROP_SQL)->execute();
+ }
+
+ public function down()
+ {
+ $this->db->createCommand($this->DROP_SQL)->execute();
+ }
+}
\ No newline at end of file
diff --git a/backend/modules/activity/controllers/NotificationController.php b/backend/modules/activity/controllers/NotificationController.php
index 601d6288a..c555cc366 100644
--- a/backend/modules/activity/controllers/NotificationController.php
+++ b/backend/modules/activity/controllers/NotificationController.php
@@ -21,7 +21,18 @@ class NotificationController extends \app\components\BaseController
*/
public function behaviors()
{
- return ArrayHelper::merge(parent::behaviors(), []);
+ return ArrayHelper::merge([
+ 'access' => [
+ 'class' => \yii\filters\AccessControl::class,
+ 'rules' => [
+ '00filtered-actions' => [
+ 'actions' => ['create', 'delete', 'rotate'],
+ 'allow' => true,
+ 'roles' => ['@'],
+ ]
+ ],
+ ],
+ ], parent::behaviors());
}
/**
diff --git a/backend/modules/content/controllers/CreditsController.php b/backend/modules/content/controllers/CreditsController.php
index 091a1084b..80badcd2b 100644
--- a/backend/modules/content/controllers/CreditsController.php
+++ b/backend/modules/content/controllers/CreditsController.php
@@ -17,107 +17,115 @@ class CreditsController extends \app\components\BaseController
/**
* {@inheritdoc}
*/
- public function behaviors()
- {
- return ArrayHelper::merge(parent::behaviors(),[]);
- }
+ public function behaviors()
+ {
+ return ArrayHelper::merge([
+ 'access' => [
+ 'class' => \yii\filters\AccessControl::class,
+ 'rules' => [
+ '00filtered-actions' => [
+ 'actions' => ['update', 'delete'],
+ 'allow' => true,
+ 'roles' => ['@'],
+ ]
+ ],
+ ],
+ ], parent::behaviors());
+ }
- /**
- * Lists all Credits models.
- * @return mixed
- */
- public function actionIndex()
- {
- $searchModel=new CreditsSearch();
- $dataProvider=$searchModel->search(Yii::$app->request->queryParams);
-
- return $this->render('index', [
- 'searchModel' => $searchModel,
- 'dataProvider' => $dataProvider,
- ]);
- }
+ /**
+ * Lists all Credits models.
+ * @return mixed
+ */
+ public function actionIndex()
+ {
+ $searchModel = new CreditsSearch();
+ $dataProvider = $searchModel->search(Yii::$app->request->queryParams);
- /**
- * Displays a single Credits model.
- * @param integer $id
- * @return mixed
- * @throws NotFoundHttpException if the model cannot be found
- */
- public function actionView($id)
- {
- return $this->render('view', [
- 'model' => $this->findModel($id),
- ]);
- }
+ return $this->render('index', [
+ 'searchModel' => $searchModel,
+ 'dataProvider' => $dataProvider,
+ ]);
+ }
- /**
- * Creates a new Credits model.
- * If creation is successful, the browser will be redirected to the 'view' page.
- * @return mixed
- */
- public function actionCreate()
- {
- $model=new Credits();
-
- if($model->load(Yii::$app->request->post()) && $model->save())
- {
- return $this->redirect(['view', 'id' => $model->id]);
- }
-
- return $this->render('create', [
- 'model' => $model,
- ]);
- }
+ /**
+ * Displays a single Credits model.
+ * @param integer $id
+ * @return mixed
+ * @throws NotFoundHttpException if the model cannot be found
+ */
+ public function actionView($id)
+ {
+ return $this->render('view', [
+ 'model' => $this->findModel($id),
+ ]);
+ }
+
+ /**
+ * Creates a new Credits model.
+ * If creation is successful, the browser will be redirected to the 'view' page.
+ * @return mixed
+ */
+ public function actionCreate()
+ {
+ $model = new Credits();
- /**
- * Updates an existing Credits model.
- * If update is successful, the browser will be redirected to the 'view' page.
- * @param integer $id
- * @return mixed
- * @throws NotFoundHttpException if the model cannot be found
- */
- public function actionUpdate($id)
- {
- $model=$this->findModel($id);
-
- if($model->load(Yii::$app->request->post()) && $model->save())
- {
- return $this->redirect(['view', 'id' => $model->id]);
- }
-
- return $this->render('update', [
- 'model' => $model,
- ]);
+ if ($model->load(Yii::$app->request->post()) && $model->save()) {
+ return $this->redirect(['view', 'id' => $model->id]);
}
- /**
- * Deletes an existing Credits model.
- * If deletion is successful, the browser will be redirected to the 'index' page.
- * @param integer $id
- * @return mixed
- * @throws NotFoundHttpException if the model cannot be found
- */
- public function actionDelete($id)
- {
- $this->findModel($id)->delete();
-
- return $this->redirect(['index']);
+ return $this->render('create', [
+ 'model' => $model,
+ ]);
+ }
+
+ /**
+ * Updates an existing Credits model.
+ * If update is successful, the browser will be redirected to the 'view' page.
+ * @param integer $id
+ * @return mixed
+ * @throws NotFoundHttpException if the model cannot be found
+ */
+ public function actionUpdate($id)
+ {
+ $model = $this->findModel($id);
+
+ if ($model->load(Yii::$app->request->post()) && $model->save()) {
+ return $this->redirect(['view', 'id' => $model->id]);
}
- /**
- * Finds the Credits model based on its primary key value.
- * If the model is not found, a 404 HTTP exception will be thrown.
- * @param integer $id
- * @return Credits the loaded model
- * @throws NotFoundHttpException if the model cannot be found
- */
- protected function findModel($id)
- {
- if(($model=Credits::findOne($id)) !== null)
- {
- return $model;
- }
-
- throw new NotFoundHttpException(Yii::t('app', 'The requested page does not exist.'));
+ return $this->render('update', [
+ 'model' => $model,
+ ]);
+ }
+
+ /**
+ * Deletes an existing Credits model.
+ * If deletion is successful, the browser will be redirected to the 'index' page.
+ * @param integer $id
+ * @return mixed
+ * @throws NotFoundHttpException if the model cannot be found
+ */
+ public function actionDelete($id)
+ {
+ $this->findModel($id)->delete();
+
+ return $this->redirect(['index']);
+ }
+
+ /**
+ * Finds the Credits model based on its primary key value.
+ * If the model is not found, a 404 HTTP exception will be thrown.
+ * @param integer $id
+ * @return Credits the loaded model
+ * @throws NotFoundHttpException if the model cannot be found
+ */
+ protected function findModel($id)
+ {
+ if (($model = Credits::findOne($id)) !== null) {
+ return $model;
}
+
+ throw new NotFoundHttpException(Yii::t('app', 'The requested page does not exist.'));
+ }
}
diff --git a/backend/modules/content/controllers/DefaultController.php b/backend/modules/content/controllers/DefaultController.php
index b59cbc9c9..b36cc0caa 100644
--- a/backend/modules/content/controllers/DefaultController.php
+++ b/backend/modules/content/controllers/DefaultController.php
@@ -15,10 +15,21 @@ class DefaultController extends \app\components\BaseController
/**
* {@inheritdoc}
*/
- public function behaviors()
- {
- return ArrayHelper::merge(parent::behaviors(),[]);
- }
+ public function behaviors()
+ {
+ return ArrayHelper::merge([
+ 'access' => [
+ 'class' => \yii\filters\AccessControl::class,
+ 'rules' => [
+ '00filtered-actions' => [
+ 'actions' => ['css-override', 'js-override','menu-items','frontpage-scenario','defense-scenario', 'offense-scenario', 'footer-logos'],
+ 'allow' => true,
+ 'roles' => ['@'],
+ ]
+ ],
+ ],
+ ], parent::behaviors());
+ }
/**
* Renders the index view for the module
diff --git a/backend/modules/content/controllers/EmailTemplateController.php b/backend/modules/content/controllers/EmailTemplateController.php
index 607cd2004..ad3e3f88b 100644
--- a/backend/modules/content/controllers/EmailTemplateController.php
+++ b/backend/modules/content/controllers/EmailTemplateController.php
@@ -20,7 +20,18 @@ class EmailTemplateController extends \app\components\BaseController
*/
public function behaviors()
{
- return ArrayHelper::merge(parent::behaviors(), []);
+ return ArrayHelper::merge([
+ 'access' => [
+ 'class' => \yii\filters\AccessControl::class,
+ 'rules' => [
+ '00filtered-actions' => [
+ 'actions' => ['update', 'delete','adhoc-mail'],
+ 'allow' => true,
+ 'roles' => ['@'],
+ ]
+ ],
+ ],
+ ], parent::behaviors());
}
/**
diff --git a/backend/modules/content/controllers/FaqController.php b/backend/modules/content/controllers/FaqController.php
index f02680889..7ca9f053a 100644
--- a/backend/modules/content/controllers/FaqController.php
+++ b/backend/modules/content/controllers/FaqController.php
@@ -17,107 +17,115 @@ class FaqController extends \app\components\BaseController
/**
* {@inheritdoc}
*/
- public function behaviors()
- {
- return ArrayHelper::merge(parent::behaviors(),[]);
- }
+ public function behaviors()
+ {
+ return ArrayHelper::merge([
+ 'access' => [
+ 'class' => \yii\filters\AccessControl::class,
+ 'rules' => [
+ '00filtered-actions' => [
+ 'actions' => ['update', 'delete'],
+ 'allow' => true,
+ 'roles' => ['@'],
+ ]
+ ],
+ ],
+ ], parent::behaviors());
+ }
- /**
- * Lists all Faq models.
- * @return mixed
- */
- public function actionIndex()
- {
- $searchModel=new FaqSearch();
- $dataProvider=$searchModel->search(Yii::$app->request->queryParams);
-
- return $this->render('index', [
- 'searchModel' => $searchModel,
- 'dataProvider' => $dataProvider,
- ]);
- }
+ /**
+ * Lists all Faq models.
+ * @return mixed
+ */
+ public function actionIndex()
+ {
+ $searchModel = new FaqSearch();
+ $dataProvider = $searchModel->search(Yii::$app->request->queryParams);
- /**
- * Displays a single Faq model.
- * @param integer $id
- * @return mixed
- * @throws NotFoundHttpException if the model cannot be found
- */
- public function actionView($id)
- {
- return $this->render('view', [
- 'model' => $this->findModel($id),
- ]);
- }
+ return $this->render('index', [
+ 'searchModel' => $searchModel,
+ 'dataProvider' => $dataProvider,
+ ]);
+ }
- /**
- * Creates a new Faq model.
- * If creation is successful, the browser will be redirected to the 'view' page.
- * @return mixed
- */
- public function actionCreate()
- {
- $model=new Faq();
-
- if($model->load(Yii::$app->request->post()) && $model->save())
- {
- return $this->redirect(['view', 'id' => $model->id]);
- }
-
- return $this->render('create', [
- 'model' => $model,
- ]);
- }
+ /**
+ * Displays a single Faq model.
+ * @param integer $id
+ * @return mixed
+ * @throws NotFoundHttpException if the model cannot be found
+ */
+ public function actionView($id)
+ {
+ return $this->render('view', [
+ 'model' => $this->findModel($id),
+ ]);
+ }
+
+ /**
+ * Creates a new Faq model.
+ * If creation is successful, the browser will be redirected to the 'view' page.
+ * @return mixed
+ */
+ public function actionCreate()
+ {
+ $model = new Faq();
- /**
- * Updates an existing Faq model.
- * If update is successful, the browser will be redirected to the 'view' page.
- * @param integer $id
- * @return mixed
- * @throws NotFoundHttpException if the model cannot be found
- */
- public function actionUpdate($id)
- {
- $model=$this->findModel($id);
-
- if($model->load(Yii::$app->request->post()) && $model->save())
- {
- return $this->redirect(['view', 'id' => $model->id]);
- }
-
- return $this->render('update', [
- 'model' => $model,
- ]);
+ if ($model->load(Yii::$app->request->post()) && $model->save()) {
+ return $this->redirect(['view', 'id' => $model->id]);
}
- /**
- * Deletes an existing Faq model.
- * If deletion is successful, the browser will be redirected to the 'index' page.
- * @param integer $id
- * @return mixed
- * @throws NotFoundHttpException if the model cannot be found
- */
- public function actionDelete($id)
- {
- $this->findModel($id)->delete();
-
- return $this->redirect(['index']);
+ return $this->render('create', [
+ 'model' => $model,
+ ]);
+ }
+
+ /**
+ * Updates an existing Faq model.
+ * If update is successful, the browser will be redirected to the 'view' page.
+ * @param integer $id
+ * @return mixed
+ * @throws NotFoundHttpException if the model cannot be found
+ */
+ public function actionUpdate($id)
+ {
+ $model = $this->findModel($id);
+
+ if ($model->load(Yii::$app->request->post()) && $model->save()) {
+ return $this->redirect(['view', 'id' => $model->id]);
}
- /**
- * Finds the Faq model based on its primary key value.
- * If the model is not found, a 404 HTTP exception will be thrown.
- * @param integer $id
- * @return Faq the loaded model
- * @throws NotFoundHttpException if the model cannot be found
- */
- protected function findModel($id)
- {
- if(($model=Faq::findOne($id)) !== null)
- {
- return $model;
- }
-
- throw new NotFoundHttpException(Yii::t('app', 'The requested page does not exist.'));
+ return $this->render('update', [
+ 'model' => $model,
+ ]);
+ }
+
+ /**
+ * Deletes an existing Faq model.
+ * If deletion is successful, the browser will be redirected to the 'index' page.
+ * @param integer $id
+ * @return mixed
+ * @throws NotFoundHttpException if the model cannot be found
+ */
+ public function actionDelete($id)
+ {
+ $this->findModel($id)->delete();
+
+ return $this->redirect(['index']);
+ }
+
+ /**
+ * Finds the Faq model based on its primary key value.
+ * If the model is not found, a 404 HTTP exception will be thrown.
+ * @param integer $id
+ * @return Faq the loaded model
+ * @throws NotFoundHttpException if the model cannot be found
+ */
+ protected function findModel($id)
+ {
+ if (($model = Faq::findOne($id)) !== null) {
+ return $model;
}
+
+ throw new NotFoundHttpException(Yii::t('app', 'The requested page does not exist.'));
+ }
}
diff --git a/backend/modules/content/controllers/InstructionController.php b/backend/modules/content/controllers/InstructionController.php
index 4f0168db7..576ef5c32 100644
--- a/backend/modules/content/controllers/InstructionController.php
+++ b/backend/modules/content/controllers/InstructionController.php
@@ -17,107 +17,115 @@ class InstructionController extends \app\components\BaseController
/**
* {@inheritdoc}
*/
- public function behaviors()
- {
- return ArrayHelper::merge(parent::behaviors(),[]);
- }
+ public function behaviors()
+ {
+ return ArrayHelper::merge([
+ 'access' => [
+ 'class' => \yii\filters\AccessControl::class,
+ 'rules' => [
+ '00filtered-actions' => [
+ 'actions' => ['update', 'delete'],
+ 'allow' => true,
+ 'roles' => ['@'],
+ ]
+ ],
+ ],
+ ], parent::behaviors());
+ }
- /**
- * Lists all Instruction models.
- * @return mixed
- */
- public function actionIndex()
- {
- $searchModel=new InstructionSearch();
- $dataProvider=$searchModel->search(Yii::$app->request->queryParams);
-
- return $this->render('index', [
- 'searchModel' => $searchModel,
- 'dataProvider' => $dataProvider,
- ]);
- }
+ /**
+ * Lists all Instruction models.
+ * @return mixed
+ */
+ public function actionIndex()
+ {
+ $searchModel = new InstructionSearch();
+ $dataProvider = $searchModel->search(Yii::$app->request->queryParams);
- /**
- * Displays a single Instruction model.
- * @param integer $id
- * @return mixed
- * @throws NotFoundHttpException if the model cannot be found
- */
- public function actionView($id)
- {
- return $this->render('view', [
- 'model' => $this->findModel($id),
- ]);
- }
+ return $this->render('index', [
+ 'searchModel' => $searchModel,
+ 'dataProvider' => $dataProvider,
+ ]);
+ }
- /**
- * Creates a new Instruction model.
- * If creation is successful, the browser will be redirected to the 'view' page.
- * @return mixed
- */
- public function actionCreate()
- {
- $model=new Instruction();
-
- if($model->load(Yii::$app->request->post()) && $model->save())
- {
- return $this->redirect(['view', 'id' => $model->id]);
- }
-
- return $this->render('create', [
- 'model' => $model,
- ]);
- }
+ /**
+ * Displays a single Instruction model.
+ * @param integer $id
+ * @return mixed
+ * @throws NotFoundHttpException if the model cannot be found
+ */
+ public function actionView($id)
+ {
+ return $this->render('view', [
+ 'model' => $this->findModel($id),
+ ]);
+ }
+
+ /**
+ * Creates a new Instruction model.
+ * If creation is successful, the browser will be redirected to the 'view' page.
+ * @return mixed
+ */
+ public function actionCreate()
+ {
+ $model = new Instruction();
- /**
- * Updates an existing Instruction model.
- * If update is successful, the browser will be redirected to the 'view' page.
- * @param integer $id
- * @return mixed
- * @throws NotFoundHttpException if the model cannot be found
- */
- public function actionUpdate($id)
- {
- $model=$this->findModel($id);
-
- if($model->load(Yii::$app->request->post()) && $model->save())
- {
- return $this->redirect(['view', 'id' => $model->id]);
- }
-
- return $this->render('update', [
- 'model' => $model,
- ]);
+ if ($model->load(Yii::$app->request->post()) && $model->save()) {
+ return $this->redirect(['view', 'id' => $model->id]);
}
- /**
- * Deletes an existing Instruction model.
- * If deletion is successful, the browser will be redirected to the 'index' page.
- * @param integer $id
- * @return mixed
- * @throws NotFoundHttpException if the model cannot be found
- */
- public function actionDelete($id)
- {
- $this->findModel($id)->delete();
-
- return $this->redirect(['index']);
+ return $this->render('create', [
+ 'model' => $model,
+ ]);
+ }
+
+ /**
+ * Updates an existing Instruction model.
+ * If update is successful, the browser will be redirected to the 'view' page.
+ * @param integer $id
+ * @return mixed
+ * @throws NotFoundHttpException if the model cannot be found
+ */
+ public function actionUpdate($id)
+ {
+ $model = $this->findModel($id);
+
+ if ($model->load(Yii::$app->request->post()) && $model->save()) {
+ return $this->redirect(['view', 'id' => $model->id]);
}
- /**
- * Finds the Instruction model based on its primary key value.
- * If the model is not found, a 404 HTTP exception will be thrown.
- * @param integer $id
- * @return Instruction the loaded model
- * @throws NotFoundHttpException if the model cannot be found
- */
- protected function findModel($id)
- {
- if(($model=Instruction::findOne($id)) !== null)
- {
- return $model;
- }
-
- throw new NotFoundHttpException('The requested page does not exist.');
+ return $this->render('update', [
+ 'model' => $model,
+ ]);
+ }
+
+ /**
+ * Deletes an existing Instruction model.
+ * If deletion is successful, the browser will be redirected to the 'index' page.
+ * @param integer $id
+ * @return mixed
+ * @throws NotFoundHttpException if the model cannot be found
+ */
+ public function actionDelete($id)
+ {
+ $this->findModel($id)->delete();
+
+ return $this->redirect(['index']);
+ }
+
+ /**
+ * Finds the Instruction model based on its primary key value.
+ * If the model is not found, a 404 HTTP exception will be thrown.
+ * @param integer $id
+ * @return Instruction the loaded model
+ * @throws NotFoundHttpException if the model cannot be found
+ */
+ protected function findModel($id)
+ {
+ if (($model = Instruction::findOne($id)) !== null) {
+ return $model;
}
+
+ throw new NotFoundHttpException('The requested page does not exist.');
+ }
}
diff --git a/backend/modules/content/controllers/LayoutOverrideController.php b/backend/modules/content/controllers/LayoutOverrideController.php
index 1d8fe4859..3044c40fa 100644
--- a/backend/modules/content/controllers/LayoutOverrideController.php
+++ b/backend/modules/content/controllers/LayoutOverrideController.php
@@ -15,107 +15,118 @@
*/
class LayoutOverrideController extends \app\components\BaseController
{
- /**
- * {@inheritdoc}
- */
- public function behaviors()
- {
- return ArrayHelper::merge(parent::behaviors(),[]);
+ /**
+ * {@inheritdoc}
+ */
+ public function behaviors()
+ {
+ return ArrayHelper::merge([
+ 'access' => [
+ 'class' => \yii\filters\AccessControl::class,
+ 'rules' => [
+ '00filtered-actions' => [
+ 'actions' => ['update', 'delete'],
+ 'allow' => true,
+ 'roles' => ['@'],
+ ]
+ ],
+ ],
+ ], parent::behaviors());
+ }
+
+ /**
+ * Lists all LayoutOverride models.
+ * @return mixed
+ */
+ public function actionIndex()
+ {
+ $searchModel = new LayoutOverrideSearch();
+ $dataProvider = $searchModel->search(Yii::$app->request->queryParams);
+
+ return $this->render('index', [
+ 'searchModel' => $searchModel,
+ 'dataProvider' => $dataProvider,
+ ]);
+ }
+
+ /**
+ * Displays a single LayoutOverride model.
+ * @param integer $id
+ * @return mixed
+ * @throws NotFoundHttpException if the model cannot be found
+ */
+ public function actionView($id)
+ {
+ return $this->render('view', [
+ 'model' => $this->findModel($id),
+ ]);
+ }
+
+ /**
+ * Creates a new LayoutOverride model.
+ * If creation is successful, the browser will be redirected to the 'view' page.
+ * @return mixed
+ */
+ public function actionCreate()
+ {
+ $model = new LayoutOverride();
+
+ if ($model->load(Yii::$app->request->post()) && $model->save()) {
+ return $this->redirect(['view', 'id' => $model->id]);
}
- /**
- * Lists all LayoutOverride models.
- * @return mixed
- */
- public function actionIndex()
- {
- $searchModel = new LayoutOverrideSearch();
- $dataProvider = $searchModel->search(Yii::$app->request->queryParams);
-
- return $this->render('index', [
- 'searchModel' => $searchModel,
- 'dataProvider' => $dataProvider,
- ]);
+ return $this->render('create', [
+ 'model' => $model,
+ ]);
+ }
+
+ /**
+ * Updates an existing LayoutOverride model.
+ * If update is successful, the browser will be redirected to the 'view' page.
+ * @param integer $id
+ * @return mixed
+ * @throws NotFoundHttpException if the model cannot be found
+ */
+ public function actionUpdate($id)
+ {
+ $model = $this->findModel($id);
+
+ if ($model->load(Yii::$app->request->post()) && $model->save()) {
+ return $this->redirect(['view', 'id' => $model->id]);
}
- /**
- * Displays a single LayoutOverride model.
- * @param integer $id
- * @return mixed
- * @throws NotFoundHttpException if the model cannot be found
- */
- public function actionView($id)
- {
- return $this->render('view', [
- 'model' => $this->findModel($id),
- ]);
+ return $this->render('update', [
+ 'model' => $model,
+ ]);
+ }
+
+ /**
+ * Deletes an existing LayoutOverride model.
+ * If deletion is successful, the browser will be redirected to the 'index' page.
+ * @param integer $id
+ * @return mixed
+ * @throws NotFoundHttpException if the model cannot be found
+ */
+ public function actionDelete($id)
+ {
+ $this->findModel($id)->delete();
+
+ return $this->redirect(['index']);
+ }
+
+ /**
+ * Finds the LayoutOverride model based on its primary key value.
+ * If the model is not found, a 404 HTTP exception will be thrown.
+ * @param integer $id
+ * @return LayoutOverride the loaded model
+ * @throws NotFoundHttpException if the model cannot be found
+ */
+ protected function findModel($id)
+ {
+ if (($model = LayoutOverride::findOne($id)) !== null) {
+ return $model;
}
- /**
- * Creates a new LayoutOverride model.
- * If creation is successful, the browser will be redirected to the 'view' page.
- * @return mixed
- */
- public function actionCreate()
- {
- $model = new LayoutOverride();
-
- if ($model->load(Yii::$app->request->post()) && $model->save()) {
- return $this->redirect(['view', 'id' => $model->id]);
- }
-
- return $this->render('create', [
- 'model' => $model,
- ]);
- }
-
- /**
- * Updates an existing LayoutOverride model.
- * If update is successful, the browser will be redirected to the 'view' page.
- * @param integer $id
- * @return mixed
- * @throws NotFoundHttpException if the model cannot be found
- */
- public function actionUpdate($id)
- {
- $model = $this->findModel($id);
-
- if ($model->load(Yii::$app->request->post()) && $model->save()) {
- return $this->redirect(['view', 'id' => $model->id]);
- }
-
- return $this->render('update', [
- 'model' => $model,
- ]);
- }
-
- /**
- * Deletes an existing LayoutOverride model.
- * If deletion is successful, the browser will be redirected to the 'index' page.
- * @param integer $id
- * @return mixed
- * @throws NotFoundHttpException if the model cannot be found
- */
- public function actionDelete($id)
- {
- $this->findModel($id)->delete();
-
- return $this->redirect(['index']);
- }
-
- /**
- * Finds the LayoutOverride model based on its primary key value.
- * If the model is not found, a 404 HTTP exception will be thrown.
- * @param integer $id
- * @return LayoutOverride the loaded model
- * @throws NotFoundHttpException if the model cannot be found
- */
- protected function findModel($id)
- {
- if (($model = LayoutOverride::findOne($id)) !== null) {
- return $model;
- }
-
- throw new NotFoundHttpException(Yii::t('app', 'The requested page does not exist.'));
- }
+ throw new NotFoundHttpException(Yii::t('app', 'The requested page does not exist.'));
+ }
}
diff --git a/backend/modules/content/controllers/NewsController.php b/backend/modules/content/controllers/NewsController.php
index 5c8d3bfbc..fa7b3bc22 100644
--- a/backend/modules/content/controllers/NewsController.php
+++ b/backend/modules/content/controllers/NewsController.php
@@ -17,130 +17,139 @@ class NewsController extends \app\components\BaseController
/**
* {@inheritdoc}
*/
- public function behaviors()
- {
- return ArrayHelper::merge(parent::behaviors(),[
- 'verbs' => [
- 'class' => VerbFilter::class,
- 'actions' => [
- 'discord' => ['POST'],
- ],
- ],
- ]);
- }
+ public function behaviors()
+ {
+ return ArrayHelper::merge([
+ 'access' => [
+ 'class' => \yii\filters\AccessControl::class,
+ 'rules' => [
+ '00filtered-actions' => [
+ 'actions' => ['update', 'delete'],
+ 'allow' => true,
+ 'roles' => ['@'],
+ ]
+ ],
+ ],
+ 'verbs' => [
+ 'class' => VerbFilter::class,
+ 'actions' => [
+ 'discord' => ['POST'],
+ ],
+ ],
+ ], parent::behaviors());
+ }
- /**
- * Lists all News models.
- * @return mixed
- */
- public function actionIndex()
- {
- $searchModel = new NewsSearch();
- $dataProvider = $searchModel->search(Yii::$app->request->queryParams);
-
- return $this->render('index', [
- 'searchModel' => $searchModel,
- 'dataProvider' => $dataProvider,
- ]);
- }
+ /**
+ * Lists all News models.
+ * @return mixed
+ */
+ public function actionIndex()
+ {
+ $searchModel = new NewsSearch();
+ $dataProvider = $searchModel->search(Yii::$app->request->queryParams);
- /**
- * Displays a single News model.
- * @param integer $id
- * @return mixed
- * @throws NotFoundHttpException if the model cannot be found
- */
- public function actionView($id)
- {
- return $this->render('view', [
- 'model' => $this->findModel($id),
- ]);
- }
+ return $this->render('index', [
+ 'searchModel' => $searchModel,
+ 'dataProvider' => $dataProvider,
+ ]);
+ }
- /**
- * Creates a new News model.
- * If creation is successful, the browser will be redirected to the 'view' page.
- * @return mixed
- */
- public function actionCreate()
- {
- $model = new News();
-
- if ($model->load(Yii::$app->request->post()) && $model->save()) {
- return $this->redirect(['view', 'id' => $model->id]);
- }
-
- return $this->render('create', [
- 'model' => $model,
- ]);
- }
+ /**
+ * Displays a single News model.
+ * @param integer $id
+ * @return mixed
+ * @throws NotFoundHttpException if the model cannot be found
+ */
+ public function actionView($id)
+ {
+ return $this->render('view', [
+ 'model' => $this->findModel($id),
+ ]);
+ }
+
+ /**
+ * Creates a new News model.
+ * If creation is successful, the browser will be redirected to the 'view' page.
+ * @return mixed
+ */
+ public function actionCreate()
+ {
+ $model = new News();
- /**
- * Updates an existing News model.
- * If update is successful, the browser will be redirected to the 'view' page.
- * @param integer $id
- * @return mixed
- * @throws NotFoundHttpException if the model cannot be found
- */
- public function actionUpdate($id)
- {
- $model = $this->findModel($id);
-
- if ($model->load(Yii::$app->request->post()) && $model->save()) {
- return $this->redirect(['view', 'id' => $model->id]);
- }
-
- return $this->render('update', [
- 'model' => $model,
- ]);
+ if ($model->load(Yii::$app->request->post()) && $model->save()) {
+ return $this->redirect(['view', 'id' => $model->id]);
}
- /**
- * Deletes an existing News model.
- * If deletion is successful, the browser will be redirected to the 'index' page.
- * @param integer $id
- * @return mixed
- * @throws NotFoundHttpException if the model cannot be found
- */
- public function actionDelete($id)
- {
- $this->findModel($id)->delete();
-
- return $this->redirect(['index']);
+ return $this->render('create', [
+ 'model' => $model,
+ ]);
+ }
+
+ /**
+ * Updates an existing News model.
+ * If update is successful, the browser will be redirected to the 'view' page.
+ * @param integer $id
+ * @return mixed
+ * @throws NotFoundHttpException if the model cannot be found
+ */
+ public function actionUpdate($id)
+ {
+ $model = $this->findModel($id);
+
+ if ($model->load(Yii::$app->request->post()) && $model->save()) {
+ return $this->redirect(['view', 'id' => $model->id]);
}
- /**
- * Posts an existing News model to discord webhook
- * Upon submission (successful or not), the browser will be redirected to the 'index' page and display an appropriate messages.
- * @param integer $id
- * @return mixed
- * @throws NotFoundHttpException if the model cannot be found
- */
- public function actionDiscord($id)
- {
- try {
- $result=$this->findModel($id)->toDiscord();
- Yii::$app->session->setFlash('success',Yii::t('app','News item got send to the discord news webhook'));
- }
- catch (\Exception $e) {
- Yii::$app->session->setFlash('error',Yii::t('app','Failed to send news item to discord webhook'));
- }
- return $this->redirect(['index']);
+ return $this->render('update', [
+ 'model' => $model,
+ ]);
+ }
+
+ /**
+ * Deletes an existing News model.
+ * If deletion is successful, the browser will be redirected to the 'index' page.
+ * @param integer $id
+ * @return mixed
+ * @throws NotFoundHttpException if the model cannot be found
+ */
+ public function actionDelete($id)
+ {
+ $this->findModel($id)->delete();
+
+ return $this->redirect(['index']);
+ }
+
+ /**
+ * Posts an existing News model to discord webhook
+ * Upon submission (successful or not), the browser will be redirected to the 'index' page and display an appropriate messages.
+ * @param integer $id
+ * @return mixed
+ * @throws NotFoundHttpException if the model cannot be found
+ */
+ public function actionDiscord($id)
+ {
+ try {
+ $result = $this->findModel($id)->toDiscord();
+ Yii::$app->session->setFlash('success', Yii::t('app', 'News item got send to the discord news webhook'));
+ } catch (\Exception $e) {
+ Yii::$app->session->setFlash('error', Yii::t('app', 'Failed to send news item to discord webhook'));
}
+ return $this->redirect(['index']);
+ }
- /**
- * Finds the News model based on its primary key value.
- * If the model is not found, a 404 HTTP exception will be thrown.
- * @param integer $id
- * @return News the loaded model
- * @throws NotFoundHttpException if the model cannot be found
- */
- protected function findModel($id)
- {
- if (($model = News::findOne($id)) !== null) {
- return $model;
- }
-
- throw new NotFoundHttpException(Yii::t('app', 'The requested page does not exist.'));
+ /**
+ * Finds the News model based on its primary key value.
+ * If the model is not found, a 404 HTTP exception will be thrown.
+ * @param integer $id
+ * @return News the loaded model
+ * @throws NotFoundHttpException if the model cannot be found
+ */
+ protected function findModel($id)
+ {
+ if (($model = News::findOne($id)) !== null) {
+ return $model;
}
+
+ throw new NotFoundHttpException(Yii::t('app', 'The requested page does not exist.'));
+ }
}
diff --git a/backend/modules/content/controllers/ObjectiveController.php b/backend/modules/content/controllers/ObjectiveController.php
index f3fba39c1..497c2c463 100644
--- a/backend/modules/content/controllers/ObjectiveController.php
+++ b/backend/modules/content/controllers/ObjectiveController.php
@@ -17,107 +17,115 @@ class ObjectiveController extends \app\components\BaseController
/**
* {@inheritdoc}
*/
- public function behaviors()
- {
- return ArrayHelper::merge(parent::behaviors(),[]);
- }
+ public function behaviors()
+ {
+ return ArrayHelper::merge([
+ 'access' => [
+ 'class' => \yii\filters\AccessControl::class,
+ 'rules' => [
+ '00filtered-actions' => [
+ 'actions' => ['update', 'delete'],
+ 'allow' => true,
+ 'roles' => ['@'],
+ ]
+ ],
+ ],
+ ], parent::behaviors());
+ }
- /**
- * Lists all Objective models.
- * @return mixed
- */
- public function actionIndex()
- {
- $searchModel=new ObjectiveSearch();
- $dataProvider=$searchModel->search(Yii::$app->request->queryParams);
-
- return $this->render('index', [
- 'searchModel' => $searchModel,
- 'dataProvider' => $dataProvider,
- ]);
- }
+ /**
+ * Lists all Objective models.
+ * @return mixed
+ */
+ public function actionIndex()
+ {
+ $searchModel = new ObjectiveSearch();
+ $dataProvider = $searchModel->search(Yii::$app->request->queryParams);
- /**
- * Displays a single Objective model.
- * @param integer $id
- * @return mixed
- * @throws NotFoundHttpException if the model cannot be found
- */
- public function actionView($id)
- {
- return $this->render('view', [
- 'model' => $this->findModel($id),
- ]);
- }
+ return $this->render('index', [
+ 'searchModel' => $searchModel,
+ 'dataProvider' => $dataProvider,
+ ]);
+ }
- /**
- * Creates a new Objective model.
- * If creation is successful, the browser will be redirected to the 'view' page.
- * @return mixed
- */
- public function actionCreate()
- {
- $model=new Objective();
-
- if($model->load(Yii::$app->request->post()) && $model->save())
- {
- return $this->redirect(['view', 'id' => $model->id]);
- }
-
- return $this->render('create', [
- 'model' => $model,
- ]);
- }
+ /**
+ * Displays a single Objective model.
+ * @param integer $id
+ * @return mixed
+ * @throws NotFoundHttpException if the model cannot be found
+ */
+ public function actionView($id)
+ {
+ return $this->render('view', [
+ 'model' => $this->findModel($id),
+ ]);
+ }
+
+ /**
+ * Creates a new Objective model.
+ * If creation is successful, the browser will be redirected to the 'view' page.
+ * @return mixed
+ */
+ public function actionCreate()
+ {
+ $model = new Objective();
- /**
- * Updates an existing Objective model.
- * If update is successful, the browser will be redirected to the 'view' page.
- * @param integer $id
- * @return mixed
- * @throws NotFoundHttpException if the model cannot be found
- */
- public function actionUpdate($id)
- {
- $model=$this->findModel($id);
-
- if($model->load(Yii::$app->request->post()) && $model->save())
- {
- return $this->redirect(['view', 'id' => $model->id]);
- }
-
- return $this->render('update', [
- 'model' => $model,
- ]);
+ if ($model->load(Yii::$app->request->post()) && $model->save()) {
+ return $this->redirect(['view', 'id' => $model->id]);
}
- /**
- * Deletes an existing Objective model.
- * If deletion is successful, the browser will be redirected to the 'index' page.
- * @param integer $id
- * @return mixed
- * @throws NotFoundHttpException if the model cannot be found
- */
- public function actionDelete($id)
- {
- $this->findModel($id)->delete();
-
- return $this->redirect(['index']);
+ return $this->render('create', [
+ 'model' => $model,
+ ]);
+ }
+
+ /**
+ * Updates an existing Objective model.
+ * If update is successful, the browser will be redirected to the 'view' page.
+ * @param integer $id
+ * @return mixed
+ * @throws NotFoundHttpException if the model cannot be found
+ */
+ public function actionUpdate($id)
+ {
+ $model = $this->findModel($id);
+
+ if ($model->load(Yii::$app->request->post()) && $model->save()) {
+ return $this->redirect(['view', 'id' => $model->id]);
}
- /**
- * Finds the Objective model based on its primary key value.
- * If the model is not found, a 404 HTTP exception will be thrown.
- * @param integer $id
- * @return Objective the loaded model
- * @throws NotFoundHttpException if the model cannot be found
- */
- protected function findModel($id)
- {
- if(($model=Objective::findOne($id)) !== null)
- {
- return $model;
- }
-
- throw new NotFoundHttpException('The requested page does not exist.');
+ return $this->render('update', [
+ 'model' => $model,
+ ]);
+ }
+
+ /**
+ * Deletes an existing Objective model.
+ * If deletion is successful, the browser will be redirected to the 'index' page.
+ * @param integer $id
+ * @return mixed
+ * @throws NotFoundHttpException if the model cannot be found
+ */
+ public function actionDelete($id)
+ {
+ $this->findModel($id)->delete();
+
+ return $this->redirect(['index']);
+ }
+
+ /**
+ * Finds the Objective model based on its primary key value.
+ * If the model is not found, a 404 HTTP exception will be thrown.
+ * @param integer $id
+ * @return Objective the loaded model
+ * @throws NotFoundHttpException if the model cannot be found
+ */
+ protected function findModel($id)
+ {
+ if (($model = Objective::findOne($id)) !== null) {
+ return $model;
}
+
+ throw new NotFoundHttpException('The requested page does not exist.');
+ }
}
diff --git a/backend/modules/content/controllers/PagesController.php b/backend/modules/content/controllers/PagesController.php
index 4367b5736..e18c88e4a 100644
--- a/backend/modules/content/controllers/PagesController.php
+++ b/backend/modules/content/controllers/PagesController.php
@@ -8,112 +8,124 @@
use yii\web\NotFoundHttpException;
use yii\filters\VerbFilter;
use yii\helpers\ArrayHelper;
+
/**
* PagesController implements the CRUD actions for Pages model.
*/
class PagesController extends \app\components\BaseController
{
- /**
- * {@inheritdoc}
- */
- public function behaviors()
- {
- return ArrayHelper::merge(parent::behaviors(),[]);
- }
+ /**
+ * {@inheritdoc}
+ */
+ public function behaviors()
+ {
+ return ArrayHelper::merge([
+ 'access' => [
+ 'class' => \yii\filters\AccessControl::class,
+ 'rules' => [
+ '00filtered-actions' => [
+ 'actions' => ['update', 'delete'],
+ 'allow' => true,
+ 'roles' => ['@'],
+ ]
+ ],
+ ],
+ ], parent::behaviors());
+ }
- /**
- * Lists all Pages models.
- * @return mixed
- */
- public function actionIndex()
- {
- $searchModel = new PagesSearch();
- $dataProvider = $searchModel->search(Yii::$app->request->queryParams);
-
- return $this->render('index', [
- 'searchModel' => $searchModel,
- 'dataProvider' => $dataProvider,
- ]);
- }
+ /**
+ * Lists all Pages models.
+ * @return mixed
+ */
+ public function actionIndex()
+ {
+ $searchModel = new PagesSearch();
+ $dataProvider = $searchModel->search(Yii::$app->request->queryParams);
- /**
- * Displays a single Pages model.
- * @param integer $id
- * @return mixed
- * @throws NotFoundHttpException if the model cannot be found
- */
- public function actionView($id)
- {
- return $this->render('view', [
- 'model' => $this->findModel($id),
- ]);
- }
+ return $this->render('index', [
+ 'searchModel' => $searchModel,
+ 'dataProvider' => $dataProvider,
+ ]);
+ }
- /**
- * Creates a new Pages model.
- * If creation is successful, the browser will be redirected to the 'view' page.
- * @return mixed
- */
- public function actionCreate()
- {
- $model = new Pages();
-
- if ($model->load(Yii::$app->request->post()) && $model->save()) {
- return $this->redirect(['view', 'id' => $model->id]);
- }
-
- return $this->render('create', [
- 'model' => $model,
- ]);
- }
+ /**
+ * Displays a single Pages model.
+ * @param integer $id
+ * @return mixed
+ * @throws NotFoundHttpException if the model cannot be found
+ */
+ public function actionView($id)
+ {
+ return $this->render('view', [
+ 'model' => $this->findModel($id),
+ ]);
+ }
+
+ /**
+ * Creates a new Pages model.
+ * If creation is successful, the browser will be redirected to the 'view' page.
+ * @return mixed
+ */
+ public function actionCreate()
+ {
+ $model = new Pages();
- /**
- * Updates an existing Pages model.
- * If update is successful, the browser will be redirected to the 'view' page.
- * @param integer $id
- * @return mixed
- * @throws NotFoundHttpException if the model cannot be found
- */
- public function actionUpdate($id)
- {
- $model = $this->findModel($id);
-
- if ($model->load(Yii::$app->request->post()) && $model->save()) {
- return $this->redirect(['view', 'id' => $model->id]);
- }
-
- return $this->render('update', [
- 'model' => $model,
- ]);
+ if ($model->load(Yii::$app->request->post()) && $model->save()) {
+ return $this->redirect(['view', 'id' => $model->id]);
}
- /**
- * Deletes an existing Pages model.
- * If deletion is successful, the browser will be redirected to the 'index' page.
- * @param integer $id
- * @return mixed
- * @throws NotFoundHttpException if the model cannot be found
- */
- public function actionDelete($id)
- {
- $this->findModel($id)->delete();
-
- return $this->redirect(['index']);
+ return $this->render('create', [
+ 'model' => $model,
+ ]);
+ }
+
+ /**
+ * Updates an existing Pages model.
+ * If update is successful, the browser will be redirected to the 'view' page.
+ * @param integer $id
+ * @return mixed
+ * @throws NotFoundHttpException if the model cannot be found
+ */
+ public function actionUpdate($id)
+ {
+ $model = $this->findModel($id);
+
+ if ($model->load(Yii::$app->request->post()) && $model->save()) {
+ return $this->redirect(['view', 'id' => $model->id]);
}
- /**
- * Finds the Pages model based on its primary key value.
- * If the model is not found, a 404 HTTP exception will be thrown.
- * @param integer $id
- * @return Pages the loaded model
- * @throws NotFoundHttpException if the model cannot be found
- */
- protected function findModel($id)
- {
- if (($model = Pages::findOne($id)) !== null) {
- return $model;
- }
-
- throw new NotFoundHttpException(Yii::t('app', 'The requested page does not exist.'));
+ return $this->render('update', [
+ 'model' => $model,
+ ]);
+ }
+
+ /**
+ * Deletes an existing Pages model.
+ * If deletion is successful, the browser will be redirected to the 'index' page.
+ * @param integer $id
+ * @return mixed
+ * @throws NotFoundHttpException if the model cannot be found
+ */
+ public function actionDelete($id)
+ {
+ $this->findModel($id)->delete();
+
+ return $this->redirect(['index']);
+ }
+
+ /**
+ * Finds the Pages model based on its primary key value.
+ * If the model is not found, a 404 HTTP exception will be thrown.
+ * @param integer $id
+ * @return Pages the loaded model
+ * @throws NotFoundHttpException if the model cannot be found
+ */
+ protected function findModel($id)
+ {
+ if (($model = Pages::findOne($id)) !== null) {
+ return $model;
}
+
+ throw new NotFoundHttpException(Yii::t('app', 'The requested page does not exist.'));
+ }
}
diff --git a/backend/modules/content/controllers/RuleController.php b/backend/modules/content/controllers/RuleController.php
index 5cb141d85..516fde8ea 100644
--- a/backend/modules/content/controllers/RuleController.php
+++ b/backend/modules/content/controllers/RuleController.php
@@ -17,107 +17,115 @@ class RuleController extends \app\components\BaseController
/**
* {@inheritdoc}
*/
- public function behaviors()
- {
- return ArrayHelper::merge(parent::behaviors(),[]);
- }
+ public function behaviors()
+ {
+ return ArrayHelper::merge([
+ 'access' => [
+ 'class' => \yii\filters\AccessControl::class,
+ 'rules' => [
+ '00filtered-actions' => [
+ 'actions' => ['update', 'delete'],
+ 'allow' => true,
+ 'roles' => ['@'],
+ ]
+ ],
+ ],
+ ], parent::behaviors());
+ }
- /**
- * Lists all Rule models.
- * @return mixed
- */
- public function actionIndex()
- {
- $searchModel=new RuleSearch();
- $dataProvider=$searchModel->search(Yii::$app->request->queryParams);
-
- return $this->render('index', [
- 'searchModel' => $searchModel,
- 'dataProvider' => $dataProvider,
- ]);
- }
+ /**
+ * Lists all Rule models.
+ * @return mixed
+ */
+ public function actionIndex()
+ {
+ $searchModel = new RuleSearch();
+ $dataProvider = $searchModel->search(Yii::$app->request->queryParams);
- /**
- * Displays a single Rule model.
- * @param integer $id
- * @return mixed
- * @throws NotFoundHttpException if the model cannot be found
- */
- public function actionView($id)
- {
- return $this->render('view', [
- 'model' => $this->findModel($id),
- ]);
- }
+ return $this->render('index', [
+ 'searchModel' => $searchModel,
+ 'dataProvider' => $dataProvider,
+ ]);
+ }
- /**
- * Creates a new Rule model.
- * If creation is successful, the browser will be redirected to the 'view' page.
- * @return mixed
- */
- public function actionCreate()
- {
- $model=new Rule();
-
- if($model->load(Yii::$app->request->post()) && $model->save())
- {
- return $this->redirect(['view', 'id' => $model->id]);
- }
-
- return $this->render('create', [
- 'model' => $model,
- ]);
- }
+ /**
+ * Displays a single Rule model.
+ * @param integer $id
+ * @return mixed
+ * @throws NotFoundHttpException if the model cannot be found
+ */
+ public function actionView($id)
+ {
+ return $this->render('view', [
+ 'model' => $this->findModel($id),
+ ]);
+ }
+
+ /**
+ * Creates a new Rule model.
+ * If creation is successful, the browser will be redirected to the 'view' page.
+ * @return mixed
+ */
+ public function actionCreate()
+ {
+ $model = new Rule();
- /**
- * Updates an existing Rule model.
- * If update is successful, the browser will be redirected to the 'view' page.
- * @param integer $id
- * @return mixed
- * @throws NotFoundHttpException if the model cannot be found
- */
- public function actionUpdate($id)
- {
- $model=$this->findModel($id);
-
- if($model->load(Yii::$app->request->post()) && $model->save())
- {
- return $this->redirect(['view', 'id' => $model->id]);
- }
-
- return $this->render('update', [
- 'model' => $model,
- ]);
+ if ($model->load(Yii::$app->request->post()) && $model->save()) {
+ return $this->redirect(['view', 'id' => $model->id]);
}
- /**
- * Deletes an existing Rule model.
- * If deletion is successful, the browser will be redirected to the 'index' page.
- * @param integer $id
- * @return mixed
- * @throws NotFoundHttpException if the model cannot be found
- */
- public function actionDelete($id)
- {
- $this->findModel($id)->delete();
-
- return $this->redirect(['index']);
+ return $this->render('create', [
+ 'model' => $model,
+ ]);
+ }
+
+ /**
+ * Updates an existing Rule model.
+ * If update is successful, the browser will be redirected to the 'view' page.
+ * @param integer $id
+ * @return mixed
+ * @throws NotFoundHttpException if the model cannot be found
+ */
+ public function actionUpdate($id)
+ {
+ $model = $this->findModel($id);
+
+ if ($model->load(Yii::$app->request->post()) && $model->save()) {
+ return $this->redirect(['view', 'id' => $model->id]);
}
- /**
- * Finds the Rule model based on its primary key value.
- * If the model is not found, a 404 HTTP exception will be thrown.
- * @param integer $id
- * @return Rule the loaded model
- * @throws NotFoundHttpException if the model cannot be found
- */
- protected function findModel($id)
- {
- if(($model=Rule::findOne($id)) !== null)
- {
- return $model;
- }
-
- throw new NotFoundHttpException('The requested page does not exist.');
+ return $this->render('update', [
+ 'model' => $model,
+ ]);
+ }
+
+ /**
+ * Deletes an existing Rule model.
+ * If deletion is successful, the browser will be redirected to the 'index' page.
+ * @param integer $id
+ * @return mixed
+ * @throws NotFoundHttpException if the model cannot be found
+ */
+ public function actionDelete($id)
+ {
+ $this->findModel($id)->delete();
+
+ return $this->redirect(['index']);
+ }
+
+ /**
+ * Finds the Rule model based on its primary key value.
+ * If the model is not found, a 404 HTTP exception will be thrown.
+ * @param integer $id
+ * @return Rule the loaded model
+ * @throws NotFoundHttpException if the model cannot be found
+ */
+ protected function findModel($id)
+ {
+ if (($model = Rule::findOne($id)) !== null) {
+ return $model;
}
+
+ throw new NotFoundHttpException('The requested page does not exist.');
+ }
}
diff --git a/backend/modules/content/controllers/VpnTemplateController.php b/backend/modules/content/controllers/VpnTemplateController.php
index df37b5639..4017314f5 100644
--- a/backend/modules/content/controllers/VpnTemplateController.php
+++ b/backend/modules/content/controllers/VpnTemplateController.php
@@ -15,107 +15,118 @@
*/
class VpnTemplateController extends \app\components\BaseController
{
- /**
- * {@inheritdoc}
- */
- public function behaviors()
- {
- return ArrayHelper::merge(parent::behaviors(),[]);
+ /**
+ * {@inheritdoc}
+ */
+ public function behaviors()
+ {
+ return ArrayHelper::merge([
+ 'access' => [
+ 'class' => \yii\filters\AccessControl::class,
+ 'rules' => [
+ '00filtered-actions' => [
+ 'actions' => ['update', 'delete'],
+ 'allow' => true,
+ 'roles' => ['@'],
+ ]
+ ],
+ ],
+ ], parent::behaviors());
+ }
+
+ /**
+ * Lists all VpnTemplate models.
+ * @return mixed
+ */
+ public function actionIndex()
+ {
+ $searchModel = new VpnTemplateSearch();
+ $dataProvider = $searchModel->search(Yii::$app->request->queryParams);
+
+ return $this->render('index', [
+ 'searchModel' => $searchModel,
+ 'dataProvider' => $dataProvider,
+ ]);
+ }
+
+ /**
+ * Displays a single VpnTemplate model.
+ * @param integer $id
+ * @return mixed
+ * @throws NotFoundHttpException if the model cannot be found
+ */
+ public function actionView($id)
+ {
+ return $this->render('view', [
+ 'model' => $this->findModel($id),
+ ]);
+ }
+
+ /**
+ * Creates a new VpnTemplate model.
+ * If creation is successful, the browser will be redirected to the 'view' page.
+ * @return mixed
+ */
+ public function actionCreate()
+ {
+ $model = new VpnTemplate();
+
+ if ($model->load(Yii::$app->request->post()) && $model->save()) {
+ return $this->redirect(['view', 'id' => $model->id]);
}
- /**
- * Lists all VpnTemplate models.
- * @return mixed
- */
- public function actionIndex()
- {
- $searchModel = new VpnTemplateSearch();
- $dataProvider = $searchModel->search(Yii::$app->request->queryParams);
-
- return $this->render('index', [
- 'searchModel' => $searchModel,
- 'dataProvider' => $dataProvider,
- ]);
+ return $this->render('create', [
+ 'model' => $model,
+ ]);
+ }
+
+ /**
+ * Updates an existing VpnTemplate model.
+ * If update is successful, the browser will be redirected to the 'view' page.
+ * @param integer $id
+ * @return mixed
+ * @throws NotFoundHttpException if the model cannot be found
+ */
+ public function actionUpdate($id)
+ {
+ $model = $this->findModel($id);
+
+ if ($model->load(Yii::$app->request->post()) && $model->save()) {
+ return $this->redirect(['view', 'id' => $model->id]);
}
- /**
- * Displays a single VpnTemplate model.
- * @param integer $id
- * @return mixed
- * @throws NotFoundHttpException if the model cannot be found
- */
- public function actionView($id)
- {
- return $this->render('view', [
- 'model' => $this->findModel($id),
- ]);
+ return $this->render('update', [
+ 'model' => $model,
+ ]);
+ }
+
+ /**
+ * Deletes an existing VpnTemplate model.
+ * If deletion is successful, the browser will be redirected to the 'index' page.
+ * @param integer $id
+ * @return mixed
+ * @throws NotFoundHttpException if the model cannot be found
+ */
+ public function actionDelete($id)
+ {
+ $this->findModel($id)->delete();
+
+ return $this->redirect(['index']);
+ }
+
+ /**
+ * Finds the VpnTemplate model based on its primary key value.
+ * If the model is not found, a 404 HTTP exception will be thrown.
+ * @param integer $id
+ * @return VpnTemplate the loaded model
+ * @throws NotFoundHttpException if the model cannot be found
+ */
+ protected function findModel($id)
+ {
+ if (($model = VpnTemplate::findOne($id)) !== null) {
+ return $model;
}
- /**
- * Creates a new VpnTemplate model.
- * If creation is successful, the browser will be redirected to the 'view' page.
- * @return mixed
- */
- public function actionCreate()
- {
- $model = new VpnTemplate();
-
- if ($model->load(Yii::$app->request->post()) && $model->save()) {
- return $this->redirect(['view', 'id' => $model->id]);
- }
-
- return $this->render('create', [
- 'model' => $model,
- ]);
- }
-
- /**
- * Updates an existing VpnTemplate model.
- * If update is successful, the browser will be redirected to the 'view' page.
- * @param integer $id
- * @return mixed
- * @throws NotFoundHttpException if the model cannot be found
- */
- public function actionUpdate($id)
- {
- $model = $this->findModel($id);
-
- if ($model->load(Yii::$app->request->post()) && $model->save()) {
- return $this->redirect(['view', 'id' => $model->id]);
- }
-
- return $this->render('update', [
- 'model' => $model,
- ]);
- }
-
- /**
- * Deletes an existing VpnTemplate model.
- * If deletion is successful, the browser will be redirected to the 'index' page.
- * @param integer $id
- * @return mixed
- * @throws NotFoundHttpException if the model cannot be found
- */
- public function actionDelete($id)
- {
- $this->findModel($id)->delete();
-
- return $this->redirect(['index']);
- }
-
- /**
- * Finds the VpnTemplate model based on its primary key value.
- * If the model is not found, a 404 HTTP exception will be thrown.
- * @param integer $id
- * @return VpnTemplate the loaded model
- * @throws NotFoundHttpException if the model cannot be found
- */
- protected function findModel($id)
- {
- if (($model = VpnTemplate::findOne($id)) !== null) {
- return $model;
- }
-
- throw new NotFoundHttpException(Yii::t('app', 'The requested page does not exist.'));
- }
+ throw new NotFoundHttpException(Yii::t('app', 'The requested page does not exist.'));
+ }
}
diff --git a/backend/modules/frontend/actions/player/MailAction.php b/backend/modules/frontend/actions/player/MailAction.php
index e9c5e9901..3b5de091d 100644
--- a/backend/modules/frontend/actions/player/MailAction.php
+++ b/backend/modules/frontend/actions/player/MailAction.php
@@ -10,6 +10,7 @@
use app\modules\frontend\models\PlayerSsl;
use app\modules\frontend\models\PlayerSearch;
use app\modules\settings\models\Sysconfig;
+use yii\base\UserException;
use yii\helpers\Html;
class MailAction extends \yii\base\Action
@@ -22,27 +23,17 @@ public function run(int $id, $baseURL = "https://echoctf.red/activate/")
{
// Get innactive players
$player = $this->controller->findModel($id);
- if ($player->status == 10)
- {
+ if ($player->status == 10) {
\Yii::$app->getSession()->setFlash('warning', Yii::t('app', 'Player already active skipping mail.'));
- }
- elseif ($player->status == 9)
- {
- if (\Yii::$app->sys->player_require_approval === true && $player->approval > 0 && $player->approval <= 2)
- {
+ } elseif ($player->status == 9) {
+ if (\Yii::$app->sys->player_require_approval === true && $player->approval > 0 && $player->approval <= 2) {
$this->approvalMail($player);
- }
- elseif (\Yii::$app->sys->player_require_approval === true && $player->approval > 2 && $player->approval <= 4)
- {
+ } elseif (\Yii::$app->sys->player_require_approval === true && $player->approval > 2 && $player->approval <= 4) {
$this->rejectionMail($player);
- }
- elseif (\Yii::$app->sys->player_require_approval !== true)
- {
+ } elseif (\Yii::$app->sys->player_require_approval !== true) {
$this->verificationMail($player);
}
- }
- elseif ($player->status == 0)
- {
+ } elseif ($player->status == 0) {
$this->rejectionMail($player);
}
@@ -60,12 +51,11 @@ public function run(int $id, $baseURL = "https://echoctf.red/activate/")
private function rejectionMail($player)
{
try {
- $emailtpl=\app\modules\content\models\EmailTemplate::findOne(['name' => 'rejectVerify']);
+ $emailtpl = \app\modules\content\models\EmailTemplate::findOne(['name' => 'rejectVerify']);
$contentHtml = $this->controller->renderPhpContent("?>" . $emailtpl->html, ['user' => $player]);
$contentTxt = $this->controller->renderPhpContent("?>" . $emailtpl->txt, ['user' => $player]);
- $subject=Yii::t('app', '{event_name} Account rejected', ['event_name' => trim(Yii::$app->sys->event_name)]);
- if(!$player->mail($subject,$contentHtml,$contentTxt))
- {
+ $subject = Yii::t('app', '{event_name} Account rejected', ['event_name' => trim(Yii::$app->sys->event_name)]);
+ if (!$player->mail($subject, $contentHtml, $contentTxt)) {
throw new \Exception('Could not send mail');
}
@@ -85,15 +75,18 @@ private function rejectionMail($player)
*/
private function approvalMail($player)
{
+ if ($player->verification_token == null) {
+ throw new UserException("The user has no token to mail");
+ }
+
try {
$activationURL = sprintf("https://%s/verify-email?token=%s", \Yii::$app->sys->offense_domain, $player->verification_token);
- $emailtpl=\app\modules\content\models\EmailTemplate::findOne(['name' => 'emailVerify']);
- $contentHtml = $this->controller->renderPhpContent("?>" . $emailtpl->html, ['user' => $player,'verifyLink'=>$activationURL]);
- $contentTxt = $this->controller->renderPhpContent("?>" . $emailtpl->txt, ['user' => $player,'verifyLink'=>$activationURL]);
- $subject=Yii::t('app', '{event_name} Account approved', ['event_name' => trim(Yii::$app->sys->event_name)]);
+ $emailtpl = \app\modules\content\models\EmailTemplate::findOne(['name' => 'emailVerify']);
+ $contentHtml = $this->controller->renderPhpContent("?>" . $emailtpl->html, ['user' => $player, 'verifyLink' => $activationURL]);
+ $contentTxt = $this->controller->renderPhpContent("?>" . $emailtpl->txt, ['user' => $player, 'verifyLink' => $activationURL]);
+ $subject = Yii::t('app', '{event_name} Account approved', ['event_name' => trim(Yii::$app->sys->event_name)]);
- if(!$player->mail($subject,$contentHtml,$contentTxt))
- {
+ if (!$player->mail($subject, $contentHtml, $contentTxt)) {
return;
}
@@ -112,15 +105,18 @@ private function approvalMail($player)
*/
private function verificationMail($player)
{
+ if ($player->verification_token == null) {
+ throw new UserException("The user has no token to mail");
+ }
+
try {
$activationURL = sprintf("https://%s/verify-email?token=%s", \Yii::$app->sys->offense_domain, $player->verification_token);
- $emailtpl=\app\modules\content\models\EmailTemplate::findOne(['name' => 'emailVerify']);
- $contentHtml = $this->controller->renderPhpContent("?>" . $emailtpl->html, ['user' => $player,'verifyLink'=>$activationURL]);
- $contentTxt = $this->controller->renderPhpContent("?>" . $emailtpl->txt, ['user' => $player,'verifyLink'=>$activationURL]);
- $subject=Yii::t('app', 'Account registration for {event_name}', ['event_name' => trim(Yii::$app->sys->event_name)]);
+ $emailtpl = \app\modules\content\models\EmailTemplate::findOne(['name' => 'emailVerify']);
+ $contentHtml = $this->controller->renderPhpContent("?>" . $emailtpl->html, ['user' => $player, 'verifyLink' => $activationURL]);
+ $contentTxt = $this->controller->renderPhpContent("?>" . $emailtpl->txt, ['user' => $player, 'verifyLink' => $activationURL]);
+ $subject = Yii::t('app', 'Account registration for {event_name}', ['event_name' => trim(Yii::$app->sys->event_name)]);
- if(!$player->mail($subject,$contentHtml,$contentTxt))
- {
+ if (!$player->mail($subject, $contentHtml, $contentTxt)) {
throw new \Exception('Could not send mail');
}
@@ -129,5 +125,4 @@ private function verificationMail($player)
\Yii::$app->getSession()->setFlash('error', Yii::t('app', 'Failed to mail player. {exception}', ['exception' => Html::encode($e->getMessage())]));
}
}
-
}
diff --git a/backend/modules/frontend/controllers/PlayerController.php b/backend/modules/frontend/controllers/PlayerController.php
index 2d8686403..30d8f6962 100644
--- a/backend/modules/frontend/controllers/PlayerController.php
+++ b/backend/modules/frontend/controllers/PlayerController.php
@@ -32,7 +32,7 @@ public function behaviors()
'class' => \yii\filters\AccessControl::class,
'rules' => [
'00filtered-actions' => [
- 'actions' => ['mail', 'approve', 'reject', 'export'],
+ 'actions' => ['mail', 'approve', 'reject', 'export', 'notify', 'set-deleted', 'disconnect-vpn', 'generate-ssl', 'ajax-search','mail-filtered'],
'allow' => true,
'roles' => ['@'],
]
@@ -616,11 +616,13 @@ public function actionMailFiltered()
{
$searchModel = new PlayerSearch();
$query = $searchModel->search(['PlayerSearch' => Yii::$app->request->post()]);
+ $query->query->innerJoinWith('emailToken', false);
+ $query->query->andFilterWhere(['IS NOT', 'emailToken.token', NULL]);
$query->query->andFilterWhere([
'player.approval' => [1, 3],
]);
- //$query->pagination = false;
- $query->pagination = ['pageSize' => 5];
+ $query->pagination = false;
+ //$query->pagination = ['pageSize' => 5];
if (intval($query->count) === intval(Player::find()->count())) {
Yii::$app->session->setFlash('error', Yii::t('app', 'You have attempted to mail all the players.'));
return $this->redirect(['index']);
@@ -708,7 +710,7 @@ public function actionAjaxSearch($term, $load = false, $active = null, $status =
function ($model) {
return [
'id' => $model->id,
- 'pid'=>$model->profile->id,
+ 'pid' => $model->profile->id,
'label' => sprintf("(id: %d / pid: %d) %s <%s>%s", $model->id, $model->profile->id, $model->username, $model->email, $model->status === 10 ? '' : ' (innactive)'),
];
}
@@ -748,7 +750,7 @@ public function actionNotify($id)
private function notifyLogic($player, $notificationModel, $ovpn = false, $online = false)
{
- if ($ovpn && $player->playerLast->vpn_local_address===null)
+ if ($ovpn && $player->playerLast->vpn_local_address === null)
return null;
if ($online && !boolval($player->online))
return null;
diff --git a/backend/modules/frontend/controllers/ProfileController.php b/backend/modules/frontend/controllers/ProfileController.php
index f23c4b624..9fba53c01 100644
--- a/backend/modules/frontend/controllers/ProfileController.php
+++ b/backend/modules/frontend/controllers/ProfileController.php
@@ -32,7 +32,7 @@ public function behaviors()
'class' => \yii\filters\AccessControl::class,
'rules' => [
'00filtered-actions'=>[
- 'actions' => ['view-full','target-progress','score-monthly','headshots','vpn-history','spin-history','notifications'],
+ 'actions' => ['view-full','target-progress','score-monthly','headshots','vpn-history','spin-history','notifications','stream-lag','vpn-history-duplicates'],
'allow' => true,
'roles' => ['@'],
]
diff --git a/backend/modules/frontend/controllers/TeamController.php b/backend/modules/frontend/controllers/TeamController.php
index 604253131..39a3f8067 100644
--- a/backend/modules/frontend/controllers/TeamController.php
+++ b/backend/modules/frontend/controllers/TeamController.php
@@ -24,7 +24,17 @@ class TeamController extends \app\components\BaseController
*/
public function behaviors()
{
- return ArrayHelper::merge(parent::behaviors(), [
+ return ArrayHelper::merge([
+ 'access' => [
+ 'class' => \yii\filters\AccessControl::class,
+ 'rules' => [
+ '00filtered-actions' => [
+ 'actions' => ['free-player-ajax-search','notify','ajax-search'],
+ 'allow' => true,
+ 'roles' => ['@'],
+ ]
+ ],
+ ],
'rules' => [
'class' => 'yii\filters\AjaxFilter',
'only' => ['free-player-ajax-search']
@@ -36,7 +46,7 @@ public function behaviors()
'repopulate-stream' => ['POST'],
],
],
- ]);
+ ], parent::behaviors());
}
/**
@@ -187,13 +197,11 @@ public function actionToggleAcademic($id)
$trans = Yii::$app->db->beginTransaction();
try {
$model->updateAttributes(['academic' => ($model->academic + 1) % \Yii::$app->sys->academic_grouping]);
- foreach($model->teamPlayers as $p)
- {
- $p->updateAttributes(['academic'=>$model->academic]);
+ foreach ($model->teamPlayers as $p) {
+ $p->updateAttributes(['academic' => $model->academic]);
}
$trans->commit();
\Yii::$app->getSession()->setFlash('success', Yii::t('app', 'Team changed academic grouping.'));
-
} catch (\Exception $e) {
$trans->rollBack();
\Yii::$app->getSession()->setFlash('error', Yii::t('app', 'Failed to update academic grouping for team'));
diff --git a/backend/modules/frontend/models/Player.php b/backend/modules/frontend/models/Player.php
index 97aec5de9..60782458f 100644
--- a/backend/modules/frontend/models/Player.php
+++ b/backend/modules/frontend/models/Player.php
@@ -54,6 +54,7 @@ public function getAuthKey()
public function saveWithSsl()
{
if (!$this->save()) {
+ Yii::error($this->getErrorSummary(true));
return false;
}
@@ -63,6 +64,7 @@ public function saveWithSsl()
if ($playerSsl->save()) {
return $playerSsl->refresh();
}
+ Yii::error($playerSsl->getErrorSummary(true));
return false;
}
@@ -144,6 +146,11 @@ public function createTeam($team_name, $approved)
if (!$tp->save())
echo Yii::t('app', "Error saving team player\n");
+ $ti = new \app\modules\frontend\models\TeamInvite(['team_id' => $team->id, 'token' => Yii::$app->security->generateRandomString(8)]);
+ if (!$ti->save()) {
+ echo Yii::t('app', "Error saving team invite\n");
+ Yii::error($ti->getErrorSummary(true));
+ }
}
/**
diff --git a/backend/modules/frontend/models/PlayerAR.php b/backend/modules/frontend/models/PlayerAR.php
index 878030d40..5675a39f6 100644
--- a/backend/modules/frontend/models/PlayerAR.php
+++ b/backend/modules/frontend/models/PlayerAR.php
@@ -526,7 +526,22 @@ public function getAuthKey()
*/
public function getApiToken()
{
- return $this->hasOne(PlayerToken::class, ['player_id' => 'id'])->andWhere(['type' => 'API']);
+ return $this->hasOne(PlayerToken::class, ['player_id' => 'id'])->from(['apiToken' => PlayerToken::tableName()])->andWhere(['apiToken.type' => 'API']);
}
+ /**
+ * @return \yii\db\ActiveQuery
+ */
+ public function getEmailToken()
+ {
+ return $this->hasOne(PlayerToken::class, ['player_id' => 'id'])->from(['emailToken' => PlayerToken::tableName()])->andWhere(['emailToken.type' => 'email_verification']);
+ }
+
+ /**
+ * @return \yii\db\ActiveQuery
+ */
+ public function getPasswordResetToken()
+ {
+ return $this->hasOne(PlayerToken::class, ['player_id' => 'id'])->from(['passwordResetToken' => PlayerToken::tableName()])->andWhere(['passwordResetToken.type' => 'password_reset']);
+ }
}
diff --git a/backend/modules/frontend/models/PlayerSsl.php b/backend/modules/frontend/models/PlayerSsl.php
index 6e8bdae84..0cec4d946 100644
--- a/backend/modules/frontend/models/PlayerSsl.php
+++ b/backend/modules/frontend/models/PlayerSsl.php
@@ -107,7 +107,9 @@ public function generate() {
$CAprivkey=array("file://".$tmpCAprivkey, null);
file_put_contents($tmpCAprivkey, Yii::$app->sys->{'CA.key'});
file_put_contents($tmpCAcert, Yii::$app->sys->{'CA.crt'});
- $serial=time();
+ do {
+ $serial=time();
+ } while (self::findOne(['serial'=>$serial])!=null);
$x509=openssl_csr_sign($csr, $CAcert, $CAprivkey, 3650, array('digest_alg'=>'sha256', 'config'=>Yii::getAlias('@appconfig').'/CA.cnf', 'x509_extensions'=>'usr_cert'), $serial);
openssl_csr_export($csr, $csrout);
openssl_x509_export($x509, $certout, false);
diff --git a/backend/modules/frontend/models/Team.php b/backend/modules/frontend/models/Team.php
index ce40c889d..10cf9bb84 100644
--- a/backend/modules/frontend/models/Team.php
+++ b/backend/modules/frontend/models/Team.php
@@ -22,6 +22,7 @@
* @property Player $owner
* @property TeamPlayer[] $teamPlayers
* @property Player[] $players
+ * @property string[] $approvedMemberIPs
*/
class Team extends \yii\db\ActiveRecord
{
@@ -98,11 +99,12 @@ public function getTeamPlayers()
public function getInstances()
{
- return $this->hasMany(\app\modules\infrastructure\models\TargetInstance::class, ['player_id' => 'player_id'])
- ->via('teamPlayers', function($query) {
- $query->andWhere(['approved' => 1]);
- });
+ return $this->hasMany(\app\modules\infrastructure\models\TargetInstance::class, ['player_id' => 'player_id'])
+ ->via('teamPlayers', function ($query) {
+ $query->andWhere(['approved' => 1]);
+ });
}
+
/**
* @return \yii\db\ActiveQuery
*/
@@ -111,6 +113,22 @@ public function getApprovedMembers()
return $this->hasMany(TeamPlayer::class, ['team_id' => 'id'])->andWhere(['approved' => 1]);
}
+ /**
+ * Get array of all approved members currently online
+ *
+ * @return array
+ */
+ public function getApprovedMemberIPs()
+ {
+ $ips=[];
+ foreach ($this->approvedMembers as $tp) {
+ if ((int)$tp->player->last->vpn_local_address !== 0) {
+ $ips[] = long2ip($tp->player->last->vpn_local_address);
+ }
+ }
+ return $ips;
+ }
+
/**
* @return \yii\db\ActiveQuery
*/
@@ -197,6 +215,6 @@ public function getInvite()
*/
public function repopulateStream()
{
- return \Yii::$app->db->createCommand('CALL repopulate_team_stream(:tid)',[':tid'=>$this->id])->execute();
+ return \Yii::$app->db->createCommand('CALL repopulate_team_stream(:tid)', [':tid' => $this->id])->execute();
}
}
diff --git a/backend/modules/frontend/views/player/index.php b/backend/modules/frontend/views/player/index.php
index 8b684d02c..9238f5ae0 100644
--- a/backend/modules/frontend/views/player/index.php
+++ b/backend/modules/frontend/views/player/index.php
@@ -22,7 +22,7 @@
= Html::a('Create Player', ['create'], ['class' => 'btn btn-success']) ?>
= Html::a('Import Players', ['import'], ['class' => 'btn btn-info']) ?>
- = Html::a('Export Full Players', ['export'], ['class' => 'btn','style' => 'background: #4040bf; color: white;',]) ?>
+ = Html::a('Export Full Players', ['export'], ['class' => 'btn', 'style' => 'background: #4040bf; color: white;',]) ?>
= Html::a(Yii::t('app', 'Fail Validate'), ['fail-validation'], [
'class' => 'btn',
'style' => 'background: #4d246f; color: white;',
@@ -45,7 +45,7 @@
'rowOptions' => function ($model, $key, $index, $grid) {
// $model is the current data model being rendered
// check your condition in the if like `if($model->hasMedicalRecord())` which could be a method of model class which checks for medical records.
- $tmpObj = clone ($model);
+ $tmpObj = clone($model);
$tmpObj->scenario = 'validator';
if (!$tmpObj->validate()) {
unset($tmpObj);
@@ -112,9 +112,12 @@
[
'attribute' => 'approval',
'filter' => $searchModel::APPROVAL,
+ 'format' => 'html',
'visible' => Yii::$app->sys->player_require_approval === true,
'value' => function ($model) {
- return $model::APPROVAL[$model->approval];
+ if ($model->status === 10)
+ return "(" . $model::APPROVAL[$model->approval] . ") ";
+ return "" . $model::APPROVAL[$model->approval] . " ";
}
],
@@ -138,7 +141,7 @@
return false;
},
'disconnect-vpn' => function ($model) {
- if ($model->last->vpn_local_address !== null && $model->disconnectQueue===null) return true;
+ if ($model->last->vpn_local_address !== null && $model->disconnectQueue === null) return true;
return false;
},
'view' => function ($model) {
@@ -157,7 +160,7 @@
return false;
},
'mail' => function ($model) {
- if ($model->status == 10 || $model->approval == 0) return false;
+ if ($model->status == 10 || $model->status == 0 || $model->approval == 0 || ( $model->emailToken == null && $model->passwordResetToken == null)) return false;
return true;
},
'delete' => function ($model) {
diff --git a/backend/modules/gameplay/controllers/ChallengeController.php b/backend/modules/gameplay/controllers/ChallengeController.php
index 893a293c5..281693787 100644
--- a/backend/modules/gameplay/controllers/ChallengeController.php
+++ b/backend/modules/gameplay/controllers/ChallengeController.php
@@ -22,167 +22,171 @@ class ChallengeController extends \app\components\BaseController
/**
* {@inheritdoc}
*/
- public function behaviors()
- {
- return ArrayHelper::merge(parent::behaviors(),[]);
- }
+ public function behaviors()
+ {
+ return ArrayHelper::merge(parent::behaviors(), [
+ 'access' => [
+ 'class' => \yii\filters\AccessControl::class,
+ 'rules' => [
+ 'authActions' => [
+ 'allow' => true,
+ 'actions' => ['index', 'view'],
+ 'roles' => ['@'],
+ 'matchCallback' => function () {
+ return \Yii::$app->user->identity->isAdmin;
+ },
+ ],
+ ],
+ ],
+ ]);
+ }
- /**
- * Lists all Challenge models.
- * @return mixed
- */
- public function actionIndex()
- {
- $searchModel=new ChallengeSearch();
- $dataProvider=$searchModel->search(Yii::$app->request->queryParams);
-
- return $this->render('index', [
- 'searchModel' => $searchModel,
- 'dataProvider' => $dataProvider,
- ]);
- }
+ /**
+ * Lists all Challenge models.
+ * @return mixed
+ */
+ public function actionIndex()
+ {
+ $searchModel = new ChallengeSearch();
+ $dataProvider = $searchModel->search(Yii::$app->request->queryParams);
- /**
- * Displays a single Challenge model.
- * @param integer $id
- * @return mixed
- * @throws NotFoundHttpException if the model cannot be found
- */
- public function actionView($id)
- {
- $query=Question::find()->joinWith('challenge');
-
- $query->select('question.*,(SELECT COUNT(question_id) FROM player_question WHERE question.id=player_question.question_id) as answered');
- // add conditions that should always apply here
-
- $dataProvider=new ActiveDataProvider([
- 'query' => $query,
- ]);
- $query->andFilterWhere([
- 'question.challenge_id' => $id,
- ]);
-
- $dataProvider->setSort([
- 'defaultOrder' => ['weight' => SORT_ASC,'id'=>SORT_ASC],
- 'attributes' => array_merge(
- $dataProvider->getSort()->attributes,
- [
- 'challengename' => [
- 'asc' => ['challengename' => SORT_ASC],
- 'desc' => ['challengename' => SORT_DESC],
- ],
- 'answered' => [
- 'asc' => ['answered' => SORT_ASC],
- 'desc' => ['answered' => SORT_DESC],
- ],
- ]
- ),
- ]);
-
- return $this->render('view', [
- 'model' => $this->findModel($id),
- 'questionProvider'=>$dataProvider,
- ]);
- }
+ return $this->render('index', [
+ 'searchModel' => $searchModel,
+ 'dataProvider' => $dataProvider,
+ ]);
+ }
- /**
- * Creates a new Challenge model.
- * If creation is successful, the browser will be redirected to the 'view' page.
- * @return mixed
- */
- public function actionCreate()
- {
- $model=new Challenge();
-
- if($model->load(Yii::$app->request->post()) && $model->save())
- {
- $model->file=UploadedFile::getInstance($model, 'file');
- try
- {
- if($model->file)
- {
- if(trim($model->filename)==='')
- {
- $model->filename=$model->id;
- $model->updateAttributes(['filename'=>$model->id]);
- }
- $model->file->saveAs(Yii::getAlias(Yii::$app->sys->challenge_home).'/'.$model->filename);
- }
- Yii::$app->session->addFlash('success', Yii::t('app','Challenge [{name}] created',['name'=>Html::encode($model->name)]));
- Yii::$app->session->addFlash('warning', Yii::t('app','Don\'t forget to create a question for the challenge.'));
- }
- catch(\Exception $e)
- {
- Yii::$app->session->setFlash('error', Yii::t('app','Failed to create challenge [{name}]',['name'=>Html::encode($model->name)]));
- }
- return $this->redirect(['view', 'id' => $model->id]);
- }
+ /**
+ * Displays a single Challenge model.
+ * @param integer $id
+ * @return mixed
+ * @throws NotFoundHttpException if the model cannot be found
+ */
+ public function actionView($id)
+ {
+ $query = Question::find()->joinWith('challenge');
+
+ $query->select('question.*,(SELECT COUNT(question_id) FROM player_question WHERE question.id=player_question.question_id) as answered');
+ // add conditions that should always apply here
+
+ $dataProvider = new ActiveDataProvider([
+ 'query' => $query,
+ ]);
+ $query->andFilterWhere([
+ 'question.challenge_id' => $id,
+ ]);
+
+ $dataProvider->setSort([
+ 'defaultOrder' => ['weight' => SORT_ASC, 'id' => SORT_ASC],
+ 'attributes' => array_merge(
+ $dataProvider->getSort()->attributes,
+ [
+ 'challengename' => [
+ 'asc' => ['challengename' => SORT_ASC],
+ 'desc' => ['challengename' => SORT_DESC],
+ ],
+ 'answered' => [
+ 'asc' => ['answered' => SORT_ASC],
+ 'desc' => ['answered' => SORT_DESC],
+ ],
+ ]
+ ),
+ ]);
+
+ return $this->render('view', [
+ 'model' => $this->findModel($id),
+ 'questionProvider' => $dataProvider,
+ ]);
+ }
- return $this->render('create', [
- 'model' => $model,
- ]);
+ /**
+ * Creates a new Challenge model.
+ * If creation is successful, the browser will be redirected to the 'view' page.
+ * @return mixed
+ */
+ public function actionCreate()
+ {
+ $model = new Challenge();
+
+ if ($model->load(Yii::$app->request->post()) && $model->save()) {
+ $model->file = UploadedFile::getInstance($model, 'file');
+ try {
+ if ($model->file) {
+ if (trim($model->filename) === '') {
+ $model->filename = $model->id;
+ $model->updateAttributes(['filename' => $model->id]);
+ }
+ $model->file->saveAs(Yii::getAlias(Yii::$app->sys->challenge_home) . '/' . $model->filename);
+ }
+ Yii::$app->session->addFlash('success', Yii::t('app', 'Challenge [{name}] created', ['name' => Html::encode($model->name)]));
+ Yii::$app->session->addFlash('warning', Yii::t('app', 'Don\'t forget to create a question for the challenge.'));
+ } catch (\Exception $e) {
+ Yii::$app->session->setFlash('error', Yii::t('app', 'Failed to create challenge [{name}]', ['name' => Html::encode($model->name)]));
+ }
+ return $this->redirect(['view', 'id' => $model->id]);
}
- /**
- * Updates an existing Challenge model.
- * If update is successful, the browser will be redirected to the 'view' page.
- * @param integer $id
- * @return mixed
- * @throws NotFoundHttpException if the model cannot be found
- */
- public function actionUpdate($id)
- {
- $model=$this->findModel($id);
-
- if($model->load(Yii::$app->request->post()) && $model->save())
- {
- $model->file=UploadedFile::getInstance($model, 'file');
- if($model->file !== null)
- {
- if(trim($model->filename)==='')
- {
- $model->filename=$model->id;
- $model->updateAttributes(['filename'=>$model->id]);
- }
- $model->file->saveAs(Yii::getAlias(Yii::$app->sys->challenge_home).'/'.$model->filename);
- }
- Yii::$app->session->addFlash('success', Yii::t('app','Challenge [{name}] updated',['name'=>Html::encode($model->name)]));
- return $this->redirect(['view', 'id' => $model->id]);
- }
+ return $this->render('create', [
+ 'model' => $model,
+ ]);
+ }
- return $this->render('update', [
- 'model' => $model,
- ]);
+ /**
+ * Updates an existing Challenge model.
+ * If update is successful, the browser will be redirected to the 'view' page.
+ * @param integer $id
+ * @return mixed
+ * @throws NotFoundHttpException if the model cannot be found
+ */
+ public function actionUpdate($id)
+ {
+ $model = $this->findModel($id);
+
+ if ($model->load(Yii::$app->request->post()) && $model->save()) {
+ $model->file = UploadedFile::getInstance($model, 'file');
+ if ($model->file !== null) {
+ if (trim($model->filename) === '') {
+ $model->filename = $model->id;
+ $model->updateAttributes(['filename' => $model->id]);
+ }
+ $model->file->saveAs(Yii::getAlias(Yii::$app->sys->challenge_home) . '/' . $model->filename);
+ }
+ Yii::$app->session->addFlash('success', Yii::t('app', 'Challenge [{name}] updated', ['name' => Html::encode($model->name)]));
+ return $this->redirect(['view', 'id' => $model->id]);
}
- /**
- * Deletes an existing Challenge model.
- * If deletion is successful, the browser will be redirected to the 'index' page.
- * @param integer $id
- * @return mixed
- * @throws NotFoundHttpException if the model cannot be found
- */
- public function actionDelete($id)
- {
- $this->findModel($id)->delete();
-
- return $this->redirect(['index']);
- }
+ return $this->render('update', [
+ 'model' => $model,
+ ]);
+ }
- /**
- * Finds the Challenge model based on its primary key value.
- * If the model is not found, a 404 HTTP exception will be thrown.
- * @param integer $id
- * @return Challenge the loaded model
- * @throws NotFoundHttpException if the model cannot be found
- */
- protected function findModel($id)
- {
- if(($model=Challenge::findOne($id)) !== null)
- {
- return $model;
- }
+ /**
+ * Deletes an existing Challenge model.
+ * If deletion is successful, the browser will be redirected to the 'index' page.
+ * @param integer $id
+ * @return mixed
+ * @throws NotFoundHttpException if the model cannot be found
+ */
+ public function actionDelete($id)
+ {
+ $this->findModel($id)->delete();
+
+ return $this->redirect(['index']);
+ }
- throw new NotFoundHttpException(Yii::t('app','The requested page does not exist.'));
+ /**
+ * Finds the Challenge model based on its primary key value.
+ * If the model is not found, a 404 HTTP exception will be thrown.
+ * @param integer $id
+ * @return Challenge the loaded model
+ * @throws NotFoundHttpException if the model cannot be found
+ */
+ protected function findModel($id)
+ {
+ if (($model = Challenge::findOne($id)) !== null) {
+ return $model;
}
+
+ throw new NotFoundHttpException(Yii::t('app', 'The requested page does not exist.'));
+ }
}
diff --git a/backend/modules/gameplay/controllers/QuestionController.php b/backend/modules/gameplay/controllers/QuestionController.php
index d02804c92..83a49e414 100644
--- a/backend/modules/gameplay/controllers/QuestionController.php
+++ b/backend/modules/gameplay/controllers/QuestionController.php
@@ -17,113 +17,124 @@ class QuestionController extends \app\components\BaseController
/**
* {@inheritdoc}
*/
- public function behaviors()
- {
- return ArrayHelper::merge(parent::behaviors(),[]);
- }
+ public function behaviors()
+ {
+ return ArrayHelper::merge(parent::behaviors(), [
+ 'access' => [
+ 'class' => \yii\filters\AccessControl::class,
+ 'rules' => [
+ 'authActions' => [
+ 'allow' => true,
+ 'actions' => ['index', 'view'],
+ 'roles' => ['@'],
+ 'matchCallback' => function () {
+ return \Yii::$app->user->identity->isAdmin;
+ },
+ ],
+ ],
+ ],
+
+ ]);
+ }
- /**
- * Lists all Question models.
- * @return mixed
- */
- public function actionIndex()
- {
- $searchModel=new QuestionSearch();
- $dataProvider=$searchModel->search(Yii::$app->request->queryParams);
-
- return $this->render('index', [
- 'searchModel' => $searchModel,
- 'dataProvider' => $dataProvider,
- ]);
- }
+ /**
+ * Lists all Question models.
+ * @return mixed
+ */
+ public function actionIndex()
+ {
+ $searchModel = new QuestionSearch();
+ $dataProvider = $searchModel->search(Yii::$app->request->queryParams);
- /**
- * Displays a single Question model.
- * @param integer $id
- * @return mixed
- * @throws NotFoundHttpException if the model cannot be found
- */
- public function actionView($id)
- {
- return $this->render('view', [
- 'model' => $this->findModel($id),
- ]);
- }
+ return $this->render('index', [
+ 'searchModel' => $searchModel,
+ 'dataProvider' => $dataProvider,
+ ]);
+ }
- /**
- * Creates a new Question model.
- * If creation is successful, the browser will be redirected to the 'view' page.
- * @return mixed
- */
- public function actionCreate()
- {
- $model=new Question();
- if(\app\modules\gameplay\models\Challenge::find()->count() == 0)
- {
- // If there are no player redirect to create player page
- Yii::$app->session->setFlash('warning', Yii::t('app',"No Challenges found create one first."));
- return $this->redirect(['/frontend/challenge/create']);
- }
-
- if($model->load(Yii::$app->request->post()) && $model->save())
- {
- return $this->redirect(['view', 'id' => $model->id]);
- }
-
- return $this->render('create', [
- 'model' => $model,
- ]);
+ /**
+ * Displays a single Question model.
+ * @param integer $id
+ * @return mixed
+ * @throws NotFoundHttpException if the model cannot be found
+ */
+ public function actionView($id)
+ {
+ return $this->render('view', [
+ 'model' => $this->findModel($id),
+ ]);
+ }
+
+ /**
+ * Creates a new Question model.
+ * If creation is successful, the browser will be redirected to the 'view' page.
+ * @return mixed
+ */
+ public function actionCreate()
+ {
+ $model = new Question();
+ if (\app\modules\gameplay\models\Challenge::find()->count() == 0) {
+ // If there are no player redirect to create player page
+ Yii::$app->session->setFlash('warning', Yii::t('app', "No Challenges found create one first."));
+ return $this->redirect(['/frontend/challenge/create']);
}
- /**
- * Updates an existing Question model.
- * If update is successful, the browser will be redirected to the 'view' page.
- * @param integer $id
- * @return mixed
- * @throws NotFoundHttpException if the model cannot be found
- */
- public function actionUpdate($id)
- {
- $model=$this->findModel($id);
-
- if($model->load(Yii::$app->request->post()) && $model->save())
- {
- return $this->redirect(['view', 'id' => $model->id]);
- }
-
- return $this->render('update', [
- 'model' => $model,
- ]);
+ if ($model->load(Yii::$app->request->post()) && $model->save()) {
+ return $this->redirect(['view', 'id' => $model->id]);
}
- /**
- * Deletes an existing Question model.
- * If deletion is successful, the browser will be redirected to the 'index' page.
- * @param integer $id
- * @return mixed
- * @throws NotFoundHttpException if the model cannot be found
- */
- public function actionDelete($id)
- {
- $this->findModel($id)->delete();
-
- return $this->redirect(['index']);
+ return $this->render('create', [
+ 'model' => $model,
+ ]);
+ }
+
+ /**
+ * Updates an existing Question model.
+ * If update is successful, the browser will be redirected to the 'view' page.
+ * @param integer $id
+ * @return mixed
+ * @throws NotFoundHttpException if the model cannot be found
+ */
+ public function actionUpdate($id)
+ {
+ $model = $this->findModel($id);
+
+ if ($model->load(Yii::$app->request->post()) && $model->save()) {
+ return $this->redirect(['view', 'id' => $model->id]);
}
- /**
- * Finds the Question model based on its primary key value.
- * If the model is not found, a 404 HTTP exception will be thrown.
- * @param integer $id
- * @return Question the loaded model
- * @throws NotFoundHttpException if the model cannot be found
- */
- protected function findModel($id)
- {
- if(($model=Question::findOne($id)) !== null)
- {
- return $model;
- }
-
- throw new NotFoundHttpException(Yii::t('app','The requested page does not exist.'));
+ return $this->render('update', [
+ 'model' => $model,
+ ]);
+ }
+
+ /**
+ * Deletes an existing Question model.
+ * If deletion is successful, the browser will be redirected to the 'index' page.
+ * @param integer $id
+ * @return mixed
+ * @throws NotFoundHttpException if the model cannot be found
+ */
+ public function actionDelete($id)
+ {
+ $this->findModel($id)->delete();
+
+ return $this->redirect(['index']);
+ }
+
+ /**
+ * Finds the Question model based on its primary key value.
+ * If the model is not found, a 404 HTTP exception will be thrown.
+ * @param integer $id
+ * @return Question the loaded model
+ * @throws NotFoundHttpException if the model cannot be found
+ */
+ protected function findModel($id)
+ {
+ if (($model = Question::findOne($id)) !== null) {
+ return $model;
}
+
+ throw new NotFoundHttpException(Yii::t('app', 'The requested page does not exist.'));
+ }
}
diff --git a/backend/modules/gameplay/controllers/TreasureController.php b/backend/modules/gameplay/controllers/TreasureController.php
index 8b25e255a..9937f722e 100644
--- a/backend/modules/gameplay/controllers/TreasureController.php
+++ b/backend/modules/gameplay/controllers/TreasureController.php
@@ -19,7 +19,21 @@ class TreasureController extends \app\components\BaseController
*/
public function behaviors()
{
- return ArrayHelper::merge(parent::behaviors(), []);
+ return ArrayHelper::merge(parent::behaviors(), [
+ 'access' => [
+ 'class' => \yii\filters\AccessControl::class,
+ 'rules' => [
+ 'authActions' => [
+ 'allow' => true,
+ 'actions' => ['index', 'view'],
+ 'roles' => ['@'],
+ 'matchCallback' => function () {
+ return \Yii::$app->user->identity->isAdmin;
+ },
+ ],
+ ],
+ ],
+ ]);
}
/**
@@ -47,7 +61,7 @@ public function actionValidate()
if ($string !== "") {
$secretKey = Yii::$app->sys->treasure_secret_key;
$results = Yii::$app->db->createCommand("select treasure.id,player.id as player_id from treasure,player where md5(HEX(AES_ENCRYPT(CONCAT(code, player.id), :secretKey))) LIKE :code", [':secretKey' => $secretKey, ':code' => $string])->queryOne();
- if ($results === [] || $results===false) {
+ if ($results === [] || $results === false) {
Yii::$app->session->setFlash('warning', Yii::t('app', "Code not found."));
} else {
$player = \app\modules\frontend\models\Player::findOne($results['player_id']);
@@ -56,21 +70,18 @@ public function actionValidate()
'username' => $player->username,
'actions' => false
]);
- if($player->teamPlayer!==NULL)
- {
- $msg = sprintf('Code belongs to player [%s] from team [%s] for target %s and treasure %s', $profileLink,$player->teamPlayer->team->name, $treasure->target->name, $treasure->name);
- }
- else
- {
+ if ($player->teamPlayer !== NULL) {
+ $msg = sprintf('Code belongs to player [%s] from team [%s] for target %s and treasure %s', $profileLink, $player->teamPlayer->team->name, $treasure->target->name, $treasure->name);
+ } else {
$msg = sprintf('Code belongs to player [%s] for target %s and treasure %s', $profileLink, $treasure->target->name, $treasure->name);
}
Yii::$app->session->setFlash('success', $msg);
- $string='';
+ $string = '';
}
}
- return $this->render('validate',['code'=>$string]);
+ return $this->render('validate', ['code' => $string]);
}
/**
diff --git a/backend/modules/infrastructure/controllers/TargetMetadataController.php b/backend/modules/infrastructure/controllers/TargetMetadataController.php
index 25f062ab9..a7ee6c011 100644
--- a/backend/modules/infrastructure/controllers/TargetMetadataController.php
+++ b/backend/modules/infrastructure/controllers/TargetMetadataController.php
@@ -19,102 +19,116 @@ class TargetMetadataController extends \app\components\BaseController
*/
public function behaviors()
{
- return ArrayHelper::merge(parent::behaviors(), []);
+ return ArrayHelper::merge(parent::behaviors(), [
+ 'access' => [
+ 'class' => \yii\filters\AccessControl::class,
+ 'rules' => [
+ 'authActions' => [
+ 'allow' => true,
+ 'actions' => ['index', 'view'],
+ 'roles' => ['@'],
+ 'matchCallback' => function () {
+ return \Yii::$app->user->identity->isAdmin;
+ },
+ ],
+ ],
+ ],
+ ]);
}
- /**
- * Lists all TargetMetadata models.
- * @return mixed
- */
+ /**
+ * Lists all TargetMetadata models.
+ * @return mixed
+ */
public function actionIndex()
{
- $searchModel = new TargetMetadataSearch();
- $dataProvider = $searchModel->search(Yii::$app->request->queryParams);
+ $searchModel = new TargetMetadataSearch();
+ $dataProvider = $searchModel->search(Yii::$app->request->queryParams);
- return $this->render('index', [
- 'searchModel' => $searchModel,
- 'dataProvider' => $dataProvider,
- ]);
+ return $this->render('index', [
+ 'searchModel' => $searchModel,
+ 'dataProvider' => $dataProvider,
+ ]);
}
- /**
- * Displays a single TargetMetadata model.
- * @param integer $id
- * @return mixed
- * @throws NotFoundHttpException if the model cannot be found
- */
+ /**
+ * Displays a single TargetMetadata model.
+ * @param integer $id
+ * @return mixed
+ * @throws NotFoundHttpException if the model cannot be found
+ */
public function actionView($id)
{
- return $this->render('view', [
- 'model' => $this->findModel($id),
- ]);
+ return $this->render('view', [
+ 'model' => $this->findModel($id),
+ ]);
}
- /**
- * Creates a new TargetMetadata model.
- * If creation is successful, the browser will be redirected to the 'view' page.
- * @return mixed
- */
+ /**
+ * Creates a new TargetMetadata model.
+ * If creation is successful, the browser will be redirected to the 'view' page.
+ * @return mixed
+ */
public function actionCreate()
{
- $model = new TargetMetadata();
+ $model = new TargetMetadata();
if ($model->load(Yii::$app->request->post()) && $model->save()) {
- return $this->redirect(['view', 'id' => $model->target_id]);
+ return $this->redirect(['view', 'id' => $model->target_id]);
}
- return $this->render('create', [
- 'model' => $model,
- ]);
+ return $this->render('create', [
+ 'model' => $model,
+ ]);
}
- /**
- * Updates an existing TargetMetadata model.
- * If update is successful, the browser will be redirected to the 'view' page.
- * @param integer $id
- * @return mixed
- * @throws NotFoundHttpException if the model cannot be found
- */
+ /**
+ * Updates an existing TargetMetadata model.
+ * If update is successful, the browser will be redirected to the 'view' page.
+ * @param integer $id
+ * @return mixed
+ * @throws NotFoundHttpException if the model cannot be found
+ */
public function actionUpdate($id)
{
- $model = $this->findModel($id);
+ $model = $this->findModel($id);
if ($model->load(Yii::$app->request->post()) && $model->save()) {
- return $this->redirect(['view', 'id' => $model->target_id]);
+ return $this->redirect(['view', 'id' => $model->target_id]);
}
- return $this->render('update', [
- 'model' => $model,
- ]);
+ return $this->render('update', [
+ 'model' => $model,
+ ]);
}
- /**
- * Deletes an existing TargetMetadata model.
- * If deletion is successful, the browser will be redirected to the 'index' page.
- * @param integer $id
- * @return mixed
- * @throws NotFoundHttpException if the model cannot be found
- */
+ /**
+ * Deletes an existing TargetMetadata model.
+ * If deletion is successful, the browser will be redirected to the 'index' page.
+ * @param integer $id
+ * @return mixed
+ * @throws NotFoundHttpException if the model cannot be found
+ */
public function actionDelete($id)
{
- $this->findModel($id)->delete();
+ $this->findModel($id)->delete();
- return $this->redirect(['index']);
+ return $this->redirect(['index']);
}
- /**
- * Finds the TargetMetadata model based on its primary key value.
- * If the model is not found, a 404 HTTP exception will be thrown.
- * @param integer $id
- * @return TargetMetadata the loaded model
- * @throws NotFoundHttpException if the model cannot be found
- */
+ /**
+ * Finds the TargetMetadata model based on its primary key value.
+ * If the model is not found, a 404 HTTP exception will be thrown.
+ * @param integer $id
+ * @return TargetMetadata the loaded model
+ * @throws NotFoundHttpException if the model cannot be found
+ */
protected function findModel($id)
{
if (($model = TargetMetadata::findOne($id)) !== null) {
- return $model;
+ return $model;
}
- throw new NotFoundHttpException('The requested page does not exist.');
+ throw new NotFoundHttpException('The requested page does not exist.');
}
}
diff --git a/backend/modules/infrastructure/models/TargetInstanceQuery.php b/backend/modules/infrastructure/models/TargetInstanceQuery.php
index b2551b250..da1067901 100644
--- a/backend/modules/infrastructure/models/TargetInstanceQuery.php
+++ b/backend/modules/infrastructure/models/TargetInstanceQuery.php
@@ -9,14 +9,50 @@
*/
class TargetInstanceQuery extends \yii\db\ActiveQuery
{
+ /**
+ * Filters TargetInstances to those that are active
+ * and whose team has at least one approved member with vpn_local_address != 0
+ */
+ public function withApprovedMemberHeartbeat()
+ {
+ return $this
+ // join to the team_instance player with teamPlayer
+ ->innerJoin(['tp' => 'team_player'], 'target_instance.player_id = tp.player_id AND tp.approved = 1')
+ // join to the team
+ ->innerJoin(['t' => 'team'], 'tp.team_id = t.id')
+ // join to approved members of the team
+ ->innerJoin(['am' => 'team_player'], 'am.team_id = t.id AND am.approved = 1')
+ // join approved member's last
+ ->innerJoin(['al' => 'player_last'], 'al.id = am.player_id and al.vpn_local_address is not null')
+ // ensure the approved member has a vpn_local_address
+ ->distinct();
+ }
+
public function active()
{
- return $this->andWhere('[[ip]] IS NOT NULL')->andWhere('[[reboot]]!=2');
+ return $this->andWhere('target_instance.[[ip]] IS NOT NULL')->andWhere('target_instance.[[reboot]]!=2');
+ }
+
+ public function last_updated(int $seconds_ago = 1)
+ {
+ return $this->andWhere(['<', 'target_instance.[[updated_at]]', new \yii\db\Expression("NOW() - INTERVAL $seconds_ago SECOND")]);
}
- public function pending_action($minutes_ago = 60)
+ public function pending_action(int $seconds_ago = 1)
{
- return $this->andWhere('[[ip]] IS NULL')->orWhere(['>', 'reboot', 0])->orWhere(['<', 'updated_at', new \yii\db\Expression("NOW() - INTERVAL $minutes_ago MINUTE")]);
+ return $this->addSelect([
+ 'target_instance.*',
+ 'reboot' => new \yii\db\Expression(
+ "IF(target_instance.updated_at < (NOW() - INTERVAL :seconds SECOND), 2, target_instance.reboot)",
+ [':seconds' => $seconds_ago]
+ ),
+ ])
+ ->andWhere([
+ 'or',
+ ['target_instance.ip' => null],
+ ['>', 'target_instance.reboot', 0],
+ ['<', 'target_instance.updated_at', new \yii\db\Expression("NOW() - INTERVAL $seconds_ago SECOND")]
+ ]);
}
diff --git a/backend/modules/infrastructure/views/target-instance/view.php b/backend/modules/infrastructure/views/target-instance/view.php
index 1a6c5f3ae..92ebc9210 100644
--- a/backend/modules/infrastructure/views/target-instance/view.php
+++ b/backend/modules/infrastructure/views/target-instance/view.php
@@ -66,7 +66,7 @@
'team_allowed:boolean',
[
'label' => 'encrypted flags',
- 'visible'=>$model->target->dynamic_treasures,
+ 'visible'=>$model->target->dynamic_treasures && \Yii::$app->user->identity->isAdmin,
'format' => 'raw',
'value' => function ($model) {
$lines=[];
diff --git a/backend/modules/settings/controllers/CountryController.php b/backend/modules/settings/controllers/CountryController.php
index 0f4a9e51c..5bd83eac0 100644
--- a/backend/modules/settings/controllers/CountryController.php
+++ b/backend/modules/settings/controllers/CountryController.php
@@ -14,110 +14,121 @@
*/
class CountryController extends \app\components\BaseController
{
- /**
- * {@inheritdoc}
- */
- public function behaviors()
- {
- return ArrayHelper::merge(parent::behaviors(),[]);
+ /**
+ * {@inheritdoc}
+ */
+ public function behaviors()
+ {
+ return ArrayHelper::merge(parent::behaviors(), [
+ 'access' => [
+ 'class' => \yii\filters\AccessControl::class,
+ 'rules' => [
+ 'authActions' => [
+ 'allow' => true,
+ 'actions' => ['index', 'view'],
+ 'roles' => ['@'],
+ 'matchCallback' => function () {
+ return \Yii::$app->user->identity->isAdmin;
+ },
+ ],
+ ],
+ ],
+ ]);
+ }
+
+ /**
+ * Lists all Country models.
+ * @return mixed
+ */
+ public function actionIndex()
+ {
+ $searchModel = new CountrySearch();
+ $dataProvider = $searchModel->search(Yii::$app->request->queryParams);
+
+ return $this->render('index', [
+ 'searchModel' => $searchModel,
+ 'dataProvider' => $dataProvider,
+ ]);
+ }
+
+ /**
+ * Displays a single Country model.
+ * @param string $id
+ * @return mixed
+ * @throws NotFoundHttpException if the model cannot be found
+ */
+ public function actionView($id)
+ {
+ return $this->render('view', [
+ 'model' => $this->findModel($id),
+ ]);
+ }
+
+ /**
+ * Creates a new Country model.
+ * If creation is successful, the browser will be redirected to the 'view' page.
+ * @return mixed
+ */
+ public function actionCreate()
+ {
+ $model = new Country();
+
+ if ($model->load(Yii::$app->request->post()) && $model->save()) {
+ return $this->redirect(['view', 'id' => $model->id]);
}
- /**
- * Lists all Country models.
- * @return mixed
- */
- public function actionIndex()
- {
- $searchModel=new CountrySearch();
- $dataProvider=$searchModel->search(Yii::$app->request->queryParams);
-
- return $this->render('index', [
- 'searchModel' => $searchModel,
- 'dataProvider' => $dataProvider,
- ]);
+ return $this->render('create', [
+ 'model' => $model,
+ ]);
+ }
+
+ /**
+ * Updates an existing Country model.
+ * If update is successful, the browser will be redirected to the 'view' page.
+ * @param string $id
+ * @return mixed
+ * @throws NotFoundHttpException if the model cannot be found
+ */
+ public function actionUpdate($id)
+ {
+ $model = $this->findModel($id);
+
+ if ($model->load(Yii::$app->request->post()) && $model->save()) {
+ return $this->redirect(['view', 'id' => $model->id]);
}
- /**
- * Displays a single Country model.
- * @param string $id
- * @return mixed
- * @throws NotFoundHttpException if the model cannot be found
- */
- public function actionView($id)
- {
- return $this->render('view', [
- 'model' => $this->findModel($id),
- ]);
+ return $this->render('update', [
+ 'model' => $model,
+ ]);
+ }
+
+ /**
+ * Deletes an existing Country model.
+ * If deletion is successful, the browser will be redirected to the 'index' page.
+ * @param string $id
+ * @return mixed
+ * @throws NotFoundHttpException if the model cannot be found
+ */
+ public function actionDelete($id)
+ {
+ $this->findModel($id)->delete();
+
+ return $this->redirect(['index']);
+ }
+
+ /**
+ * Finds the Country model based on its primary key value.
+ * If the model is not found, a 404 HTTP exception will be thrown.
+ * @param string $id
+ * @return Country the loaded model
+ * @throws NotFoundHttpException if the model cannot be found
+ */
+ protected function findModel($id)
+ {
+ if (($model = Country::findOne($id)) !== null) {
+ return $model;
}
- /**
- * Creates a new Country model.
- * If creation is successful, the browser will be redirected to the 'view' page.
- * @return mixed
- */
- public function actionCreate()
- {
- $model=new Country();
-
- if($model->load(Yii::$app->request->post()) && $model->save())
- {
- return $this->redirect(['view', 'id' => $model->id]);
- }
-
- return $this->render('create', [
- 'model' => $model,
- ]);
- }
-
- /**
- * Updates an existing Country model.
- * If update is successful, the browser will be redirected to the 'view' page.
- * @param string $id
- * @return mixed
- * @throws NotFoundHttpException if the model cannot be found
- */
- public function actionUpdate($id)
- {
- $model=$this->findModel($id);
-
- if($model->load(Yii::$app->request->post()) && $model->save())
- {
- return $this->redirect(['view', 'id' => $model->id]);
- }
-
- return $this->render('update', [
- 'model' => $model,
- ]);
- }
-
- /**
- * Deletes an existing Country model.
- * If deletion is successful, the browser will be redirected to the 'index' page.
- * @param string $id
- * @return mixed
- * @throws NotFoundHttpException if the model cannot be found
- */
- public function actionDelete($id)
- {
- $this->findModel($id)->delete();
-
- return $this->redirect(['index']);
- }
-
- /**
- * Finds the Country model based on its primary key value.
- * If the model is not found, a 404 HTTP exception will be thrown.
- * @param string $id
- * @return Country the loaded model
- * @throws NotFoundHttpException if the model cannot be found
- */
- protected function findModel($id)
- {
- if(($model=Country::findOne($id)) !== null)
- {
- return $model;
- }
-
- throw new NotFoundHttpException(Yii::t('app', 'The requested page does not exist.'));
- }
+ throw new NotFoundHttpException(Yii::t('app', 'The requested page does not exist.'));
+ }
}
diff --git a/backend/modules/settings/controllers/DisabledRouteController.php b/backend/modules/settings/controllers/DisabledRouteController.php
index b83d419c6..5390a6223 100644
--- a/backend/modules/settings/controllers/DisabledRouteController.php
+++ b/backend/modules/settings/controllers/DisabledRouteController.php
@@ -17,107 +17,118 @@ class DisabledRouteController extends \app\components\BaseController
/**
* {@inheritdoc}
*/
- public function behaviors()
- {
- return ArrayHelper::merge(parent::behaviors(),[]);
- }
+ public function behaviors()
+ {
+ return ArrayHelper::merge(parent::behaviors(), [
+ 'access' => [
+ 'class' => \yii\filters\AccessControl::class,
+ 'rules' => [
+ 'authActions' => [
+ 'allow' => true,
+ 'actions' => ['index', 'view'],
+ 'roles' => ['@'],
+ 'matchCallback' => function () {
+ return \Yii::$app->user->identity->isAdmin;
+ },
+ ],
+ ],
+ ],
+ ]);
+ }
- /**
- * Lists all DisabledRoute models.
- * @return mixed
- */
- public function actionIndex()
- {
- $searchModel=new DisabledRouteSearch();
- $dataProvider=$searchModel->search(Yii::$app->request->queryParams);
-
- return $this->render('index', [
- 'searchModel' => $searchModel,
- 'dataProvider' => $dataProvider,
- ]);
- }
+ /**
+ * Lists all DisabledRoute models.
+ * @return mixed
+ */
+ public function actionIndex()
+ {
+ $searchModel = new DisabledRouteSearch();
+ $dataProvider = $searchModel->search(Yii::$app->request->queryParams);
- /**
- * Displays a single DisabledRoute model.
- * @param string $id
- * @return mixed
- * @throws NotFoundHttpException if the model cannot be found
- */
- public function actionView($id)
- {
- return $this->render('view', [
- 'model' => $this->findModel($id),
- ]);
- }
+ return $this->render('index', [
+ 'searchModel' => $searchModel,
+ 'dataProvider' => $dataProvider,
+ ]);
+ }
- /**
- * Creates a new DisabledRoute model.
- * If creation is successful, the browser will be redirected to the 'view' page.
- * @return mixed
- */
- public function actionCreate()
- {
- $model=new DisabledRoute();
-
- if($model->load(Yii::$app->request->post()) && $model->save())
- {
- return $this->redirect(['view', 'id' => $model->route]);
- }
-
- return $this->render('create', [
- 'model' => $model,
- ]);
- }
+ /**
+ * Displays a single DisabledRoute model.
+ * @param string $id
+ * @return mixed
+ * @throws NotFoundHttpException if the model cannot be found
+ */
+ public function actionView($id)
+ {
+ return $this->render('view', [
+ 'model' => $this->findModel($id),
+ ]);
+ }
+
+ /**
+ * Creates a new DisabledRoute model.
+ * If creation is successful, the browser will be redirected to the 'view' page.
+ * @return mixed
+ */
+ public function actionCreate()
+ {
+ $model = new DisabledRoute();
- /**
- * Updates an existing DisabledRoute model.
- * If update is successful, the browser will be redirected to the 'view' page.
- * @param string $id
- * @return mixed
- * @throws NotFoundHttpException if the model cannot be found
- */
- public function actionUpdate($id)
- {
- $model=$this->findModel($id);
-
- if($model->load(Yii::$app->request->post()) && $model->save())
- {
- return $this->redirect(['view', 'id' => $model->route]);
- }
-
- return $this->render('update', [
- 'model' => $model,
- ]);
+ if ($model->load(Yii::$app->request->post()) && $model->save()) {
+ return $this->redirect(['view', 'id' => $model->route]);
}
- /**
- * Deletes an existing DisabledRoute model.
- * If deletion is successful, the browser will be redirected to the 'index' page.
- * @param string $id
- * @return mixed
- * @throws NotFoundHttpException if the model cannot be found
- */
- public function actionDelete($id)
- {
- $this->findModel($id)->delete();
-
- return $this->redirect(['index']);
+ return $this->render('create', [
+ 'model' => $model,
+ ]);
+ }
+
+ /**
+ * Updates an existing DisabledRoute model.
+ * If update is successful, the browser will be redirected to the 'view' page.
+ * @param string $id
+ * @return mixed
+ * @throws NotFoundHttpException if the model cannot be found
+ */
+ public function actionUpdate($id)
+ {
+ $model = $this->findModel($id);
+
+ if ($model->load(Yii::$app->request->post()) && $model->save()) {
+ return $this->redirect(['view', 'id' => $model->route]);
}
- /**
- * Finds the DisabledRoute model based on its primary key value.
- * If the model is not found, a 404 HTTP exception will be thrown.
- * @param string $id
- * @return DisabledRoute the loaded model
- * @throws NotFoundHttpException if the model cannot be found
- */
- protected function findModel($id)
- {
- if(($model=DisabledRoute::findOne($id)) !== null)
- {
- return $model;
- }
-
- throw new NotFoundHttpException('The requested page does not exist.');
+ return $this->render('update', [
+ 'model' => $model,
+ ]);
+ }
+
+ /**
+ * Deletes an existing DisabledRoute model.
+ * If deletion is successful, the browser will be redirected to the 'index' page.
+ * @param string $id
+ * @return mixed
+ * @throws NotFoundHttpException if the model cannot be found
+ */
+ public function actionDelete($id)
+ {
+ $this->findModel($id)->delete();
+
+ return $this->redirect(['index']);
+ }
+
+ /**
+ * Finds the DisabledRoute model based on its primary key value.
+ * If the model is not found, a 404 HTTP exception will be thrown.
+ * @param string $id
+ * @return DisabledRoute the loaded model
+ * @throws NotFoundHttpException if the model cannot be found
+ */
+ protected function findModel($id)
+ {
+ if (($model = DisabledRoute::findOne($id)) !== null) {
+ return $model;
}
+
+ throw new NotFoundHttpException('The requested page does not exist.');
+ }
}
diff --git a/backend/modules/settings/controllers/OpenvpnController.php b/backend/modules/settings/controllers/OpenvpnController.php
index 2cf6ddb77..b14886aac 100644
--- a/backend/modules/settings/controllers/OpenvpnController.php
+++ b/backend/modules/settings/controllers/OpenvpnController.php
@@ -15,107 +15,121 @@
*/
class OpenvpnController extends \app\components\BaseController
{
- /**
- * {@inheritdoc}
- */
- public function behaviors()
- {
- return ArrayHelper::merge(parent::behaviors(),[]);
+ /**
+ * {@inheritdoc}
+ */
+ public function behaviors()
+ {
+ return ArrayHelper::merge(parent::behaviors(), [
+ 'access' => [
+ 'class' => \yii\filters\AccessControl::class,
+ 'rules' => [
+ 'authActions' => [
+ 'allow' => true,
+ 'actions' => ['index', 'view'],
+ 'roles' => ['@'],
+ 'matchCallback' => function () {
+ return \Yii::$app->user->identity->isAdmin;
+ },
+ ],
+ ],
+ ],
+ ]);
+ }
+
+ /**
+ * Lists all Openvpn models.
+ * @return mixed
+ */
+ public function actionIndex()
+ {
+ $searchModel = new OpenvpnSearch();
+ $dataProvider = $searchModel->search(Yii::$app->request->queryParams);
+
+ return $this->render('index', [
+ 'searchModel' => $searchModel,
+ 'dataProvider' => $dataProvider,
+ ]);
+ }
+
+ /**
+ * Displays a single Openvpn model.
+ * @param integer $id
+ * @return mixed
+ * @throws NotFoundHttpException if the model cannot be found
+ */
+ public function actionView($id)
+ {
+ return $this->render('view', [
+ 'model' => $this->findModel($id),
+ ]);
+ }
+
+ /**
+ * Creates a new Openvpn model.
+ * If creation is successful, the browser will be redirected to the 'view' page.
+ * @return mixed
+ */
+ public function actionCreate()
+ {
+ $model = new Openvpn();
+
+ if ($model->load(Yii::$app->request->post()) && $model->save()) {
+ return $this->redirect(['view', 'id' => $model->id]);
}
- /**
- * Lists all Openvpn models.
- * @return mixed
- */
- public function actionIndex()
- {
- $searchModel = new OpenvpnSearch();
- $dataProvider = $searchModel->search(Yii::$app->request->queryParams);
-
- return $this->render('index', [
- 'searchModel' => $searchModel,
- 'dataProvider' => $dataProvider,
- ]);
+ return $this->render('create', [
+ 'model' => $model,
+ ]);
+ }
+
+ /**
+ * Updates an existing Openvpn model.
+ * If update is successful, the browser will be redirected to the 'view' page.
+ * @param integer $id
+ * @return mixed
+ * @throws NotFoundHttpException if the model cannot be found
+ */
+ public function actionUpdate($id)
+ {
+ $model = $this->findModel($id);
+
+ if ($model->load(Yii::$app->request->post()) && $model->save()) {
+ return $this->redirect(['view', 'id' => $model->id]);
}
- /**
- * Displays a single Openvpn model.
- * @param integer $id
- * @return mixed
- * @throws NotFoundHttpException if the model cannot be found
- */
- public function actionView($id)
- {
- return $this->render('view', [
- 'model' => $this->findModel($id),
- ]);
+ return $this->render('update', [
+ 'model' => $model,
+ ]);
+ }
+
+ /**
+ * Deletes an existing Openvpn model.
+ * If deletion is successful, the browser will be redirected to the 'index' page.
+ * @param integer $id
+ * @return mixed
+ * @throws NotFoundHttpException if the model cannot be found
+ */
+ public function actionDelete($id)
+ {
+ $this->findModel($id)->delete();
+
+ return $this->redirect(['index']);
+ }
+
+ /**
+ * Finds the Openvpn model based on its primary key value.
+ * If the model is not found, a 404 HTTP exception will be thrown.
+ * @param integer $id
+ * @return Openvpn the loaded model
+ * @throws NotFoundHttpException if the model cannot be found
+ */
+ protected function findModel($id)
+ {
+ if (($model = Openvpn::findOne($id)) !== null) {
+ return $model;
}
- /**
- * Creates a new Openvpn model.
- * If creation is successful, the browser will be redirected to the 'view' page.
- * @return mixed
- */
- public function actionCreate()
- {
- $model = new Openvpn();
-
- if ($model->load(Yii::$app->request->post()) && $model->save()) {
- return $this->redirect(['view', 'id' => $model->id]);
- }
-
- return $this->render('create', [
- 'model' => $model,
- ]);
- }
-
- /**
- * Updates an existing Openvpn model.
- * If update is successful, the browser will be redirected to the 'view' page.
- * @param integer $id
- * @return mixed
- * @throws NotFoundHttpException if the model cannot be found
- */
- public function actionUpdate($id)
- {
- $model = $this->findModel($id);
-
- if ($model->load(Yii::$app->request->post()) && $model->save()) {
- return $this->redirect(['view', 'id' => $model->id]);
- }
-
- return $this->render('update', [
- 'model' => $model,
- ]);
- }
-
- /**
- * Deletes an existing Openvpn model.
- * If deletion is successful, the browser will be redirected to the 'index' page.
- * @param integer $id
- * @return mixed
- * @throws NotFoundHttpException if the model cannot be found
- */
- public function actionDelete($id)
- {
- $this->findModel($id)->delete();
-
- return $this->redirect(['index']);
- }
-
- /**
- * Finds the Openvpn model based on its primary key value.
- * If the model is not found, a 404 HTTP exception will be thrown.
- * @param integer $id
- * @return Openvpn the loaded model
- * @throws NotFoundHttpException if the model cannot be found
- */
- protected function findModel($id)
- {
- if (($model = Openvpn::findOne($id)) !== null) {
- return $model;
- }
-
- throw new NotFoundHttpException(Yii::t('app', 'The requested page does not exist.'));
- }
+ throw new NotFoundHttpException(Yii::t('app', 'The requested page does not exist.'));
+ }
}
diff --git a/backend/modules/settings/controllers/PlayerDisabledrouteController.php b/backend/modules/settings/controllers/PlayerDisabledrouteController.php
index a780accc2..8ed11c0ad 100644
--- a/backend/modules/settings/controllers/PlayerDisabledrouteController.php
+++ b/backend/modules/settings/controllers/PlayerDisabledrouteController.php
@@ -14,107 +14,121 @@
*/
class PlayerDisabledrouteController extends \app\components\BaseController
{
- /**
- * {@inheritdoc}
- */
- public function behaviors()
- {
- return ArrayHelper::merge(parent::behaviors(),[]);
+ /**
+ * {@inheritdoc}
+ */
+ public function behaviors()
+ {
+ return ArrayHelper::merge(parent::behaviors(), [
+ 'access' => [
+ 'class' => \yii\filters\AccessControl::class,
+ 'rules' => [
+ 'authActions' => [
+ 'allow' => true,
+ 'actions' => ['index', 'view'],
+ 'roles' => ['@'],
+ 'matchCallback' => function () {
+ return \Yii::$app->user->identity->isAdmin;
+ },
+ ],
+ ],
+ ],
+ ]);
+ }
+
+ /**
+ * Lists all PlayerDisabledroute models.
+ * @return mixed
+ */
+ public function actionIndex()
+ {
+ $searchModel = new PlayerDisabledrouteSearch();
+ $dataProvider = $searchModel->search(Yii::$app->request->queryParams);
+
+ return $this->render('index', [
+ 'searchModel' => $searchModel,
+ 'dataProvider' => $dataProvider,
+ ]);
+ }
+
+ /**
+ * Displays a single PlayerDisabledroute model.
+ * @param integer $id
+ * @return mixed
+ * @throws NotFoundHttpException if the model cannot be found
+ */
+ public function actionView($id)
+ {
+ return $this->render('view', [
+ 'model' => $this->findModel($id),
+ ]);
+ }
+
+ /**
+ * Creates a new PlayerDisabledroute model.
+ * If creation is successful, the browser will be redirected to the 'view' page.
+ * @return mixed
+ */
+ public function actionCreate()
+ {
+ $model = new PlayerDisabledroute();
+
+ if ($model->load(Yii::$app->request->post()) && $model->save()) {
+ return $this->redirect(['view', 'id' => $model->id]);
}
- /**
- * Lists all PlayerDisabledroute models.
- * @return mixed
- */
- public function actionIndex()
- {
- $searchModel = new PlayerDisabledrouteSearch();
- $dataProvider = $searchModel->search(Yii::$app->request->queryParams);
-
- return $this->render('index', [
- 'searchModel' => $searchModel,
- 'dataProvider' => $dataProvider,
- ]);
+ return $this->render('create', [
+ 'model' => $model,
+ ]);
+ }
+
+ /**
+ * Updates an existing PlayerDisabledroute model.
+ * If update is successful, the browser will be redirected to the 'view' page.
+ * @param integer $id
+ * @return mixed
+ * @throws NotFoundHttpException if the model cannot be found
+ */
+ public function actionUpdate($id)
+ {
+ $model = $this->findModel($id);
+
+ if ($model->load(Yii::$app->request->post()) && $model->save()) {
+ return $this->redirect(['view', 'id' => $model->id]);
}
- /**
- * Displays a single PlayerDisabledroute model.
- * @param integer $id
- * @return mixed
- * @throws NotFoundHttpException if the model cannot be found
- */
- public function actionView($id)
- {
- return $this->render('view', [
- 'model' => $this->findModel($id),
- ]);
+ return $this->render('update', [
+ 'model' => $model,
+ ]);
+ }
+
+ /**
+ * Deletes an existing PlayerDisabledroute model.
+ * If deletion is successful, the browser will be redirected to the 'index' page.
+ * @param integer $id
+ * @return mixed
+ * @throws NotFoundHttpException if the model cannot be found
+ */
+ public function actionDelete($id)
+ {
+ $this->findModel($id)->delete();
+
+ return $this->redirect(['index']);
+ }
+
+ /**
+ * Finds the PlayerDisabledroute model based on its primary key value.
+ * If the model is not found, a 404 HTTP exception will be thrown.
+ * @param integer $id
+ * @return PlayerDisabledroute the loaded model
+ * @throws NotFoundHttpException if the model cannot be found
+ */
+ protected function findModel($id)
+ {
+ if (($model = PlayerDisabledroute::findOne($id)) !== null) {
+ return $model;
}
- /**
- * Creates a new PlayerDisabledroute model.
- * If creation is successful, the browser will be redirected to the 'view' page.
- * @return mixed
- */
- public function actionCreate()
- {
- $model = new PlayerDisabledroute();
-
- if ($model->load(Yii::$app->request->post()) && $model->save()) {
- return $this->redirect(['view', 'id' => $model->id]);
- }
-
- return $this->render('create', [
- 'model' => $model,
- ]);
- }
-
- /**
- * Updates an existing PlayerDisabledroute model.
- * If update is successful, the browser will be redirected to the 'view' page.
- * @param integer $id
- * @return mixed
- * @throws NotFoundHttpException if the model cannot be found
- */
- public function actionUpdate($id)
- {
- $model = $this->findModel($id);
-
- if ($model->load(Yii::$app->request->post()) && $model->save()) {
- return $this->redirect(['view', 'id' => $model->id]);
- }
-
- return $this->render('update', [
- 'model' => $model,
- ]);
- }
-
- /**
- * Deletes an existing PlayerDisabledroute model.
- * If deletion is successful, the browser will be redirected to the 'index' page.
- * @param integer $id
- * @return mixed
- * @throws NotFoundHttpException if the model cannot be found
- */
- public function actionDelete($id)
- {
- $this->findModel($id)->delete();
-
- return $this->redirect(['index']);
- }
-
- /**
- * Finds the PlayerDisabledroute model based on its primary key value.
- * If the model is not found, a 404 HTTP exception will be thrown.
- * @param integer $id
- * @return PlayerDisabledroute the loaded model
- * @throws NotFoundHttpException if the model cannot be found
- */
- protected function findModel($id)
- {
- if (($model = PlayerDisabledroute::findOne($id)) !== null) {
- return $model;
- }
-
- throw new NotFoundHttpException(Yii::t('app', 'The requested page does not exist.'));
- }
+ throw new NotFoundHttpException(Yii::t('app', 'The requested page does not exist.'));
+ }
}
diff --git a/backend/modules/settings/controllers/SysconfigController.php b/backend/modules/settings/controllers/SysconfigController.php
index 233701be8..6ff1a10fc 100644
--- a/backend/modules/settings/controllers/SysconfigController.php
+++ b/backend/modules/settings/controllers/SysconfigController.php
@@ -15,129 +15,137 @@
*/
class SysconfigController extends \app\components\BaseController
{
- /**
- * {@inheritdoc}
- */
- public function behaviors()
- {
- return ArrayHelper::merge(parent::behaviors(),[]);
+ /**
+ * {@inheritdoc}
+ */
+ public function behaviors()
+ {
+ return ArrayHelper::merge(parent::behaviors(), [
+ 'access' => [
+ 'class' => \yii\filters\AccessControl::class,
+ 'rules' => [
+ 'authActions' => [
+ 'allow' => true,
+ 'actions' => ['index', 'view'],
+ 'roles' => ['@'],
+ 'matchCallback' => function () {
+ return \Yii::$app->user->identity->isAdmin;
+ },
+ ],
+ ],
+ ],
+ ]);
+ }
+
+ /**
+ * Lists all Sysconfig models.
+ * @return mixed
+ */
+ public function actionIndex()
+ {
+ $searchModel = new SysconfigSearch();
+ $dataProvider = $searchModel->search(Yii::$app->request->queryParams);
+
+ return $this->render('index', [
+ 'searchModel' => $searchModel,
+ 'dataProvider' => $dataProvider,
+ ]);
+ }
+
+ /**
+ * Creates a new Sysconfig model.
+ * If creation is successful, the browser will be redirected to the 'index' page.
+ * @return mixed
+ */
+ public function actionCreate()
+ {
+ $model = new Sysconfig();
+
+ if ($model->load(Yii::$app->request->post()) && $model->save()) {
+ return $this->redirect(['index']);
}
- /**
- * Lists all Sysconfig models.
- * @return mixed
- */
- public function actionIndex()
- {
- $searchModel=new SysconfigSearch();
- $dataProvider=$searchModel->search(Yii::$app->request->queryParams);
-
- return $this->render('index', [
- 'searchModel' => $searchModel,
- 'dataProvider' => $dataProvider,
- ]);
- }
-
- /**
- * Creates a new Sysconfig model.
- * If creation is successful, the browser will be redirected to the 'index' page.
- * @return mixed
- */
- public function actionCreate()
- {
- $model=new Sysconfig();
-
- if($model->load(Yii::$app->request->post()) && $model->save())
- {
- return $this->redirect(['index']);
- }
-
- return $this->render('create', [
- 'model' => $model,
- ]);
- }
-
- /**
- * Updates an existing Sysconfig model.
- * If update is successful, the browser will be redirected to the 'index' page.
- * @param string $id
- * @return mixed
- * @throws NotFoundHttpException if the model cannot be found
- */
- public function actionUpdate($id)
- {
- $model=$this->findModel($id);
-
- if($model->load(Yii::$app->request->post()) && $model->save())
- {
- Yii::$app->session->setFlash('success', Yii::t('app','{id} updated.',['id'=>$model->id]));
- if($id!==$model->id)
- {
- return $this->redirect(['update','id'=>$model->id]);
- }
- }
-
- return $this->render('update', [
- 'model' => $model,
- ]);
- }
-
- /**
- * Creates/Updates a Sysconfig set model.
- * If update is successful, the browser will be redirected to the 'index' page.
- * @param string $id
- * @return mixed
- * @throws NotFoundHttpException if the model cannot be found
- */
- public function actionConfigure()
- {
- $model=new ConfigureForm();
- if($model->load(Yii::$app->request->post()) && $model->save())
- {
- Yii::$app->session->setFlash('success',Yii::t('app','Configuration saved'));
- return $this->redirect(['configure']);
+ return $this->render('create', [
+ 'model' => $model,
+ ]);
+ }
+
+ /**
+ * Updates an existing Sysconfig model.
+ * If update is successful, the browser will be redirected to the 'index' page.
+ * @param string $id
+ * @return mixed
+ * @throws NotFoundHttpException if the model cannot be found
+ */
+ public function actionUpdate($id)
+ {
+ $model = $this->findModel($id);
+
+ if ($model->load(Yii::$app->request->post()) && $model->save()) {
+ Yii::$app->session->setFlash('success', Yii::t('app', '{id} updated.', ['id' => $model->id]));
+ if ($id !== $model->id) {
+ return $this->redirect(['update', 'id' => $model->id]);
}
-
- return $this->render('configure', [
- 'model' => $model,
- ]);
}
- /**
- * Deletes an existing Sysconfig model.
- * If deletion is successful, the browser will be redirected to the 'index' page.
- * @param string $id
- * @return mixed
- * @throws NotFoundHttpException if the model cannot be found
- */
- public function actionDelete($id)
- {
- $this->findModel($id)->delete();
-
- return $this->redirect(['index']);
+ return $this->render('update', [
+ 'model' => $model,
+ ]);
+ }
+
+ /**
+ * Creates/Updates a Sysconfig set model.
+ * If update is successful, the browser will be redirected to the 'index' page.
+ * @param string $id
+ * @return mixed
+ * @throws NotFoundHttpException if the model cannot be found
+ */
+ public function actionConfigure()
+ {
+ $model = new ConfigureForm();
+ if ($model->load(Yii::$app->request->post()) && $model->save()) {
+ Yii::$app->session->setFlash('success', Yii::t('app', 'Configuration saved'));
+ return $this->redirect(['configure']);
}
- /**
- * Finds the Sysconfig model based on its primary key value.
- * If the model is not found, a 404 HTTP exception will be thrown.
- * @param string $id
- * @return Sysconfig the loaded model
- * @throws NotFoundHttpException if the model cannot be found
- */
- protected function findModel($id)
- {
- if(($model=Sysconfig::findOne($id)) !== null)
- {
- return $model;
- }
-
- throw new NotFoundHttpException(Yii::t('app','The requested page does not exist.'));
+ return $this->render('configure', [
+ 'model' => $model,
+ ]);
+ }
+
+ /**
+ * Deletes an existing Sysconfig model.
+ * If deletion is successful, the browser will be redirected to the 'index' page.
+ * @param string $id
+ * @return mixed
+ * @throws NotFoundHttpException if the model cannot be found
+ */
+ public function actionDelete($id)
+ {
+ $this->findModel($id)->delete();
+
+ return $this->redirect(['index']);
+ }
+
+ /**
+ * Finds the Sysconfig model based on its primary key value.
+ * If the model is not found, a 404 HTTP exception will be thrown.
+ * @param string $id
+ * @return Sysconfig the loaded model
+ * @throws NotFoundHttpException if the model cannot be found
+ */
+ protected function findModel($id)
+ {
+ if (($model = Sysconfig::findOne($id)) !== null) {
+ return $model;
}
- protected function stripYii()
- {
- $array=explode("\n", trim(ob_get_clean()));
- for($i=0;$i < 3;$i++) array_shift($array);
- return array_map('trim', $array);
- }
+ throw new NotFoundHttpException(Yii::t('app', 'The requested page does not exist.'));
+ }
+ protected function stripYii()
+ {
+ $array = explode("\n", trim(ob_get_clean()));
+ for ($i = 0; $i < 3; $i++) array_shift($array);
+ return array_map('trim', $array);
+ }
}
diff --git a/backend/modules/settings/controllers/UrlRouteController.php b/backend/modules/settings/controllers/UrlRouteController.php
index e8a27e15f..446f39a3f 100644
--- a/backend/modules/settings/controllers/UrlRouteController.php
+++ b/backend/modules/settings/controllers/UrlRouteController.php
@@ -9,112 +9,127 @@
use yii\web\NotFoundHttpException;
use yii\filters\VerbFilter;
use yii\helpers\ArrayHelper;
+
/**
* UrlRouteController implements the CRUD actions for UrlRoute model.
*/
class UrlRouteController extends \app\components\BaseController
{
- /**
- * {@inheritdoc}
- */
- public function behaviors()
- {
- return ArrayHelper::merge(parent::behaviors(),[]);
- }
+ /**
+ * {@inheritdoc}
+ */
+ public function behaviors()
+ {
+ return ArrayHelper::merge(parent::behaviors(), [
+ 'access' => [
+ 'class' => \yii\filters\AccessControl::class,
+ 'rules' => [
+ 'authActions' => [
+ 'allow' => true,
+ 'actions' => ['index', 'view'],
+ 'roles' => ['@'],
+ 'matchCallback' => function () {
+ return \Yii::$app->user->identity->isAdmin;
+ },
+ ],
+ ],
+ ],
+ ]);
+ }
- /**
- * Lists all UrlRoute models.
- * @return mixed
- */
- public function actionIndex()
- {
- $searchModel = new UrlRouteSearch();
- $dataProvider = $searchModel->search(Yii::$app->request->queryParams);
-
- return $this->render('index', [
- 'searchModel' => $searchModel,
- 'dataProvider' => $dataProvider,
- ]);
- }
+ /**
+ * Lists all UrlRoute models.
+ * @return mixed
+ */
+ public function actionIndex()
+ {
+ $searchModel = new UrlRouteSearch();
+ $dataProvider = $searchModel->search(Yii::$app->request->queryParams);
- /**
- * Displays a single UrlRoute model.
- * @param integer $id
- * @return mixed
- * @throws NotFoundHttpException if the model cannot be found
- */
- public function actionView($id)
- {
- return $this->render('view', [
- 'model' => $this->findModel($id),
- ]);
- }
+ return $this->render('index', [
+ 'searchModel' => $searchModel,
+ 'dataProvider' => $dataProvider,
+ ]);
+ }
- /**
- * Creates a new UrlRoute model.
- * If creation is successful, the browser will be redirected to the 'view' page.
- * @return mixed
- */
- public function actionCreate()
- {
- $model = new UrlRoute();
-
- if ($model->load(Yii::$app->request->post()) && $model->save()) {
- return $this->redirect(['view', 'id' => $model->id]);
- }
-
- return $this->render('create', [
- 'model' => $model,
- ]);
- }
+ /**
+ * Displays a single UrlRoute model.
+ * @param integer $id
+ * @return mixed
+ * @throws NotFoundHttpException if the model cannot be found
+ */
+ public function actionView($id)
+ {
+ return $this->render('view', [
+ 'model' => $this->findModel($id),
+ ]);
+ }
+
+ /**
+ * Creates a new UrlRoute model.
+ * If creation is successful, the browser will be redirected to the 'view' page.
+ * @return mixed
+ */
+ public function actionCreate()
+ {
+ $model = new UrlRoute();
- /**
- * Updates an existing UrlRoute model.
- * If update is successful, the browser will be redirected to the 'view' page.
- * @param integer $id
- * @return mixed
- * @throws NotFoundHttpException if the model cannot be found
- */
- public function actionUpdate($id)
- {
- $model = $this->findModel($id);
-
- if ($model->load(Yii::$app->request->post()) && $model->save()) {
- return $this->redirect(['view', 'id' => $model->id]);
- }
-
- return $this->render('update', [
- 'model' => $model,
- ]);
+ if ($model->load(Yii::$app->request->post()) && $model->save()) {
+ return $this->redirect(['view', 'id' => $model->id]);
}
- /**
- * Deletes an existing UrlRoute model.
- * If deletion is successful, the browser will be redirected to the 'index' page.
- * @param integer $id
- * @return mixed
- * @throws NotFoundHttpException if the model cannot be found
- */
- public function actionDelete($id)
- {
- $this->findModel($id)->delete();
-
- return $this->redirect(['index']);
+ return $this->render('create', [
+ 'model' => $model,
+ ]);
+ }
+
+ /**
+ * Updates an existing UrlRoute model.
+ * If update is successful, the browser will be redirected to the 'view' page.
+ * @param integer $id
+ * @return mixed
+ * @throws NotFoundHttpException if the model cannot be found
+ */
+ public function actionUpdate($id)
+ {
+ $model = $this->findModel($id);
+
+ if ($model->load(Yii::$app->request->post()) && $model->save()) {
+ return $this->redirect(['view', 'id' => $model->id]);
}
- /**
- * Finds the UrlRoute model based on its primary key value.
- * If the model is not found, a 404 HTTP exception will be thrown.
- * @param integer $id
- * @return UrlRoute the loaded model
- * @throws NotFoundHttpException if the model cannot be found
- */
- protected function findModel($id)
- {
- if (($model = UrlRoute::findOne($id)) !== null) {
- return $model;
- }
-
- throw new NotFoundHttpException(Yii::t('app', 'The requested page does not exist.'));
+ return $this->render('update', [
+ 'model' => $model,
+ ]);
+ }
+
+ /**
+ * Deletes an existing UrlRoute model.
+ * If deletion is successful, the browser will be redirected to the 'index' page.
+ * @param integer $id
+ * @return mixed
+ * @throws NotFoundHttpException if the model cannot be found
+ */
+ public function actionDelete($id)
+ {
+ $this->findModel($id)->delete();
+
+ return $this->redirect(['index']);
+ }
+
+ /**
+ * Finds the UrlRoute model based on its primary key value.
+ * If the model is not found, a 404 HTTP exception will be thrown.
+ * @param integer $id
+ * @return UrlRoute the loaded model
+ * @throws NotFoundHttpException if the model cannot be found
+ */
+ protected function findModel($id)
+ {
+ if (($model = UrlRoute::findOne($id)) !== null) {
+ return $model;
}
+
+ throw new NotFoundHttpException(Yii::t('app', 'The requested page does not exist.'));
+ }
}
diff --git a/backend/modules/settings/controllers/UserController.php b/backend/modules/settings/controllers/UserController.php
index cea3f74ba..78d1d6602 100644
--- a/backend/modules/settings/controllers/UserController.php
+++ b/backend/modules/settings/controllers/UserController.php
@@ -17,105 +17,116 @@ class UserController extends \app\components\BaseController
/**
* {@inheritdoc}
*/
- public function behaviors()
- {
- return ArrayHelper::merge(parent::behaviors(),[]);
- }
-
- /**
- * Lists all User models.
- * @return mixed
- */
- public function actionIndex()
- {
- $searchModel=new UserSearch();
- $dataProvider=$searchModel->search(Yii::$app->request->queryParams);
+ public function behaviors()
+ {
+ return ArrayHelper::merge(parent::behaviors(), [
+ 'access' => [
+ 'class' => \yii\filters\AccessControl::class,
+ 'rules' => [
+ 'authActions' => [
+ 'allow' => true,
+ 'actions' => ['index', 'view'],
+ 'roles' => ['@'],
+ 'matchCallback' => function () {
+ return \Yii::$app->user->identity->isAdmin;
+ },
+ ],
+ ],
+ ],
+ ]);
+ }
- return $this->render('index', [
- 'searchModel' => $searchModel,
- 'dataProvider' => $dataProvider,
- ]);
- }
-
- /**
- * Displays a single User model.
- * @param integer $id
- * @return mixed
- * @throws NotFoundHttpException if the model cannot be found
- */
- public function actionView($id)
- {
- return $this->render('view', [
- 'model' => $this->findModel($id),
- ]);
- }
+ /**
+ * Lists all User models.
+ * @return mixed
+ */
+ public function actionIndex()
+ {
+ $searchModel = new UserSearch();
+ $dataProvider = $searchModel->search(Yii::$app->request->queryParams);
- /**
- * Creates a new User model.
- * If creation is successful, the browser will be redirected to the 'view' page.
- * @return mixed
- */
- public function actionCreate()
- {
- $model=new User();
+ return $this->render('index', [
+ 'searchModel' => $searchModel,
+ 'dataProvider' => $dataProvider,
+ ]);
+ }
- if($model->load(Yii::$app->request->post()) && $model->save())
- {
- return $this->redirect(['view', 'id' => $model->id]);
- }
+ /**
+ * Displays a single User model.
+ * @param integer $id
+ * @return mixed
+ * @throws NotFoundHttpException if the model cannot be found
+ */
+ public function actionView($id)
+ {
+ return $this->render('view', [
+ 'model' => $this->findModel($id),
+ ]);
+ }
- return $this->render('create', [
- 'model' => $model,
- ]);
- }
+ /**
+ * Creates a new User model.
+ * If creation is successful, the browser will be redirected to the 'view' page.
+ * @return mixed
+ */
+ public function actionCreate()
+ {
+ $model = new User();
- /**
- * Updates an existing User model.
- * If update is successful, the browser will be redirected to the 'view' page.
- * @param integer $id
- * @return mixed
- * @throws NotFoundHttpException if the model cannot be found
- */
- public function actionUpdate($id)
- {
- $model=$this->findModel($id);
- if($model->load(Yii::$app->request->post()) && $model->save())
- {
- return $this->redirect(['view', 'id' => $model->id]);
- }
- return $this->render('update', [
- 'model' => $model,
- ]);
+ if ($model->load(Yii::$app->request->post()) && $model->save()) {
+ return $this->redirect(['view', 'id' => $model->id]);
}
- /**
- * Deletes an existing User model.
- * If deletion is successful, the browser will be redirected to the 'index' page.
- * @param integer $id
- * @return mixed
- * @throws NotFoundHttpException if the model cannot be found
- */
- public function actionDelete($id)
- {
- $this->findModel($id)->delete();
+ return $this->render('create', [
+ 'model' => $model,
+ ]);
+ }
- return $this->redirect(['index']);
+ /**
+ * Updates an existing User model.
+ * If update is successful, the browser will be redirected to the 'view' page.
+ * @param integer $id
+ * @return mixed
+ * @throws NotFoundHttpException if the model cannot be found
+ */
+ public function actionUpdate($id)
+ {
+ $model = $this->findModel($id);
+ if ($model->load(Yii::$app->request->post()) && $model->save()) {
+ return $this->redirect(['view', 'id' => $model->id]);
}
+ return $this->render('update', [
+ 'model' => $model,
+ ]);
+ }
+
+ /**
+ * Deletes an existing User model.
+ * If deletion is successful, the browser will be redirected to the 'index' page.
+ * @param integer $id
+ * @return mixed
+ * @throws NotFoundHttpException if the model cannot be found
+ */
+ public function actionDelete($id)
+ {
+ $this->findModel($id)->delete();
- /**
- * Finds the User model based on its primary key value.
- * If the model is not found, a 404 HTTP exception will be thrown.
- * @param integer $id
- * @return User the loaded model
- * @throws NotFoundHttpException if the model cannot be found
- */
- protected function findModel($id)
- {
- if(($model=\app\modules\settings\models\User::findOne($id)) !== null)
- {
- return $model;
- }
+ return $this->redirect(['index']);
+ }
- throw new NotFoundHttpException('The requested page does not exist.');
+ /**
+ * Finds the User model based on its primary key value.
+ * If the model is not found, a 404 HTTP exception will be thrown.
+ * @param integer $id
+ * @return User the loaded model
+ * @throws NotFoundHttpException if the model cannot be found
+ */
+ protected function findModel($id)
+ {
+ if (($model = \app\modules\settings\models\User::findOne($id)) !== null) {
+ return $model;
}
+
+ throw new NotFoundHttpException('The requested page does not exist.');
+ }
}
diff --git a/backend/modules/settings/models/ConfigureForm.php b/backend/modules/settings/models/ConfigureForm.php
index 8eb273406..58c6ea1f0 100644
--- a/backend/modules/settings/models/ConfigureForm.php
+++ b/backend/modules/settings/models/ConfigureForm.php
@@ -57,7 +57,7 @@ class ConfigureForm extends Model
public $leaderboard_show_zero;
public $time_zone;
public $target_days_new = 2;
- public $target_days_updated = 1;
+ public $target_days_updated = 0;
public $discord_news_webhook;
public $pf_state_limits;
public $stripe_apiKey;
@@ -472,7 +472,7 @@ public function rules()
[['online_timeout'], 'default', 'value' => 900],
[['spins_per_day'], 'default', 'value' => 2],
['target_days_new', 'default', 'value' => 1],
- ['target_days_updated', 'default', 'value' => 2],
+ ['target_days_updated', 'default', 'value' => 0],
[['event_start', 'event_end', 'registrations_start', 'registrations_end'], 'datetime', 'format' => 'php:Y-m-d H:i:s'],
[[
'dashboard_is_home',
diff --git a/backend/modules/settings/models/Sysconfig.php b/backend/modules/settings/models/Sysconfig.php
index 021aad19f..605c17b87 100644
--- a/backend/modules/settings/models/Sysconfig.php
+++ b/backend/modules/settings/models/Sysconfig.php
@@ -56,7 +56,7 @@ public function afterFind()
if ($this->val == 0 || $this->val == "")
$this->val = "";
else
- $this->val = Yii::$app->formatter->asDatetime($this->val, 'php:Y-m-d H:i:s', 'UTC');
+ $this->val = date('Y-m-d H:i:s', $this->val);
break;
default:
break;
@@ -70,7 +70,7 @@ public function beforeSave($insert)
$Q = sprintf("DROP EVENT IF EXISTS event_end_notification");
\Yii::$app->db->createCommand($Q)->execute();
if (!empty($this->val)) {
- $Q = sprintf("CREATE EVENT event_end_notification ON SCHEDULE AT '%s' DO INSERT INTO `notification`(player_id,category,title,body,archived) SELECT id,'swal:info',memc_get('sysconfig:event_end_notification_title'),memc_get('sysconfig:event_end_notification_body'),0 FROM player WHERE status=10", $this->val);
+ $Q = sprintf("CREATE EVENT event_end_notification ON SCHEDULE AT '%s' DO BEGIN INSERT INTO `notification`(player_id,category,title,body,archived) SELECT id,'swal:info',memc_get('sysconfig:event_end_notification_title'),memc_get('sysconfig:event_end_notification_body'),0 FROM player WHERE status=10; DO memc_set('event_finished',1); SELECT sleep(1) INTO OUTFILE '/tmp/event_finished';END", $this->val);
\Yii::$app->db->createCommand($Q)->execute();
$this->val = strtotime($this->val);
} else {
@@ -101,11 +101,9 @@ public function afterSave($insert, $changedAttributes)
if ($this->id === 'stripe_webhookLocalEndpoint' && array_key_exists('val', $changedAttributes)) {
$oldVal = $changedAttributes['val'];
$newVal = $this->val;
- if(($u=UrlRoute::findOne(['destination'=>'subscription/default/webhook']))!==NULL)
- {
- $u->updateAttributes(['source'=>$newVal]);
+ if (($u = UrlRoute::findOne(['destination' => 'subscription/default/webhook'])) !== NULL) {
+ $u->updateAttributes(['source' => $newVal]);
}
-
}
}
diff --git a/backend/views/layouts/main.php b/backend/views/layouts/main.php
index 707e5a4dd..75902eb66 100644
--- a/backend/views/layouts/main.php
+++ b/backend/views/layouts/main.php
@@ -12,12 +12,12 @@
$this->title = Yii::$app->sys->event_name . ' mUI: ' . $this->title;
AppAsset::register($this);
-$this->registerJsFile('@web/js/hljs/highlight.min.js',[
- 'depends' => [
- \yii\web\JqueryAsset::class
- ]
+$this->registerJsFile('@web/js/hljs/highlight.min.js', [
+ 'depends' => [
+ \yii\web\JqueryAsset::class
+ ]
]);
-$this->registerCssFile('@web/js/hljs/styles/a11y-dark.min.css',['depends' => [\yii\web\JqueryAsset::class]]);
+$this->registerCssFile('@web/js/hljs/styles/a11y-dark.min.css', ['depends' => [\yii\web\JqueryAsset::class]]);
?>
beginPage() ?>
@@ -31,6 +31,13 @@
registerCsrfMetaTags() ?>
= Html::encode($this->title) ?>
head() ?>
+cache->memcache->get('sysconfig:event_start') !== false && Yii::$app->cache->memcache->get('sysconfig:event_end') !== false): ?>
+
+
@@ -79,6 +86,9 @@
© = Html::a('Echothrust Solutions', 'https://www.echothrust.com/') ?> = date('Y') ?>
+
@@ -97,6 +107,5 @@
'markdown-highlighter'
);
?>
-
endPage() ?>
\ No newline at end of file
diff --git a/backend/web/js/site.js b/backend/web/js/site.js
index f35a68a21..8f2151908 100644
--- a/backend/web/js/site.js
+++ b/backend/web/js/site.js
@@ -3,3 +3,54 @@ $(function () {
$("[data-toggle='tooltip']").tooltip();
$("[data-toggle='popover']").popover();
});
+$(document).ready(function () {
+
+ var ticks = 0;
+
+ var x = setInterval(function () {
+ ticks++;
+
+ if (typeof countDownDate === 'undefined')
+ return;
+
+ if (countDownDate === 0) {
+ clearInterval(x);
+ return;
+ }
+
+ // Server-based time, tick-driven
+ var timeNow = countDownNow + (ticks * 1000);
+
+ var distance = countDownDate - timeNow;
+ var element = document.getElementById("event_countdown");
+ var msg = "The competition ends in: ";
+
+ if (countDownStart > 0 && countDownStart > timeNow) {
+ distance = countDownStart - timeNow;
+ msg = "The competition starts in: ";
+ }
+
+ if (distance < 0) {
+ clearInterval(x);
+ if (element)
+ element.innerHTML = 'The competition is finished ';
+ return;
+ }
+
+ var days = Math.floor(distance / (1000 * 60 * 60 * 24));
+ var hours = Math.floor((distance % (1000 * 60 * 60 * 24)) / (1000 * 60 * 60));
+ var minutes = Math.floor((distance % (1000 * 60 * 60)) / (1000 * 60));
+ var seconds = Math.floor((distance % (1000 * 60)) / 1000);
+
+ if (element) {
+ if (days > 0)
+ element.innerHTML = msg + days + "d " + hours + "h " + minutes + "m " + seconds + "s ";
+ else if (hours > 0)
+ element.innerHTML = msg + hours + "h " + minutes + "m " + seconds + "s ";
+ else if (minutes > 0)
+ element.innerHTML = msg + minutes + "m " + seconds + "s";
+ else
+ element.innerHTML = msg + seconds + "s";
+ }
+ }, 1000);
+});
\ No newline at end of file
diff --git a/contrib/event_shutdown.sh b/contrib/event_shutdown.sh
new file mode 100644
index 000000000..057c3091d
--- /dev/null
+++ b/contrib/event_shutdown.sh
@@ -0,0 +1,8 @@
+#!/bin/ksh
+PATH=/sbin:/usr/sbin:/bin:/usr/bin:/usr/X11R6/bin:/usr/local/sbin:/usr/local/bin
+rcctl stop openvpn findingsd heartbeatd inetd cron
+supervisorctl stop all
+backend vpn/killall
+backend vpn/logoutall
+backend target/destroy-instances
+ifconfig tun0 down
\ No newline at end of file
diff --git a/contrib/findingsd-federated.sql b/contrib/findingsd-federated.sql
index ac873b622..848499eae 100644
--- a/contrib/findingsd-federated.sql
+++ b/contrib/findingsd-federated.sql
@@ -116,6 +116,32 @@ CREATE TABLE `player_ssl` (
UNIQUE KEY `serial` (`serial`)
) ENGINE=FEDERATED DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci CONNECTION='mysql://{{db_user}}:{{db_pass}}@{{db_host}}:3306/{{db_name}}/player_ssl';
+DROP TABLE IF EXISTS `private_network`;
+CREATE TABLE `private_network` (
+ `id` int(11) NOT NULL AUTO_INCREMENT,
+ `player_id` int(11) unsigned DEFAULT NULL,
+ `name` varchar(255) DEFAULT NULL,
+ `team_accessible` tinyint(1) DEFAULT NULL,
+ `created_at` datetime DEFAULT NULL,
+ PRIMARY KEY (`id`),
+ KEY `idx-private_network-player_id` (`player_id`)
+) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci CONNECTION='mysql://{{db_user}}:{{db_pass}}@{{db_host}}:3306/{{db_name}}/private_network';
+
+DROP TABLE IF EXISTS `private_network_target`;
+CREATE TABLE `private_network_target` (
+ `id` int(11) NOT NULL AUTO_INCREMENT,
+ `private_network_id` int(11) DEFAULT NULL,
+ `target_id` int(11) NOT NULL,
+ `ip` int(11) unsigned DEFAULT NULL,
+ `state` smallint(6) unsigned DEFAULT 0,
+ `server_id` int(11) DEFAULT NULL,
+ `ipoctet` varchar(15) GENERATED ALWAYS AS (inet_ntoa(`ip`)) VIRTUAL,
+ PRIMARY KEY (`id`),
+ UNIQUE KEY `idx-unique-private_network_id-target_id` (`private_network_id`,`target_id`),
+ KEY `idx-private_network_target-private_network_id` (`private_network_id`),
+ KEY `idx-private_network_target-server_id` (`server_id`),
+ KEY `idx-private_network_target-target_id` (`target_id`)
+) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci CONNECTION='mysql://{{db_user}}:{{db_pass}}@{{db_host}}:3306/{{db_name}}/private_network_target';
DROP TABLE IF EXISTS `debuglogs`;
CREATE TABLE debuglogs (
@@ -241,3 +267,17 @@ BEGIN
END IF;
END
//
+
+
+DROP EVENT IF EXISTS `event_shutdown` //
+CREATE EVENT `event_shutdown` ON SCHEDULE EVERY 5 SECOND STARTS '2020-01-01 00:00:00' ON COMPLETION PRESERVE ENABLE DO
+BEGIN
+ IF (select memc_server_count()<1) THEN
+ select memc_servers_set('{{db_host}}:{{memc_port|default(11211)}}') INTO @memc_server_set_status;
+ END IF;
+
+ IF memc_get('event_finished') IS NOT NULL THEN
+ ALTER EVENT `event_shutdown` DISABLE;
+ SELECT 1 INTO OUTFILE '/tmp/event_finished';
+ END IF;
+END //
diff --git a/contrib/openvpn_tun0.conf b/contrib/openvpn_tun0.conf
index 6aea32ff1..516063fc8 100644
--- a/contrib/openvpn_tun0.conf
+++ b/contrib/openvpn_tun0.conf
@@ -12,7 +12,7 @@ client-config-dir /etc/openvpn/ccd
writepid /var/run/openvpn.pid
tls-auth /etc/openvpn/private/vpn-ta.key 0
replay-persist /etc/openvpn/replay-persist-file
-status /var/log/openvpn/openvpn-status.log
+status /var/log/openvpn/openvpn-status.log 5
log-append /var/log/openvpn/openvpn.log
#chroot /var/openvpn/chrootjail
crl-verify /etc/openvpn/crl.pem
@@ -29,7 +29,7 @@ data-ciphers AES-128-GCM
auth SHA256
compress
verb 1
-keepalive 3 240
+keepalive 3 30
mute-replay-warnings
script-security 2
diff --git a/contrib/sample-migrations/m000000_000001_system_settings.php b/contrib/sample-migrations/m000000_000001_system_settings.php
index 5b76f0a90..ff7323611 100644
--- a/contrib/sample-migrations/m000000_000001_system_settings.php
+++ b/contrib/sample-migrations/m000000_000001_system_settings.php
@@ -31,6 +31,10 @@ class m000000_000001_system_settings extends Migration
['id' => "leaderboard_show_zero", 'val' => "0"],
['id' => "leaderboard_visible_after_event_end", 'val' => "1"],
['id' => "leaderboard_visible_before_event_start", 'val' => "0"],
+ ['id' => "country_rankings", 'val' => "0"],
+ ['id' => "player_point_rankings", 'val' => "0"],
+ ['id' => "player_monthly_rankings", 'val' => "0"],
+
['id' => 'frontpage_scenario', 'val' => 'Welcome to our lovely event... Edit from backend Content => Frontpage Scenario'],
['id' => "event_end_notification_title", 'val' => "🎉 Our awesome echoCTF finished 🎉"],
['id' => "event_end_notification_body", 'val' => "The awesome echoCTF is over 🎉🎉🎉 Congratulations to you and your team 👏👏👏 Thank you for participating!!!"],
@@ -59,23 +63,38 @@ class m000000_000001_system_settings extends Migration
['id' => "team_manage_members", 'val' => "1"],
['id' => "team_required", 'val' => "1"],
['id' => 'team_visible_instances', 'val' => "1"],
+ ['id' => 'team_only_leaderboards', 'val' => "1"],
+ ['id' => 'team_encrypted_claims_allowed', 'val' => "1"],
+
/**
* Player settings
*/
['id' => "approved_avatar", 'val' => "1"],
['id' => "player_profile", 'val' => "1"],
['id' => "profile_visibility", 'val' => "public"],
- ['id' => "require_activation", 'val' => "0"],
- ['id' => 'player_require_identification', 'val' => "0"],
+ ['id' => "require_activation", 'val' => "1"],
+ ['id' => 'player_require_identification', 'val' => "1"],
['id' => 'all_players_vip', 'val' => "1"],
- ['id' => 'player_require_approval', 'val' => "0"],
+ ['id' => 'player_require_approval', 'val' => "1"],
['id' => 'profile_discord', 'val' => "1"],
['id' => 'profile_echoctf', 'val' => "1"],
['id' => 'profile_github', 'val' => "1"],
['id' => 'profile_settings_fields', 'val' => 'avatar,bio,country,discord,echoctf,email,fullname,github,pending_progress,twitter,username,visibility'],
+ ['id' => 'avatar_robohash_set', 'val' => 'set3'],
+
/**
* Configuration settings
*/
+ ['id' => 'target_guest_view_deny', 'val' => '1'],
+ ['id' => 'disable_ondemand_operations', 'val' => '1'],
+ ['id' => 'module_smartcity_disabled', 'val' => '1'],
+ ['id' => 'module_speedprogramming_enabled', 'val' => '0'],
+ ['id' => 'dashboard_news_total_pages', 'val' => '10'],
+ ['id' => 'dashboard_news_records_per_page', 'val' => '3'],
+ ['id' => 'force_https_urls', 'val' => '1'],
+ ['id' => 'subscriptions_menu_show', 'val' => '0'],
+ ['id' => 'log_failed_claims', 'val' => '1'],
+
['id' => 'academic_grouping', 'val' => '0'],
['id' => "challenge_home", 'val' => "uploads/"],
['id' => "dashboard_is_home", 'val' => "1"],
@@ -126,8 +145,11 @@ class m000000_000001_system_settings extends Migration
*/
public function safeUp()
{
- foreach ($this->news as $entry)
+ foreach ($this->news as $entry) {
+ $entry['created_at']=new \yii\db\Expression('NOW()');
+ $entry['updated_at']=new \yii\db\Expression('NOW()');
$this->upsert('news', $entry, true);
+ }
// delete not needed url routes
foreach ($this->delete_url_routes as $route) {
diff --git a/contrib/watchdog-action.py b/contrib/watchdog-action.py
new file mode 100644
index 000000000..d5eaa9cf5
--- /dev/null
+++ b/contrib/watchdog-action.py
@@ -0,0 +1,33 @@
+#!/usr/local/bin/python3
+#
+# pip install watchdog
+import argparse
+import os
+from watchdog.observers import Observer
+from watchdog.events import FileSystemEventHandler
+
+# CLI arguments
+parser = argparse.ArgumentParser()
+parser.add_argument("--file_path", required=True, help="Full path to the file to monitor")
+parser.add_argument("--action", required=True, help="Full path to the file we will execute")
+args = parser.parse_args()
+
+FULL_PATH = args.file_path
+FOLDER = os.path.dirname(FULL_PATH)
+TARGET_FILE = os.path.basename(FULL_PATH)
+ACTION = args.action
+
+class Handler(FileSystemEventHandler):
+ def __init__(self, observer):
+ self.observer = observer
+
+ def on_created(self, event):
+ if not event.is_directory and event.src_path == FULL_PATH:
+ os.system(ACTION)
+ self.observer.stop()
+
+observer = Observer()
+handler = Handler(observer)
+observer.schedule(handler, FOLDER, recursive=False)
+observer.start()
+observer.join()
diff --git a/contrib/watchdoger.py b/contrib/watchdoger.py
new file mode 100644
index 000000000..38651de7a
--- /dev/null
+++ b/contrib/watchdoger.py
@@ -0,0 +1,46 @@
+#!/usr/local/bin/python3
+#
+# pip install watchdog requests
+import argparse
+import os
+import requests
+from watchdog.observers import Observer
+from watchdog.events import FileSystemEventHandler
+
+# CLI arguments
+parser = argparse.ArgumentParser()
+parser.add_argument("--file_path", required=True, help="Full path to the file to monitor")
+parser.add_argument("--url", required=True, help="HTTP endpoint URL to POST to")
+parser.add_argument("--token", required=True, help="Bearer token for authorization")
+args = parser.parse_args()
+
+FULL_PATH = args.file_path
+FOLDER = os.path.dirname(FULL_PATH)
+TARGET_FILE = os.path.basename(FULL_PATH)
+URL = args.url
+BEARER_TOKEN = args.token
+
+class Handler(FileSystemEventHandler):
+ def __init__(self, observer):
+ self.observer = observer
+
+ def on_created(self, event):
+ if not event.is_directory and event.src_path == FULL_PATH:
+ response = requests.post(
+ URL,
+ headers={
+ "Authorization": f"Bearer {BEARER_TOKEN}",
+ "Content-Type": "application/json"
+ },
+ json={
+ "event": "apiNotifications"
+ }
+ )
+ print(f"Posted {event.src_path}, status: {response.status_code}")
+ self.observer.stop() # exit after sending
+
+observer = Observer()
+handler = Handler(observer)
+observer.schedule(handler, FOLDER, recursive=False)
+observer.start()
+observer.join()
diff --git a/docs/Websockets.md b/docs/Websockets.md
new file mode 100644
index 000000000..3b46b4756
--- /dev/null
+++ b/docs/Websockets.md
@@ -0,0 +1,59 @@
+# Websockets service
+
+echoCTF.RED provides player updates to the live players through the use of [ws-server](https://github.com/echoCTF/ws-server).
+
+The services that want to communicate an update to the current live players submit their events through the HTTP service of ws-server.
+
+The system can send messages to a specific player or all connected players through the `/publish` and `/broadcast` endpoints respectively.
+
+Currently the following events are implemented:
+
+* `notification`: Sends a direct notification, Alert or Sweetalerts.
+* `apiNotifications`: Tell the clients to perform an update of their in-page notifications.
+* `target`: Update the target card if currently visible
+
+## Examples
+
+* Notify all users to perform an `apiNotifications()` js call. Effectively fetch the latest notifications through ajax.
+
+```shell
+curl -X POST "http://localhost:8888/broadcast" \
+ -H "Authorization: Bearer YOURTOKEN" \
+ -H "Content-Type: application/json" \
+ -d '{ "event": "apiNotifications" }'
+```
+
+* Send a SweetAlert (`"type": "swap:info"`) notification to player with id `1`
+
+```shell
+curl -X POST "http://localhost:8888/publish" \
+ -H "Authorization: Bearer server123token" \
+ -H "Content-Type: application/json" \
+ -d '{
+ "player_id": "1",
+ "event": "notification",
+ "payload":
+ {
+ "title": "This is a notification",
+ "body": "This is the notification body",
+ "type": "swal:info"
+ }
+ }'
+```
+
+Note: Removing the `swal:` prefix from `type` sends a normal bootstrap alert notification.
+
+* Send an update for to player id `1` for updates on target id `2`
+
+```shell
+curl -X POST "http://localhost:8888/publish" \
+ -H "Authorization: Bearer server123token" \
+ -H "Content-Type: application/json" \
+ -d '{
+ "player_id": "1",
+ "event": "target",
+ "payload": { "id": "2" }
+ }'
+```
+
+This will execute the js code `targetUpdates(2)`.
diff --git a/frontend/commands/TesterController.php b/frontend/commands/TesterController.php
deleted file mode 120000
index b00eb05cc..000000000
--- a/frontend/commands/TesterController.php
+++ /dev/null
@@ -1 +0,0 @@
-../../backend/commands/TesterController.php
\ No newline at end of file
diff --git a/frontend/commands/TesterController.php b/frontend/commands/TesterController.php
new file mode 100644
index 000000000..4dc1dbdf3
--- /dev/null
+++ b/frontend/commands/TesterController.php
@@ -0,0 +1,88 @@
+stdout("*** TESTER COMMAND ***\n");
+
+ echo Table::widget([
+ 'headers' => ['Action', 'Usage', 'Description'],
+ 'rows' => [
+ ['Action' => 'tester/mail', 'Usage' => 'tester/mail email@example.com', 'Description' => 'Send a test mail with the current settings'],
+ ['Action' => 'tester/ws-notify', 'Usage' => 'tester/ws-notify player', 'Description' => 'Send a test websocket notification to the given player by id'],
+ ],
+ ]);
+ }
+
+ /**
+ * Test the mailer configuration by sending a test email.
+ *
+ * Usage:
+ * backend tester/mail test@example.com
+ *
+ * @param string $to Recipient email
+ */
+ public function actionMail($to)
+ {
+ $mailer = Yii::$app->mailer;
+ try {
+
+ $this->stdout("*** SETTINGS *** \n");
+ if (\Yii::$app->sys->mail_useFileTransport) {
+ $this->stdout("mail_useFileTransport: Yes\n");
+ $this->stdout("mails folder: " . @\Yii::getAlias('@app/runtime/mail/') . "\n");
+ }
+ if (\Yii::$app->sys->dsn) $this->stdout("dsn: " . \Yii::$app->sys->dsn . "\n");
+ if (\Yii::$app->sys->mail_from) $this->stdout("mail_from: " . \Yii::$app->sys->mail_from . "\n");
+ if (\Yii::$app->sys->mail_fromName) $this->stdout("mail_fromName: " . \Yii::$app->sys->mail_fromName . "\n");
+ if (\Yii::$app->sys->mail_host) $this->stdout("mail_host: " . \Yii::$app->sys->mail_host . "\n");
+ if (\Yii::$app->sys->mail_port) $this->stdout("mail_port: " . \Yii::$app->sys->mail_port . "\n");
+ if (\Yii::$app->sys->mail_username) $this->stdout("mail_username: " . \Yii::$app->sys->mail_username . "\n");
+ if (\Yii::$app->sys->mail_password) $this->stdout("mail_password: **USED BUT HIDDEN**\n");
+
+ $result = $mailer->compose()
+ ->setFrom([\Yii::$app->sys->mail_from => \Yii::$app->sys->mail_fromName])
+ ->setTo($to)
+ ->setSubject('echoCTF Installation Mail Test')
+ ->setTextBody("This is a test email sent at " . date('Y-m-d H:i:s'))
+ ->send();
+ if ($result) {
+ $this->stdout("✅ Test email successfully sent to {$to}\n");
+ } else {
+ $this->stderr("❌ Failed to send test email to {$to}\n");
+ }
+ } catch (\Symfony\Component\Mailer\Exception\TransportExceptionInterface $e) {
+ $this->stderr("❌ Transport error: " . $e->getMessage() . "\n");
+ } catch (\Throwable $e) {
+ $this->stderr("❌ Error: " . $e->getMessage() . "\n");
+ }
+ }
+
+ public function actionWsNotify($player)
+ {
+ $player=\app\models\Player::findOne($player);
+ $type = "info";
+ $title="title";
+ $body="body";
+ $cc = true;
+ $archive = true;
+ $apiOnly = false;
+ $player->notify($type, $title, $body, $cc, $archive, $apiOnly);
+ }
+
+}
diff --git a/frontend/components/Img.php b/frontend/components/Img.php
index f4371ad72..75126b2e1 100644
--- a/frontend/components/Img.php
+++ b/frontend/components/Img.php
@@ -55,12 +55,22 @@ public static function profile($profile)
imagestring($image, 6, 200, $lineheight*$i++, sprintf(\Yii::t('app',"root@%s:/# ./userinfo --profile %d"),\Yii::$app->sys->offense_domain,$profile->id),$textcolor);
imagestring($image, 6, 200, $lineheight*$i++, sprintf(\Yii::t('app',"username.....: %s"),$profile->owner->username),$greencolor);
imagestring($image, 6, 200, $lineheight*$i++, sprintf(\Yii::t('app',"joined.......: %s"),date("d.m.Y", strtotime($profile->owner->created))),$greencolor);
- imagestring($image, 6, 200, $lineheight*$i++, sprintf(\Yii::t('app',"points.......: %s"),number_format($profile->owner->playerScore->points)),$greencolor);
- imagestring($image, 6, 200, $lineheight*$i++, sprintf(\Yii::t('app',"rank.........: %s"),$profile->owner->playerScore->points == 0 ? "-":$profile->rank->ordinalPlace),$greencolor);
- imagestring($image, 6, 200, $lineheight*$i++, sprintf(\Yii::t('app',"level........: %d / %s"),$profile->experience->id, $profile->experience->name),$greencolor);
- imagestring($image, 6, 200, $lineheight*$i++, sprintf(\Yii::t('app',"flags........: %d"), $profile->totalTreasures),$greencolor);
- imagestring($image, 6, 200, $lineheight*$i++, sprintf(\Yii::t('app',"challenges...: %d / %d first"),$profile->challengesSolverCount, $profile->firstChallengeSolversCount),$greencolor);
- imagestring($image, 6, 200, $lineheight*$i++, sprintf(\Yii::t('app',"headshots....: %d / %d first"),$profile->headshotsCount, $profile->firstHeadshotsCount),$greencolor);
+ if (\Yii::$app->sys->team_only_leaderboards !== true)
+ {
+ imagestring($image, 6, 200, $lineheight*$i++, sprintf(\Yii::t('app',"points.......: %s"),number_format($profile->owner->playerScore->points)),$greencolor);
+ imagestring($image, 6, 200, $lineheight*$i++, sprintf(\Yii::t('app',"rank.........: %s"),$profile->owner->playerScore->points == 0 ? "-":$profile->rank->ordinalPlace),$greencolor);
+ imagestring($image, 6, 200, $lineheight*$i++, sprintf(\Yii::t('app',"level........: %d / %s"),$profile->experience->id, $profile->experience->name),$greencolor);
+ imagestring($image, 6, 200, $lineheight*$i++, sprintf(\Yii::t('app',"flags........: %d"), $profile->totalTreasures),$greencolor);
+ imagestring($image, 6, 200, $lineheight*$i++, sprintf(\Yii::t('app',"challenges...: %d / %d first"),$profile->challengesSolverCount, $profile->firstChallengeSolversCount),$greencolor);
+ imagestring($image, 6, 200, $lineheight*$i++, sprintf(\Yii::t('app',"headshots....: %d / %d first"),$profile->headshotsCount, $profile->firstHeadshotsCount),$greencolor);
+ }
+ else if($profile->owner->teamPlayer)
+ {
+ imagestring($image, 6, 200, $lineheight*$i++, \Yii::t('app',"team.........: {team}",['team'=>$profile->owner->team->name]),$greencolor);
+ imagestring($image, 6, 200, $lineheight*$i++, \Yii::t('app',"team rank....: {rank}",['rank'=>($profile->owner->team->rank !== null ? $profile->owner->team->rank->ordinalPlace : 'empty')]),$greencolor);
+ imagestring($image, 6, 200, $lineheight*$i++, \Yii::t('app',"team points..: {points,plural,=0{0 pts} =1{# pts} other{# pts}}",['points'=>($profile->owner->team->score !== null ? $profile->owner->team->score->points : 0)]),$greencolor);
+ imagestring($image, 6, 200, $lineheight*$i++, \Yii::t('app',"contributed..: {points,plural,=0{0 pts} =1{# pts} other{# pts}}",['points'=>($profile->owner->teamStreamPoints->points ?? 0)]),$greencolor);
+ }
imagedestroy($avatar);
imagedestroy($cover);
imagedestroy($src);
diff --git a/frontend/config/console.php b/frontend/config/console.php
index 4b146d6c7..61ad81f0e 100644
--- a/frontend/config/console.php
+++ b/frontend/config/console.php
@@ -1,54 +1,60 @@
'basic-console',
-// 'language' => 'el-GR',
- 'sourceLanguage' => 'en-US',
- 'basePath' => dirname(__DIR__),
- 'bootstrap' => ['log'],
- 'controllerNamespace' => 'app\commands',
- 'aliases' => [
- '@bower' => '@vendor/bower-asset',
- '@npm' => '@vendor/npm-asset',
- '@tests' => '@app/tests',
+$config = [
+ 'id' => 'basic-console',
+ // 'language' => 'el-GR',
+ 'sourceLanguage' => 'en-US',
+ 'basePath' => dirname(__DIR__),
+ 'bootstrap' => ['log'],
+ 'controllerNamespace' => 'app\commands',
+ 'aliases' => [
+ '@bower' => '@vendor/bower-asset',
+ '@npm' => '@vendor/npm-asset',
+ '@tests' => '@app/tests',
+ ],
+ 'modules' => [
+ 'team' => [
+ 'class' => 'app\modules\team\Module',
],
- 'components' => [
- 'i18n' => [
- 'translations' => [
- 'yii' => [
- 'class' => 'yii\i18n\PhpMessageSource',
- ],
- 'app*' => [
- 'class' => 'yii\i18n\PhpMessageSource',
- 'basePath' => '@app/messages',
- 'sourceLanguage' => 'en-US',
- 'fileMap' => [
- 'app' => 'app.php',
- 'app/error' => 'error.php',
- ],
- ],
- ],
+ ],
+
+ 'components' => [
+ 'i18n' => [
+ 'translations' => [
+ 'yii' => [
+ 'class' => 'yii\i18n\PhpMessageSource',
],
- 'sys'=> [
- 'class' => 'app\components\Sysconfig',
+ 'app*' => [
+ 'class' => 'yii\i18n\PhpMessageSource',
+ 'basePath' => '@app/messages',
+ 'sourceLanguage' => 'en-US',
+ 'fileMap' => [
+ 'app' => 'app.php',
+ 'app/error' => 'error.php',
+ ],
],
- 'cache' => $cache,
- 'log' => [
- 'targets' => [
- [
- 'class' => 'yii\log\FileTarget',
- 'levels' => ['error', 'warning'],
- ],
- ],
+ ],
+ ],
+ 'sys' => [
+ 'class' => 'app\components\Sysconfig',
+ ],
+ 'cache' => $cache,
+ 'log' => [
+ 'targets' => [
+ [
+ 'class' => 'yii\log\FileTarget',
+ 'levels' => ['error', 'warning'],
],
- 'db' => $db,
+ ],
],
- 'params' => $params,
- /*
+ 'db' => $db,
+ ],
+ 'params' => $params,
+ /*
'controllerMap' => [
'fixture' => [ // Fixture generation command line.
'class' => 'yii\faker\FixtureController',
@@ -57,13 +63,12 @@
*/
];
-if(YII_ENV_DEV)
-{
- // configuration adjustments for 'dev' environment
- $config['bootstrap'][]='gii';
- $config['modules']['gii']=[
- 'class' => 'yii\gii\Module',
- ];
+if (YII_ENV_DEV) {
+ // configuration adjustments for 'dev' environment
+ $config['bootstrap'][] = 'gii';
+ $config['modules']['gii'] = [
+ 'class' => 'yii\gii\Module',
+ ];
}
return $config;
diff --git a/frontend/config/web.php b/frontend/config/web.php
index 1adc34bee..05f104a1e 100644
--- a/frontend/config/web.php
+++ b/frontend/config/web.php
@@ -173,7 +173,7 @@
'name' => 'red',
'timeout' => 3600 * 12,
'cookieParams' => [
- 'secure' => true,
+ 'secure' => YII_ENV_DEV ? false : true,
'sameSite' => 'Lax',
'lifetime' => 3600 * 12,
'httpOnly' => true
@@ -185,7 +185,7 @@
'enableAutoLogin' => true,
'identityCookie' => [
'name' => '_identity-red',
- 'secure' => true,
+ 'secure' => YII_ENV_DEV ? false : true,
'httpOnly' => true,
'sameSite'=>'Strict'
],
diff --git a/frontend/models/Player.php b/frontend/models/Player.php
index 0f4720f07..669cc5b3a 100644
--- a/frontend/models/Player.php
+++ b/frontend/models/Player.php
@@ -408,21 +408,25 @@ public function notify($type = "info", $title, $body, $cc = true, $archive = tru
try {
$publisher = new \app\services\ServerPublisher(Yii::$app->params['serverPublisher']);
$publisher->publish($this->id, 'notification', ['type' => $type, 'title' => $title, 'body' => $body]);
- } catch(\Throwable $e) {
+ } catch (\Throwable $e) {
// on publishing error make sure we store the noticication as pending
- $cc=true;
- $archive=false;
+ $cc = true;
+ $archive = false;
Yii::error($e->getMessage());
}
if ($cc === true) {
$n = new \app\models\Notification;
$n->player_id = $this->id;
- $n->archived = $archive;
+ $n->archived = intval($archive);
$n->category = $type;
$n->title = $title;
$n->body = $body;
- return $n->save();
+ if (!$n->save()) {
+ Yii::error($n->getErrorSummary(true));
+ return false;
+ }
+ return true;
}
return true;
}
diff --git a/frontend/modules/target/actions/SpawnRestAction.php b/frontend/modules/target/actions/SpawnRestAction.php
index e7b0adb6d..916243e49 100644
--- a/frontend/modules/target/actions/SpawnRestAction.php
+++ b/frontend/modules/target/actions/SpawnRestAction.php
@@ -59,7 +59,7 @@ public function run($id,$team=false)
$ti=new TargetInstance;
$ti->player_id=Yii::$app->user->id;
$ti->target_id=$id;
- // pick the least used server currently
+ $ti->team_allowed=intval(\Yii::$app->sys->team_visible_instances);
if(\Yii::$app->user->identity->subscription !== null && \Yii::$app->user->identity->subscription->active > 0 && \Yii::$app->user->identity->subscription->product !== null)
{
$metadata = json_decode(\Yii::$app->user->identity->subscription->product->metadata);
@@ -67,6 +67,8 @@ public function run($id,$team=false)
$ti->team_allowed=($team===false ? 0 : 1);
}
}
+
+ // pick the least used server currently
$ti->server_id=intval(Yii::$app->db->createCommand('select id from server t1 left join target_instance t2 on t1.id=t2.server_id group by t1.id order by count(t2.server_id) limit 1')->queryScalar());
if($ti->save()!==false)
Yii::$app->session->setFlash('success', sprintf(\Yii::t('app','Spawning new instance for [%s]. You will receive a notification when the instance is up.'), $ti->target->name));
diff --git a/frontend/modules/target/models/Treasure.php b/frontend/modules/target/models/Treasure.php
index f58bf6ccd..ccc44983b 100644
--- a/frontend/modules/target/models/Treasure.php
+++ b/frontend/modules/target/models/Treasure.php
@@ -146,7 +146,7 @@ public function getTarget()
*/
public function getLocationRedacted()
{
- return str_replace($this->code,"*REDACTED*",$this->location);
+ return str_replace($this->code,"*REDACTED*",$this->solution);
}
public static function find()
diff --git a/frontend/modules/team/controllers/DefaultController.php b/frontend/modules/team/controllers/DefaultController.php
index d64f9b9b4..4ca6c0a39 100644
--- a/frontend/modules/team/controllers/DefaultController.php
+++ b/frontend/modules/team/controllers/DefaultController.php
@@ -221,7 +221,6 @@ public function actionView($token)
'pageSize' => 10,
]
]);
-
return $this->render('view', [
'team' => $model,
'teamInstanceProvider' => $teamInstanceProvider,
@@ -264,8 +263,23 @@ public function actionMine()
]
]);
+ $teamNetworks = \app\modules\network\models\PrivateNetwork::find()->forTeam(\Yii::$app->user->identity->team->id);
+ $teamNetworksProvider = new ActiveDataProvider([
+ 'query' => $teamNetworks,
+ 'pagination' => [
+ 'pageSizeParam' => 'networks-perpage',
+ 'pageParam' => 'networks-page',
+ 'pageSize' => 5,
+ ],
+ 'sort' => ['defaultOrder' => ['name' => SORT_ASC]],
+ ]);
+
+ $subQuery = TeamStream::find()
+ ->select('stream_id')
+ ->where(['team_id' => \Yii::$app->user->identity->team->id]);
+
$stream = \app\models\Stream::find()->select('stream.*,TS_AGO(ts) as ts_ago')
- ->where(['stream.player_id' => $teamPlayers])
+ ->where(['id' => $subQuery])
->orderBy(['ts' => SORT_DESC, 'id' => SORT_DESC]);
$streamProvider = new ActiveDataProvider([
'query' => $stream,
@@ -314,7 +328,9 @@ public function actionMine()
'teamTargetsProvider' => $targetProgressProvider,
'headshotsProvider' => $headshotsProvider,
'solverProvider' => $solverProvider,
- 'team' => Yii::$app->user->identity->team
+ 'team' => Yii::$app->user->identity->team,
+ 'networksProvider' => $teamNetworksProvider,
+
]);
}
/**
diff --git a/frontend/modules/team/models/Team.php b/frontend/modules/team/models/Team.php
index b84435fe7..258454e7b 100644
--- a/frontend/modules/team/models/Team.php
+++ b/frontend/modules/team/models/Team.php
@@ -25,7 +25,8 @@
* @property Player $owner
* @property TeamPlayer[] $teamPlayers
* @property Player[] $players
- */
+ * @property TeamInvite $inviteOrCreate
+*/
class Team extends \yii\db\ActiveRecord
{
public $uploadedAvatar;
@@ -142,7 +143,7 @@ public function getRank()
*/
public function getTeamPlayers()
{
- return $this->hasMany(TeamPlayer::class, ['team_id' => 'id'])->orderBy(['approved'=>SORT_DESC,'ts'=>SORT_ASC]);
+ return $this->hasMany(TeamPlayer::class, ['team_id' => 'id'])->orderBy(['approved' => SORT_DESC, 'ts' => SORT_ASC]);
}
/**
@@ -161,6 +162,28 @@ public function getInvite()
return $this->hasOne(TeamInvite::class, ['team_id' => 'id']);
}
+ /**
+ * Returns the related TeamInvite model.
+ *
+ * If the invite does not exist yet, it will be created, saved,
+ * and populated into the `invite` relation.
+ *
+ * @return TeamInvite the existing or newly created invite model
+ * @throws \RuntimeException if the invite cannot be created
+ */
+ public function getInviteOrCreate()
+ {
+ if ($this->invite === null) {
+ $invite = new TeamInvite(['team_id'=>$this->id,'token'=>Yii::$app->security->generateRandomString(8)]);
+ if (!$invite->save()) {
+ throw new \RuntimeException('Failed to create TeamInvite');
+ }
+ $this->populateRelation('invite', $invite);
+ }
+
+ return $this->invite;
+ }
+
public function getValidLogo()
{
if ($this->logo === null || trim($this->logo) === '')
@@ -286,21 +309,19 @@ public function getAcademicWord()
/**
* Generate a new invite url
*/
- public function generate_invite(){
- if($this->invite) {
- $this->invite->token=Yii::$app->security->generateRandomString(8);
- if(!$this->invite->save())
- {
- throw new UserException(Yii::t('app','Failed to save invite. [{error}]',['error'=>implode(" ",$this->invite->getErrors())]));
+ public function generate_invite()
+ {
+ if ($this->invite) {
+ $this->invite->token = Yii::$app->security->generateRandomString(8);
+ if (!$this->invite->save()) {
+ throw new UserException(Yii::t('app', 'Failed to save invite. [{error}]', ['error' => implode(" ", $this->invite->getErrors())]));
}
- }
- else {
- $ti=new TeamInvite;
- $ti->team_id=$this->id;
- $ti->token=Yii::$app->security->generateRandomString(8);
- if(!$ti->save())
- {
- throw new UserException(Yii::t('app','Failed to save invite. [{error}]',['error'=>implode(" ",$ti->getErrors())]));
+ } else {
+ $ti = new TeamInvite;
+ $ti->team_id = $this->id;
+ $ti->token = Yii::$app->security->generateRandomString(8);
+ if (!$ti->save()) {
+ throw new UserException(Yii::t('app', 'Failed to save invite. [{error}]', ['error' => implode(" ", $ti->getErrors())]));
}
}
}
diff --git a/frontend/themes/material/layouts/main.php b/frontend/themes/material/layouts/main.php
index a66aacfcc..80d5972ae 100644
--- a/frontend/themes/material/layouts/main.php
+++ b/frontend/themes/material/layouts/main.php
@@ -50,6 +50,7 @@
sys->event_start!==false && Yii::$app->sys->event_end!==false):?>
@@ -71,7 +72,7 @@
=\Yii::$app->sys->{"footer_logos"}?>
- © =date("Y")?>, made with
favorite by
+ © 2012-=date("y")?>, made with
favorite by
echothrust with
echo CTF
diff --git a/frontend/themes/material/modules/target/views/default/_target_card.php b/frontend/themes/material/modules/target/views/default/_target_card.php
index 284e2b9c8..53779fdcd 100644
--- a/frontend/themes/material/modules/target/views/default/_target_card.php
+++ b/frontend/themes/material/modules/target/views/default/_target_card.php
@@ -21,10 +21,10 @@
else
$display_ip=Html::a($target_ip,$target_ip,["class"=>'copy-to-clipboard text-danger text-bold','swal-data'=>"Copied to clipboard",'data-toggle'=>'tooltip','title'=>\Yii::t('app',"The IP of your private instance. Click to copy IP to clipboard.")]);
}
-if($target_ip=='0.0.0.0')
-{
- $this->registerJs("targetUpdates({$target->id});", \yii\web\View::POS_READY);
-}
+//if($target_ip=='0.0.0.0')
+//{
+// $this->registerJs("targetUpdates({$target->id});", \yii\web\View::POS_READY);
+//}
$subtitleARR=[$target->category,ucfirst($target->getDifficultyText($target->average_rating)),boolval($target->rootable) ? "Rootable" : "Non rootable",$target->timer===false ? null:'Timed'];
$subtitle=implode(", ",array_filter($subtitleARR));
Card::begin([
@@ -34,7 +34,7 @@
'icon'=>sprintf(' ', $target->logo),
'color'=>'target',
'subtitle'=>$subtitle,
- 'title'=>sprintf('%s / %s ', $target->name, $display_ip),
+ 'title'=>sprintf('%s / %s ', $target->name, $target->id, $display_ip),
'footer'=>sprintf('%s
%s ', $target->purpose, TargetCardActions::widget(['model'=>$target,'identity'=>$identity]) ),
]);
echo " ", $target->total_treasures, ": Flag".($target->total_treasures > 1 ? 's' : '')." ";
diff --git a/frontend/themes/material/modules/target/views/default/_target_metadata.php b/frontend/themes/material/modules/target/views/default/_target_metadata.php
index f96d082ec..2ee835d76 100644
--- a/frontend/themes/material/modules/target/views/default/_target_metadata.php
+++ b/frontend/themes/material/modules/target/views/default/_target_metadata.php
@@ -1,11 +1,13 @@
user->isGuest && $metadata):?>
+ formatter->divID; ?>
user->identity->isAdmin):?>
- scenario)):?>=\Yii::t('app','Scenario')?> : =\yii\helpers\Markdown::process($metadata->scenario,'gfm')?>
- instructions)):?>=\Yii::t('app','Instructions')?> : =\yii\helpers\Markdown::process($metadata->instructions,'gfm')?>
- solution)):?>=\Yii::t('app','Solution')?> : =\yii\helpers\Markdown::process($metadata->solution,'gfm')?>
+ scenario)):?>=\Yii::t('app','Scenario')?> : formatter->divID = 'markdown-scenario'; echo \Yii::$app->formatter->asMarkdown($metadata->scenario)?>
+ instructions)):?>=\Yii::t('app','Instructions')?> : formatter->divID = 'markdown-instructions'; echo \Yii::$app->formatter->asMarkdown($metadata->instructions)?>
+ solution)):?>=\Yii::t('app','Solution')?> : formatter->divID = 'markdown-solution'; echo \Yii::$app->formatter->asMarkdown($metadata->solution)?>
- pre_credits)):?>=\Yii::t('app','Pre exploitation credits')?> : =\yii\helpers\Markdown::process($metadata->pre_credits,'gfm')?>
- pre_exploitation)):?>=\Yii::t('app','Pre exploitation details')?> : =\yii\helpers\Markdown::process($metadata->pre_exploitation,'gfm')?>
- player_id===Yii::$app->user->id && $target->progress==100) || Yii::$app->user->identity->isAdmin) && !empty($metadata->post_exploitation)):?>=\Yii::t('app','Post exploitation')?> : =\yii\helpers\Markdown::process($metadata->post_exploitation,'gfm')?>
- player_id===Yii::$app->user->id && $target->progress==100) || Yii::$app->user->identity->isAdmin) && !empty($metadata->post_credits)):?>=\Yii::t('app','Post exploitation credits')?> : =\yii\helpers\Markdown::process($metadata->post_credits,'gfm')?>
+ pre_credits)):?>=\Yii::t('app','Pre exploitation credits')?> : formatter->divID = 'markdown-pre-credits'; echo \Yii::$app->formatter->asMarkdown($metadata->pre_credits)?>
+ pre_exploitation)):?>=\Yii::t('app','Pre exploitation details')?> : formatter->divID = 'markdown-pre-exploitation'; echo \Yii::$app->formatter->asMarkdown($metadata->pre_exploitation)?>
+ player_id===Yii::$app->user->id && $target->progress==100) || Yii::$app->user->identity->isAdmin) && !empty($metadata->post_exploitation)):?>=\Yii::t('app','Post exploitation')?> : formatter->divID = 'markdown-post-exploitation'; echo \Yii::$app->formatter->asMarkdown($metadata->post_exploitation)?>
+ player_id===Yii::$app->user->id && $target->progress==100) || Yii::$app->user->identity->isAdmin) && !empty($metadata->post_credits)):?>=\Yii::t('app','Post exploitation credits')?> : formatter->divID = 'markdown-post-credits'; echo \Yii::$app->formatter->asMarkdown($metadata->post_credits)?>
+ formatter->divID=$oldId; ?>
diff --git a/frontend/themes/material/modules/target/views/default/_versus.php b/frontend/themes/material/modules/target/views/default/_versus.php
index 83185c2f3..cc5e36332 100644
--- a/frontend/themes/material/modules/target/views/default/_versus.php
+++ b/frontend/themes/material/modules/target/views/default/_versus.php
@@ -29,6 +29,18 @@
$this->registerMetaTag(['name' => 'game:points', 'content' => '0']);
$this->registerMetaTag(['name' => 'article:published_time', 'content' => $headshot->created_at]);
}
+$this->registerJsFile('@web/js/showdown.min.js',[
+ 'depends' => [
+ \yii\web\JqueryAsset::class
+ ]
+]);
+$this->registerJsFile('@web/assets/hljs/highlight.min.js',[
+ 'depends' => [
+ \yii\web\JqueryAsset::class
+ ]
+]);
+$this->registerCssFile('@web/assets/hljs/styles/a11y-dark.min.css',['depends' => ['app\assets\MaterialAsset']]);
+
?>
@@ -167,4 +179,11 @@
= $this->render('_target_writeups', ['writeups' => $target->writeups, 'active' => false, 'writeups_activated' => (PTH::findOne(['player_id' => Yii::$app->user->id, 'target_id' => $target->id]) !== null || Headshot::findOne(['player_id' => Yii::$app->user->id, 'target_id' => $target->id]) !== null)]); ?>
-
\ No newline at end of file
+
+registerJs(
+ 'hljs.highlightAll();',
+ $this::POS_READY,
+ 'markdown-highlighter'
+);
+?>
diff --git a/frontend/themes/material/modules/team/views/default/_team_card.php b/frontend/themes/material/modules/team/views/default/_team_card.php
index 08939f0de..8b540334c 100644
--- a/frontend/themes/material/modules/team/views/default/_team_card.php
+++ b/frontend/themes/material/modules/team/views/default/_team_card.php
@@ -89,9 +89,9 @@
user->identity->isAdmin || (Yii::$app->user->identity->team && !$model->inviteonly || ($invite === false && $listing === true))) : ?>
= Html::a('View Team', ['/team/default/view', 'token' => $model->token], ['class' => 'btn block text-dark text-bold orbitron' . (!$model->inviteonly ? ' btn-info' : ' btn-warning')]) ?>
- getTeamPlayers()->count()) < Yii::$app->sys->members_per_team && !Yii::$app->user->identity->team && !$model->locked && $model->invite) : ?>
- = Html::a('Join Team', ['/team/default/join', 'token' => $model->invite->token], ['class' => 'btn block btn-primary text-dark text-bold orbitron', 'data-method' => 'POST', 'data' => ['confirm' => 'You are about to join this team. Your membership will have to be confirmed by the team captain.', 'method' => 'POST']]) ?>
+ getTeamPlayers()->count()) < Yii::$app->sys->members_per_team && !Yii::$app->user->identity->team && !$model->locked && $model->inviteOrCreate) : ?>
+ = Html::a('Join Team', ['/team/default/join', 'token' => $model->inviteOrCreate->token], ['class' => 'btn block btn-primary text-dark text-bold orbitron', 'data-method' => 'POST', 'data' => ['confirm' => 'You are about to join this team. Your membership will have to be confirmed by the team captain.', 'method' => 'POST']]) ?>
-
\ No newline at end of file
+
diff --git a/frontend/themes/material/modules/team/views/default/view.php b/frontend/themes/material/modules/team/views/default/view.php
index 23e71ed62..4a34bd3be 100644
--- a/frontend/themes/material/modules/team/views/default/view.php
+++ b/frontend/themes/material/modules/team/views/default/view.php
@@ -19,10 +19,10 @@
= \Yii::t('app', 'Details for team') ?> [= Html::encode($team->name) ?>]
getTeamPlayers()->count() < Yii::$app->sys->members_per_team): ?>
- owner_id === Yii::$app->user->id || ($team->invite && !$team->inviteonly)): ?>
+ owner_id === Yii::$app->user->id || ($team->inviteOrCreate && !$team->inviteonly)): ?>
owner_id === Yii::$app->user->id) $class .= ' copy-to-clipboard'; ?>
= \Yii::t('app', 'Allow other players to join the team easily by providing them with this link:') ?>
- = Html::a(Url::to(['/team/default/invite', 'token' => $team->invite->token], 'https'), Url::to(['/team/default/invite', 'token' => $team->invite->token], 'https'), ['class' => $class, 'swal-data' => 'Copied to clipboard!']); ?>
+ = Html::a(Url::to(['/team/default/invite', 'token' => $team->inviteOrCreate->token], 'https'), Url::to(['/team/default/invite', 'token' => $team->inviteOrCreate->token], 'https'), ['class' => $class, 'swal-data' => 'Copied to clipboard!']); ?>
= Html::encode($team->recruitment) ?>
@@ -179,8 +179,8 @@
=$this->render('../_profile_tabs',['profile'=>$profile,'game'=>$game,'headshots'=>$headshots]);?>
+sys->team_only_leaderboards!==true):?>
+
diff --git a/frontend/web/429.html b/frontend/web/429.html
index edd87e5a2..114f00e97 100644
--- a/frontend/web/429.html
+++ b/frontend/web/429.html
@@ -2,7 +2,6 @@
-
echoCTF: Error 429