├── .github └── workflows │ └── test.yml ├── .gitignore ├── .idea ├── .gitignore ├── Refractor.iml ├── copyright │ ├── Notice.xml │ └── profiles_settings.xml ├── dataSources.xml ├── modules.xml ├── scopes │ └── Refractor_Copyright.xml ├── sqldialects.xml └── vcs.xml ├── Dockerfile ├── LICENSE ├── Makefile ├── README.md ├── compose-frontend-svelte.yml ├── default ├── README.md ├── docker │ └── docker-compose.yml ├── kratos │ └── kratos.yml ├── nginx │ └── app.conf ├── postgres │ └── init.sql └── svelte │ ├── .env.production │ └── README.md ├── deploy └── kratos │ └── identity.schema.json ├── dev ├── kratos │ ├── identity.schema.json │ └── kratos.dev.yml └── postgres │ └── init.sql ├── docker-compose.dev.yml ├── quickstart.sh ├── src ├── auth │ ├── login.go │ ├── public.go │ ├── recovery.go │ ├── root.go │ ├── settings.go │ ├── setupcomplete.go │ ├── static │ │ └── style.css │ ├── templates │ │ ├── login.html │ │ ├── partial-foot.html │ │ ├── partial-head.html │ │ ├── recovery.html │ │ ├── settings.html │ │ ├── setupcomplete.html │ │ └── verification.html │ └── verification.go ├── authcheckers │ └── generic.go ├── domain │ ├── api.go │ ├── args.go │ ├── attachment.go │ ├── auth.go │ ├── chat.go │ ├── command_executor.go │ ├── error.go │ ├── game.go │ ├── group.go │ ├── http.go │ ├── infraction.go │ ├── mail.go │ ├── mocks │ │ ├── AttachmentRepo.go │ │ ├── AttachmentService.go │ │ ├── AuthRepo.go │ │ ├── AuthService.go │ │ ├── Authorizer.go │ │ ├── ChatRepo.go │ │ ├── ChatService.go │ │ ├── ClientCreator.go │ │ ├── CommandExecutor.go │ │ ├── FlaggedWordRepo.go │ │ ├── FlaggedWordService.go │ │ ├── Game.go │ │ ├── GameRepo.go │ │ ├── GameService.go │ │ ├── GroupRepo.go │ │ ├── GroupService.go │ │ ├── InfractionRepo.go │ │ ├── InfractionService.go │ │ ├── MailService.go │ │ ├── PlayerNameRepo.go │ │ ├── PlayerRepo.go │ │ ├── PlayerStatsService.go │ │ ├── RCONClient.go │ │ ├── RCONService.go │ │ ├── ServerRepo.go │ │ ├── ServerService.go │ │ ├── StatsRepo.go │ │ ├── UserMetaRepo.go │ │ ├── UserService.go │ │ └── WebsocketService.go │ ├── platform.go │ ├── player.go │ ├── player_stats.go │ ├── querybuilder.go │ ├── rcon.go │ ├── search.go │ ├── server.go │ ├── stats.go │ ├── user.go │ ├── validation.go │ └── websocket.go ├── games │ ├── minecraft │ │ └── minecraft.go │ └── mordhau │ │ └── mordhau.go ├── go.mod ├── go.sum ├── internal │ ├── attachment │ │ ├── repos │ │ │ └── postgres │ │ │ │ ├── attachment_repo.go │ │ │ │ └── attachment_repo_test.go │ │ └── service │ │ │ └── attachment_service.go │ ├── auth │ │ ├── repos │ │ │ └── kratos │ │ │ │ └── authrepo_kratos.go │ │ └── service │ │ │ ├── auth_service.go │ │ │ └── auth_service_test.go │ ├── authorizer │ │ ├── authorizer.go │ │ ├── authorizer_test.go │ │ ├── refractor_authorizer.go │ │ └── server_authorizer.go │ ├── chat │ │ ├── delivery │ │ │ └── http │ │ │ │ └── chat_handler.go │ │ ├── repos │ │ │ └── postgres │ │ │ │ ├── chat_repo.go │ │ │ │ └── chat_repo_test.go │ │ └── service │ │ │ ├── chat_service.go │ │ │ └── chat_service_test.go │ ├── command_executor │ │ ├── command_executor.go │ │ ├── command_executor_test.go │ │ └── infraction_command.go │ ├── flaggedword │ │ ├── repos │ │ │ └── postgres │ │ │ │ ├── flagged_word_repo.go │ │ │ │ └── flagged_word_repo_test.go │ │ └── service │ │ │ ├── flagged_word_service.go │ │ │ └── flagged_word_service_test.go │ ├── game │ │ ├── delivery │ │ │ └── http │ │ │ │ └── game_handler.go │ │ ├── repos │ │ │ └── file │ │ │ │ └── game_repo.go │ │ └── service │ │ │ ├── game_service.go │ │ │ └── game_service_test.go │ ├── group │ │ ├── delivery │ │ │ └── http │ │ │ │ ├── group_handler.go │ │ │ │ └── group_handler_test.go │ │ ├── repos │ │ │ └── postgres │ │ │ │ ├── group_repo.go │ │ │ │ └── group_repo_test.go │ │ └── service │ │ │ ├── group_service.go │ │ │ └── group_service_test.go │ ├── infraction │ │ ├── delivery │ │ │ └── http │ │ │ │ └── infraction_handler.go │ │ ├── repos │ │ │ └── postgres │ │ │ │ ├── infraction_repo.go │ │ │ │ └── infraction_repo_test.go │ │ ├── service │ │ │ ├── infraction_service.go │ │ │ └── infraction_service_test.go │ │ └── types │ │ │ ├── ban.go │ │ │ ├── kick.go │ │ │ ├── mute.go │ │ │ └── warning.go │ ├── mail │ │ ├── service │ │ │ └── mail_service.go │ │ └── templates │ │ │ └── welcome.html │ ├── player │ │ ├── delivery │ │ │ └── http │ │ │ │ └── player_handler.go │ │ ├── repos │ │ │ └── postgres │ │ │ │ ├── player │ │ │ │ ├── player_repo.go │ │ │ │ └── player_repo_test.go │ │ │ │ └── playername │ │ │ │ ├── playername_repo.go │ │ │ │ └── playername_repo_test.go │ │ └── service │ │ │ └── player_service.go │ ├── player_stats │ │ └── service │ │ │ ├── player_stats_service.go │ │ │ └── player_stats_service_test.go │ ├── rcon │ │ ├── clientcreator │ │ │ └── clientcreator.go │ │ └── service │ │ │ ├── rcon_service.go │ │ │ └── rcon_service_test.go │ ├── search │ │ ├── delivery │ │ │ └── http │ │ │ │ └── search_handler.go │ │ └── service │ │ │ ├── search_service.go │ │ │ └── search_service_test.go │ ├── server │ │ ├── delivery │ │ │ └── http │ │ │ │ └── server_handler.go │ │ ├── repos │ │ │ └── postgres │ │ │ │ ├── server_repo.go │ │ │ │ └── server_repo_test.go │ │ └── service │ │ │ ├── server_service.go │ │ │ └── server_service_test.go │ ├── stats │ │ ├── delivery │ │ │ └── http │ │ │ │ └── stats_handler.go │ │ ├── repos │ │ │ └── postgres │ │ │ │ ├── stats_repo.go │ │ │ │ └── stats_repo_test.go │ │ └── service │ │ │ └── stats_service.go │ ├── user │ │ ├── delivery │ │ │ └── http │ │ │ │ └── user_handler.go │ │ ├── repos │ │ │ └── postgres │ │ │ │ ├── user_repo.go │ │ │ │ └── user_repo_test.go │ │ └── service │ │ │ ├── user_service.go │ │ │ └── user_service_test.go │ ├── watchdog │ │ └── rconserver.go │ └── websocket │ │ ├── delivery │ │ └── http │ │ │ └── websocket_handler.go │ │ └── service │ │ └── websocket_service.go ├── main.go ├── migrations │ ├── 20210707174342_create_update_modified_at_function.down.sql │ ├── 20210707174342_create_update_modified_at_function.up.sql │ ├── 20210710155956_create_groups_table.down.sql │ ├── 20210710155956_create_groups_table.up.sql │ ├── 20210710155960_create_usergroups_table.down.sql │ ├── 20210710155960_create_usergroups_table.up.sql │ ├── 20210710161007_create_servers_table.down.sql │ ├── 20210710161007_create_servers_table.up.sql │ ├── 20210712140232_create_servergroups_table.down.sql │ ├── 20210712140232_create_servergroups_table.up.sql │ ├── 20210717152944_create_useroverrides_table.down.sql │ ├── 20210717152944_create_useroverrides_table.up.sql │ ├── 20210720160756_create_groups_reorder_func.down.sql │ ├── 20210720160756_create_groups_reorder_func.up.sql │ ├── 20210727131757_create_usermeta_table.down.sql │ ├── 20210727131757_create_usermeta_table.up.sql │ ├── 20210821133942_create_players_table.down.sql │ ├── 20210821133942_create_players_table.up.sql │ ├── 20210821135938_create_playernames_table.down.sql │ ├── 20210821135938_create_playernames_table.up.sql │ ├── 20210830202202_create_infractions_table.down.sql │ ├── 20210830202202_create_infractions_table.up.sql │ ├── 20210908163101_create_attachments_table.down.sql │ ├── 20210908163101_create_attachments_table.up.sql │ ├── 20210915174147_search_player_by_name_func.down.sql │ ├── 20210915174147_search_player_by_name_func.up.sql │ ├── 20210926161615_create_chatmessages_table.down.sql │ ├── 20210926161615_create_chatmessages_table.up.sql │ ├── 20210929185052_chatmessages_search_setup.down.sql │ ├── 20210929185052_chatmessages_search_setup.up.sql │ ├── 20211003133238_create_flaggedwords_table.down.sql │ ├── 20211003133238_create_flaggedwords_table.up.sql │ ├── 20211011132959_create_infractionchatmessages_table.down.sql │ ├── 20211011132959_create_infractionchatmessages_table.up.sql │ ├── 20211015125247_create_userplayers_table.down.sql │ ├── 20211015125247_create_userplayers_table.up.sql │ ├── 20211017134801_infraction_repeal_setup.down.sql │ ├── 20211017134801_infraction_repeal_setup.up.sql │ ├── 20211018175905_install_systemtables_extension.down.sql │ ├── 20211018175905_install_systemtables_extension.up.sql │ ├── 20211114003439_adjust_permanent_infraction_durations.down.sql │ └── 20211114003439_adjust_permanent_infraction_durations.up.sql ├── params │ ├── attachment.go │ ├── flagged_word.go │ ├── game.go │ ├── group.go │ ├── helpers.go │ ├── infraction.go │ ├── rules │ │ ├── rulegroup.go │ │ ├── rulegroup_test.go │ │ └── rules.go │ ├── search.go │ ├── server.go │ ├── user.go │ ├── validator.go │ └── validators │ │ └── inArr.go ├── pkg │ ├── aeshelper │ │ └── aes.go │ ├── api │ │ ├── errorhandler.go │ │ ├── middleware │ │ │ ├── enforcer.go │ │ │ └── protect.go │ │ ├── permissions.go │ │ └── request.go │ ├── bitperms │ │ ├── bitperms.go │ │ └── bitperms_test.go │ ├── broadcast │ │ ├── broadcast.go │ │ └── broadcast_test.go │ ├── conf │ │ └── config.go │ ├── env │ │ ├── env.go │ │ └── env_test.go │ ├── perms │ │ └── permissions.go │ ├── pointer │ │ ├── depointer.go │ │ └── depointer_test.go │ ├── querybuilders │ │ └── psqlqb │ │ │ ├── postgres_querybuilder.go │ │ │ └── postgres_querybuilder_test.go │ ├── regexutils │ │ ├── named.go │ │ └── named_test.go │ ├── structutils │ │ ├── reflection.go │ │ └── reflection_test.go │ ├── tmpl │ │ └── renderer.go │ ├── websocket │ │ ├── client.go │ │ ├── pool.go │ │ └── upgrader.go │ └── whitelist │ │ ├── whitelist.go │ │ └── whitelist_test.go └── platforms │ ├── mojang │ └── mojang.go │ └── playfab │ └── playfab.go └── update.sh /.github/workflows/test.yml: -------------------------------------------------------------------------------- 1 | on: [push, pull_request] 2 | name: Test 3 | jobs: 4 | test: 5 | strategy: 6 | matrix: 7 | go-version: [1.17.x] 8 | os: [ubuntu-latest] 9 | runs-on: ${{ matrix.os }} 10 | steps: 11 | - name: Install Go 12 | uses: actions/setup-go@v2 13 | with: 14 | go-version: ${{ matrix.go-version }} 15 | - name: Checkout code 16 | uses: actions/checkout@v2 17 | - name: Test 18 | working-directory: ./src 19 | run: go test ./... 20 | 21 | test-cache: 22 | runs-on: ubuntu-latest 23 | steps: 24 | - name: Install Go 25 | uses: actions/setup-go@v2 26 | with: 27 | go-version: 1.17.x 28 | - name: Checkout code 29 | uses: actions/checkout@v2 30 | - uses: actions/cache@v2 31 | with: 32 | path: | 33 | ~/go/pkg/mod 34 | ~/.cache/go-build 35 | key: ${{ runner.os }}-go-${{ hashFiles('**/go.sum') }} 36 | restore-keys: | 37 | ${{ runner.os }}-go- 38 | - name: Test 39 | working-directory: ./src 40 | run: go test ./... 41 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | app.env 2 | 3 | data/ 4 | 5 | *.bak 6 | 7 | # the quickstart script will automatically create these files from their starting values 8 | # in the defaults folder so we don't need to track changes to them, only their defaults. 9 | /deploy/kratos/kratos.yml 10 | /deploy/postgres/init.sql 11 | /deploy/nginx/app.conf 12 | /deploy/backup/ 13 | /docker-compose.yml 14 | 15 | # Ignore frontend 16 | /Refractor-Svelte 17 | 18 | .neversetup 19 | -------------------------------------------------------------------------------- /.idea/.gitignore: -------------------------------------------------------------------------------- 1 | # Default ignored files 2 | /shelf/ 3 | /workspace.xml 4 | # Datasource local storage ignored files 5 | /dataSources/ 6 | /dataSources.local.xml 7 | # Editor-based HTTP Client requests 8 | /httpRequests/ 9 | /webResources.xml 10 | -------------------------------------------------------------------------------- /.idea/Refractor.iml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | -------------------------------------------------------------------------------- /.idea/copyright/Notice.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 7 | -------------------------------------------------------------------------------- /.idea/copyright/profiles_settings.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | -------------------------------------------------------------------------------- /.idea/dataSources.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | postgresql 6 | true 7 | org.postgresql.Driver 8 | jdbc:postgresql://localhost:5432/refractor 9 | $ProjectFileDir$ 10 | 11 | 12 | -------------------------------------------------------------------------------- /.idea/modules.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | -------------------------------------------------------------------------------- /.idea/scopes/Refractor_Copyright.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | -------------------------------------------------------------------------------- /.idea/sqldialects.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | -------------------------------------------------------------------------------- /.idea/vcs.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | -------------------------------------------------------------------------------- /Dockerfile: -------------------------------------------------------------------------------- 1 | FROM golang:alpine AS build 2 | 3 | # Install build tools 4 | RUN apk --no-cache add gcc g++ make git 5 | 6 | # Set build env variables 7 | ENV GO111MODULE=on \ 8 | CGO_ENABLED=1 \ 9 | GOOS=linux \ 10 | GOARCH=amd64 11 | 12 | WORKDIR /build 13 | 14 | COPY src/go.mod . 15 | COPY src/go.sum . 16 | RUN go mod download 17 | 18 | COPY /.git . 19 | COPY /src . 20 | 21 | RUN go build -ldflags "-s -w -X main.VERSION=`echo $(git rev-parse --abbrev-ref HEAD):$(git describe --exact-match --tags 2> /dev/null || git rev-parse --short HEAD)`" -o refractor-bin main.go 22 | 23 | # Create actual container 24 | FROM alpine 25 | 26 | RUN apk --no-cache add ca-certificates 27 | 28 | WORKDIR /var/refractor 29 | 30 | # Create directories where folders containing static assets are located. This is likely not the ideal way to do this. 31 | # However, it works fine! If many more static assets are added, a more scalable solution would be warranted. 32 | RUN mkdir ./auth 33 | RUN mkdir ./auth/templates 34 | RUN mkdir ./auth/static 35 | RUN mkdir ./internal 36 | RUN mkdir ./internal/mail 37 | RUN mkdir ./internal/mail/templates 38 | 39 | # Copy the binary from the build stage into /var/refractor 40 | COPY --from=build /build/refractor-bin ./refractor 41 | COPY --from=build /build/auth/templates ./auth/templates 42 | COPY --from=build /build/auth/static ./auth/static 43 | COPY --from=build /build/internal/mail/templates ./internal/mail/templates 44 | 45 | ENTRYPOINT PORT=80 /var/refractor/refractor 46 | -------------------------------------------------------------------------------- /Makefile: -------------------------------------------------------------------------------- 1 | # Dev commands 2 | up: 3 | docker-compose -f docker-compose.dev.yml up --build --force-recreate 4 | down: 5 | docker-compose -f docker-compose.dev.yml down 6 | 7 | # Prod commands 8 | prod-remake-nginx: 9 | docker-compose -f docker-compose.yml -f compose-frontend-svelte.yml up -d --force-recreate --build nginx 10 | prod-remake-refractor: 11 | docker-compose -f docker-compose.yml -f compose-frontend-svelte.yml up -d --force-recreate --build refractor 12 | prod-remake-svelte: 13 | docker-compose -f docker-compose.yml -f compose-frontend-svelte.yml up -d --force-recreate --build refractor-frontend 14 | deploy-cleanup: 15 | rm -f ./docker-compose.yml ./deploy/kratos/kratos.yml ./deploy/postgres/init.sql ./deploy/nginx/app.conf \ 16 | ./Refractor-Svelte/rollup.config.js ./.neversetup 2> /dev/null -------------------------------------------------------------------------------- /compose-frontend-svelte.yml: -------------------------------------------------------------------------------- 1 | version: "3.7" 2 | 3 | services: 4 | refractor-frontend: 5 | container_name: "refractor-frontend" 6 | build: 7 | dockerfile: Dockerfile 8 | context: ./Refractor-Svelte 9 | ports: 10 | - "3000:3000" 11 | networks: 12 | - intranet 13 | -------------------------------------------------------------------------------- /default/README.md: -------------------------------------------------------------------------------- 1 | # /default 2 | 3 | The `default` folder contains the default configuration to be used in deployment. 4 | 5 | The `quickstart.sh` script works by making copies of the config files with `default` 6 | to their correct locations, collecting info from the user (e.g domain, email, etc) 7 | and then replacing the variables found in the copied default files with the values which 8 | were provided by the user. 9 | 10 | ## Example Flow 11 | This example flow will use the default file `/default/kratos/kratos.yml` as an example. 12 | 13 | 1. The user runs `/quickstart.sh`. It detects that `/deploy/kratos/kratos.yml` 14 | does not exist, so it makes a copy of `/default/kratos/kratos.yml` to the location 15 | `/deploy/kratos/kratos.yml`. 16 | 2. In the quickstart script, the user will information about their deployment 17 | environment. 18 | 3. The information provided by the user which is relevant to `kratos.yml` will 19 | be populated in the `/deploy/kratos/kratos.yml` (copied from default) by replacing 20 | the placeholders (e.g `{{DOMAIN}}`) with the correct values. 21 | 4. If the user ever chooses to re-run the quickstart script, they will be given 22 | the option to overwrite their config files. If they choose to do so, the file at 23 | `/deploy/kratos/kratos.yml` will be moved to `/deploy/backup/kratos/kratos.yml` 24 | and a fresh copy of `kratos.yml` will be copied from the default to the deploy location. -------------------------------------------------------------------------------- /default/kratos/kratos.yml: -------------------------------------------------------------------------------- 1 | version: v0.6.3-alpha.1 2 | 3 | dsn: "{{KRATOS_DSN}}" 4 | 5 | serve: 6 | public: 7 | base_url: https://{{DOMAIN}}/kp/ 8 | cors: 9 | enabled: true 10 | allowed_origins: 11 | - https://{{DOMAIN}} 12 | allowed_methods: 13 | - POST 14 | - GET 15 | - PUT 16 | - PATCH 17 | - DELETE 18 | allowed_headers: 19 | - Authorization 20 | - Cookie 21 | exposed_headers: 22 | - Content-Type 23 | - Set-Cookie 24 | admin: 25 | base_url: http://127.0.0.1:4434/ 26 | 27 | selfservice: 28 | default_browser_return_url: https://{{DOMAIN}}/ 29 | whitelisted_return_urls: 30 | - https://{{DOMAIN}}/ 31 | 32 | methods: 33 | password: 34 | enabled: true 35 | link: 36 | enabled: true 37 | 38 | flows: 39 | error: 40 | ui_url: https://{{DOMAIN}}/k/error 41 | 42 | settings: 43 | ui_url: https://{{DOMAIN}}/k/settings 44 | privileged_session_max_age: 15m 45 | 46 | recovery: 47 | enabled: true 48 | ui_url: https://{{DOMAIN}}/k/recovery 49 | 50 | verification: 51 | enabled: true 52 | ui_url: https://{{DOMAIN}}/k/verify 53 | after: 54 | default_browser_return_url: https://{{DOMAIN}}/k/activated 55 | 56 | logout: 57 | after: 58 | default_browser_return_url: https://{{DOMAIN}}/k/login 59 | 60 | login: 61 | ui_url: https://{{DOMAIN}}/k/login 62 | lifespan: 10m 63 | 64 | log: 65 | level: debug 66 | format: text 67 | leak_sensitive_values: true 68 | 69 | secrets: 70 | cookie: 71 | - {{COOKIE_SECRET}} 72 | 73 | hashers: 74 | argon2: 75 | parallelism: 1 76 | memory: 128MB 77 | iterations: 2 78 | salt_length: 16 79 | key_length: 16 80 | 81 | session: 82 | lifespan: 72h 83 | 84 | identity: 85 | default_schema_url: file:///etc/config/kratos/identity.schema.json 86 | -------------------------------------------------------------------------------- /default/nginx/app.conf: -------------------------------------------------------------------------------- 1 | server { 2 | listen 80; 3 | server_name {{DOMAIN}}; 4 | 5 | location / { 6 | return 301 https://$host$request_uri; 7 | } 8 | 9 | location /.well-known/acme-challenge/ { 10 | root /var/www/certbot; 11 | } 12 | } 13 | 14 | server { 15 | listen 443 ssl; 16 | server_name {{DOMAIN}}; 17 | 18 | ssl_certificate /etc/letsencrypt/live/{{DOMAIN}}/fullchain.pem; 19 | ssl_certificate_key /etc/letsencrypt/live/{{DOMAIN}}/privkey.pem; 20 | 21 | # Route API calls to the backend API. 22 | location /api/ { 23 | proxy_pass http://refractor:4000; 24 | proxy_redirect off; 25 | proxy_set_header Host $host; 26 | proxy_set_header X-Real-IP $remote_addr; 27 | proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; 28 | proxy_set_header X-Forwarded-Host $server_name; 29 | } 30 | 31 | location /ws { 32 | proxy_pass http://refractor:4000; 33 | proxy_http_version 1.1; 34 | proxy_set_header Upgrade $http_upgrade; 35 | proxy_set_header Connection "Upgrade"; 36 | proxy_set_header Host $host; 37 | } 38 | 39 | # Routes to the public Ory Kratos API. The ^~ is a special nginx matcher which is used to perform the longest 40 | # non regex match against the /kp/ URI. If a request reaches this block, no further matching takes place. 41 | # Additionally, due to the ending / after /kp/ and :4433/ in the proxy pass directive, the /kp/ portion of the 42 | # request URI will be stripped away once routed to the public kratos API. 43 | # 44 | # For example, a request to /kp/self-service/login/browser will be routed to Ory Kratos' Public API 45 | # as the following: /self-service/login/browser 46 | location ^~ /kp/ { 47 | proxy_pass http://refractor-kratos:4433/; 48 | proxy_set_header Host $host; 49 | proxy_pass_request_headers on; 50 | } 51 | 52 | # Routes to the backend server-side auth pages. Anything which starts with /k and does not match /kp/ (seen above) 53 | # will be handled in this block. 54 | location /k { 55 | proxy_pass http://refractor:4455; 56 | proxy_set_header Host $host; 57 | proxy_pass_request_headers on; 58 | } 59 | 60 | # Routes to the frontend. Anything which doesn't match any of the above matchers will be handled in this block. 61 | location / { 62 | proxy_pass http://refractor-frontend:3000; 63 | proxy_redirect off; 64 | proxy_set_header Host $host; 65 | proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; 66 | } 67 | } 68 | -------------------------------------------------------------------------------- /default/postgres/init.sql: -------------------------------------------------------------------------------- 1 | /* 2 | * This file is part of Refractor. 3 | * 4 | * Refractor is free software: you can redistribute it and/or modify 5 | * it under the terms of the GNU General Public License as published by 6 | * the Free Software Foundation, either version 3 of the License, or 7 | * (at your option) any later version. 8 | * 9 | * This program is distributed in the hope that it will be useful, 10 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 11 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 | * GNU General Public License for more details. 13 | * 14 | * You should have received a copy of the GNU General Public License 15 | * along with this program. If not, see . 16 | */ 17 | 18 | CREATE DATABASE refractor; -------------------------------------------------------------------------------- /default/svelte/.env.production: -------------------------------------------------------------------------------- 1 | VITE_COMMUNITY_NAME={{COMMUNITY_NAME}} 2 | VITE_KRATOS_ROOT={{KRATOS_ROOT}} 3 | VITE_AUTH_ROOT={{AUTH_ROOT}} 4 | VITE_API_ROOT={{API_ROOT}} 5 | VITE_WS_ROOT={{WEBSOCKET_ROOT}} -------------------------------------------------------------------------------- /default/svelte/README.md: -------------------------------------------------------------------------------- 1 | # Svelte Defaults 2 | 3 | The files alongside this readme are the default config files for the Refractor-Svelte 4 | frontend application. -------------------------------------------------------------------------------- /deploy/kratos/identity.schema.json: -------------------------------------------------------------------------------- 1 | { 2 | "$id": "https://schemas.ory.sh/presets/kratos/quickstart/email-password/identity.schema.json", 3 | "$schema": "http://json-schema.org/draft-07/schema#", 4 | "title": "Person", 5 | "type": "object", 6 | "properties": { 7 | "traits": { 8 | "type": "object", 9 | "properties": { 10 | "email": { 11 | "type": "string", 12 | "format": "email", 13 | "title": "Email", 14 | "minLength": 3, 15 | "ory.sh/kratos": { 16 | "credentials": { 17 | "password": { 18 | "identifier": true 19 | } 20 | }, 21 | "verification": { 22 | "via": "email" 23 | }, 24 | "recovery": { 25 | "via": "email" 26 | } 27 | } 28 | }, 29 | "username": { 30 | "type": "string", 31 | "title": "Username", 32 | "minLength": 1, 33 | "ory.sh/kratos": { 34 | "credentials": { 35 | "password": { 36 | "identifier": true 37 | } 38 | } 39 | } 40 | } 41 | }, 42 | "required": [ 43 | "email", 44 | "username" 45 | ], 46 | "additionalProperties": false 47 | } 48 | } 49 | } 50 | -------------------------------------------------------------------------------- /dev/kratos/identity.schema.json: -------------------------------------------------------------------------------- 1 | { 2 | "$id": "https://schemas.ory.sh/presets/kratos/quickstart/email-password/identity.schema.json", 3 | "$schema": "http://json-schema.org/draft-07/schema#", 4 | "title": "Person", 5 | "type": "object", 6 | "properties": { 7 | "traits": { 8 | "type": "object", 9 | "properties": { 10 | "email": { 11 | "type": "string", 12 | "format": "email", 13 | "title": "Email", 14 | "minLength": 3, 15 | "ory.sh/kratos": { 16 | "credentials": { 17 | "password": { 18 | "identifier": true 19 | } 20 | }, 21 | "verification": { 22 | "via": "email" 23 | }, 24 | "recovery": { 25 | "via": "email" 26 | } 27 | } 28 | }, 29 | "username": { 30 | "type": "string", 31 | "title": "Username", 32 | "minLength": 1, 33 | "ory.sh/kratos": { 34 | "credentials": { 35 | "password": { 36 | "identifier": true 37 | } 38 | } 39 | } 40 | } 41 | }, 42 | "required": [ 43 | "email", 44 | "username" 45 | ], 46 | "additionalProperties": false 47 | } 48 | } 49 | } 50 | -------------------------------------------------------------------------------- /dev/kratos/kratos.dev.yml: -------------------------------------------------------------------------------- 1 | version: v0.6.3-alpha.1 2 | 3 | dsn: postgres://postgres:password@postgresd:5432:4455ratos?sslmode=disable&max_conns=20&max_idle_conns=4 4 | 5 | serve: 6 | public: 7 | base_url: http://127.0.0.1:4433/ 8 | cors: 9 | enabled: true 10 | allowed_origins: 11 | - http://127.0.0.1:3000 12 | allowed_methods: 13 | - POST 14 | - GET 15 | - PUT 16 | - PATCH 17 | - DELETE 18 | allowed_headers: 19 | - Authorization 20 | - Cookie 21 | exposed_headers: 22 | - Content-Type 23 | - Set-Cookie 24 | admin: 25 | base_url: http://127.0.0.1:4434/ 26 | 27 | selfservice: 28 | default_browser_return_url: http://127.0.0.1:3000/ 29 | whitelisted_return_urls: 30 | - http://127.0.0.1:3000 31 | 32 | methods: 33 | password: 34 | enabled: true 35 | link: 36 | enabled: true 37 | 38 | flows: 39 | error: 40 | ui_url: http://127.0.0.1:4455/k/error 41 | 42 | settings: 43 | ui_url: http://127.0.0.1:4455/k/settings 44 | privileged_session_max_age: 15m 45 | 46 | recovery: 47 | enabled: true 48 | ui_url: http://127.0.0.1:4455/k/recovery 49 | 50 | verification: 51 | enabled: true 52 | ui_url: http://127.0.0.1:4455/k/verify 53 | after: 54 | default_browser_return_url: http://127.0.0.1:4455/k/activated 55 | 56 | logout: 57 | after: 58 | default_browser_return_url: http://127.0.0.1:4455/k/login 59 | 60 | login: 61 | ui_url: http://127.0.0.1:4455/k/login 62 | lifespan: 10m 63 | 64 | log: 65 | level: debug 66 | format: text 67 | leak_sensitive_values: true 68 | 69 | secrets: 70 | cookie: 71 | - PLEASE-CHANGE-ME-I-AM-VERY-INSECURE 72 | 73 | hashers: 74 | argon2: 75 | parallelism: 1 76 | memory: 128MB 77 | iterations: 2 78 | salt_length: 16 79 | key_length: 16 80 | 81 | session: 82 | lifespan: 72h 83 | 84 | identity: 85 | default_schema_url: file:///etc/config/kratos/identity.schema.json 86 | 87 | #courier: 88 | # smtp: 89 | # connection_uri: smtp://@mailhog:1025/ 90 | -------------------------------------------------------------------------------- /dev/postgres/init.sql: -------------------------------------------------------------------------------- 1 | /* 2 | * This file is part of Refractor. 3 | * 4 | * Refractor is free software: you can redistribute it and/or modify 5 | * it under the terms of the GNU General Public License as published by 6 | * the Free Software Foundation, either version 3 of the License, or 7 | * (at your option) any later version. 8 | * 9 | * This program is distributed in the hope that it will be useful, 10 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 11 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 | * GNU General Public License for more details. 13 | * 14 | * You should have received a copy of the GNU General Public License 15 | * along with this program. If not, see . 16 | */ 17 | 18 | CREATE DATABASE refractor; -------------------------------------------------------------------------------- /docker-compose.dev.yml: -------------------------------------------------------------------------------- 1 | version: "3.7" 2 | 3 | services: 4 | postgresd: 5 | container_name: "refractor_postgres" 6 | image: postgres:9.6 7 | ports: 8 | - "5432:5432" 9 | environment: 10 | - POSTGRES_USER=postgres 11 | - POSTGRES_PASSWORD=password 12 | - POSTGRES_DB=kratos 13 | volumes: 14 | - ./dev/postgres/init.sql:/docker-entrypoint-initdb.d/init.sql 15 | networks: 16 | - intranet 17 | 18 | kratos-migrate: 19 | container_name: "refractor_kratos_migrate" 20 | depends_on: 21 | - postgresd 22 | image: oryd/kratos:v0.6.3-alpha.1 23 | environment: 24 | - DSN=postgres://postgres:password@postgresd:5432/kratos?sslmode=disable&max_conns=20&max_idle_conns=4 25 | volumes: 26 | - type: bind 27 | source: ./dev/kratos 28 | target: /etc/config/kratos 29 | command: -c /etc/config/kratos/kratos.dev.yml migrate sql -e --yes 30 | restart: on-failure 31 | networks: 32 | - intranet 33 | 34 | kratos: 35 | container_name: "refractor_kratos" 36 | depends_on: 37 | - postgresd 38 | - kratos-migrate 39 | image: oryd/kratos:v0.6.3-alpha.1 40 | ports: 41 | - "4433:4433" # auth 42 | - "4434:4434" # admin 43 | restart: unless-stopped 44 | environment: 45 | - DSN=postgres://postgres:password@postgresd:5432/kratos?sslmode=disable&max_conns=20&max_idle_conns=4 46 | - LOG_LEVEL=trace 47 | - COURIER_SMTP_CONNECTION_URI=smtp://@mailhog:1025/ 48 | - COURIER_SMTP_FROM_ADDRESS=noreply@refractor 49 | command: serve -c /etc/config/kratos/kratos.dev.yml --dev --watch-courier 50 | volumes: 51 | - type: bind 52 | source: ./dev/kratos 53 | target: /etc/config/kratos 54 | networks: 55 | - intranet 56 | 57 | mailhog: 58 | hostname: "mailhog" 59 | container_name: "refractor_mailhog" 60 | image: mailhog/mailhog 61 | ports: 62 | - "1025:1025" 63 | - "8025:8025" 64 | networks: 65 | - intranet 66 | 67 | networks: 68 | intranet: 69 | -------------------------------------------------------------------------------- /src/auth/public.go: -------------------------------------------------------------------------------- 1 | /* 2 | * This file is part of Refractor. 3 | * 4 | * Refractor is free software: you can redistribute it and/or modify 5 | * it under the terms of the GNU General Public License as published by 6 | * the Free Software Foundation, either version 3 of the License, or 7 | * (at your option) any later version. 8 | * 9 | * This program is distributed in the hope that it will be useful, 10 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 11 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 | * GNU General Public License for more details. 13 | * 14 | * You should have received a copy of the GNU General Public License 15 | * along with this program. If not, see . 16 | */ 17 | 18 | package auth 19 | 20 | import ( 21 | "Refractor/pkg/conf" 22 | kratos "github.com/ory/kratos-client-go" 23 | ) 24 | 25 | type publicHandlers struct { 26 | client *kratos.APIClient 27 | config *conf.Config 28 | } 29 | 30 | func NewPublicHandlers(client *kratos.APIClient, config *conf.Config) *publicHandlers { 31 | return &publicHandlers{ 32 | client: client, 33 | config: config, 34 | } 35 | } 36 | 37 | type Node struct { 38 | Label string 39 | Disabled bool 40 | Name string 41 | Required bool 42 | Type string 43 | Value string 44 | } 45 | 46 | type Message struct { 47 | ID int64 48 | Text string 49 | Type string 50 | } 51 | 52 | type RenderData struct { 53 | Action string 54 | Method string 55 | FlowID string 56 | UiNodes []Node 57 | Messages []Message 58 | } 59 | -------------------------------------------------------------------------------- /src/auth/root.go: -------------------------------------------------------------------------------- 1 | /* 2 | * This file is part of Refractor. 3 | * 4 | * Refractor is free software: you can redistribute it and/or modify 5 | * it under the terms of the GNU General Public License as published by 6 | * the Free Software Foundation, either version 3 of the License, or 7 | * (at your option) any later version. 8 | * 9 | * This program is distributed in the hope that it will be useful, 10 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 11 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 | * GNU General Public License for more details. 13 | * 14 | * You should have received a copy of the GNU General Public License 15 | * along with this program. If not, see . 16 | */ 17 | 18 | package auth 19 | 20 | import ( 21 | "fmt" 22 | "github.com/labstack/echo/v4" 23 | "net/http" 24 | ) 25 | 26 | func (h *publicHandlers) RootHandler(c echo.Context) error { 27 | return c.Redirect(http.StatusTemporaryRedirect, 28 | fmt.Sprintf("%s/self-service/login/browser", h.config.KratosPublic)) 29 | } 30 | -------------------------------------------------------------------------------- /src/auth/setupcomplete.go: -------------------------------------------------------------------------------- 1 | /* 2 | * This file is part of Refractor. 3 | * 4 | * Refractor is free software: you can redistribute it and/or modify 5 | * it under the terms of the GNU General Public License as published by 6 | * the Free Software Foundation, either version 3 of the License, or 7 | * (at your option) any later version. 8 | * 9 | * This program is distributed in the hope that it will be useful, 10 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 11 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 | * GNU General Public License for more details. 13 | * 14 | * You should have received a copy of the GNU General Public License 15 | * along with this program. If not, see . 16 | */ 17 | 18 | package auth 19 | 20 | import ( 21 | "Refractor/domain" 22 | "fmt" 23 | "github.com/labstack/echo/v4" 24 | "net/http" 25 | ) 26 | 27 | func (h *publicHandlers) SetupCompleteHandler(c echo.Context) error { 28 | user, ok := c.Get("user").(*domain.AuthUser) 29 | if !ok { 30 | return fmt.Errorf("could not get AuthUser from context") 31 | } 32 | 33 | // Check if this user has a verified address 34 | verified := false 35 | for _, address := range user.Identity.VerifiableAddresses { 36 | if address.Verified { 37 | verified = true 38 | break 39 | } 40 | } 41 | 42 | if !verified { 43 | // If this user is not yet verified, redirect them to the frontend application where they will be notified that 44 | // they have to verify their email. 45 | return c.JSON(http.StatusTemporaryRedirect, h.config.FrontendRoot) 46 | } 47 | 48 | return c.Render(http.StatusOK, "setupcomplete", h.config.FrontendRoot) 49 | } 50 | -------------------------------------------------------------------------------- /src/auth/templates/login.html: -------------------------------------------------------------------------------- 1 | 17 | 18 | {{ define "login" }} 19 | {{ template "head" . }} 20 |
21 |

Sign in

22 | 23 |
24 | {{ range $message := .Messages }} 25 |
{{ $message.Text }}
26 | {{ end }} 27 | 28 |
29 | {{ range $node := .UiNodes }} 30 | {{ if eq $node.Type "submit" }} 31 | 32 | {{ else }} 33 |
34 |
35 | 36 | 37 |
38 | 39 | {{ if $node.Label }} 40 | 41 | {{ end }} 42 |
43 |
44 | {{ end }} 45 | {{ end }} 46 |
47 |
48 | 49 |

Forget your password? Click here to recover your account

50 |
51 | {{ template "foot" . }} 52 | {{ end }} -------------------------------------------------------------------------------- /src/auth/templates/partial-foot.html: -------------------------------------------------------------------------------- 1 | 17 | 18 | {{ define "foot" }} 19 | 20 | 21 | {{ end }} -------------------------------------------------------------------------------- /src/auth/templates/partial-head.html: -------------------------------------------------------------------------------- 1 | 17 | 18 | {{ define "head" }} 19 | 20 | 21 | 22 | 24 | 25 | 26 | 27 | 28 | Refractor 29 | 30 | 31 | {{ end }} 32 | -------------------------------------------------------------------------------- /src/auth/templates/recovery.html: -------------------------------------------------------------------------------- 1 | 17 | {{ define "recovery" }} 18 | {{ template "head" . }} 19 |
20 |

Recovery

21 | 22 |
23 | {{ range $message := .Messages }} 24 |
{{ $message.Text }}
25 | {{ end }} 26 | 27 |
28 | {{ range $node := .UiNodes }} 29 | {{ if eq $node.Type "submit" }} 30 | 31 | {{ else }} 32 | 33 |
34 |
35 | 36 | 37 |
38 | 39 | {{ if $node.Label }} 40 | 41 | {{ end }} 42 |
43 |
44 | {{ end }} 45 | {{ end }} 46 |
47 |
48 |
49 | {{ template "foot" . }} 50 | {{ end }} -------------------------------------------------------------------------------- /src/auth/templates/setupcomplete.html: -------------------------------------------------------------------------------- 1 | 17 | 18 | {{ define "setupcomplete" }} 19 | {{ template "head" . }} 20 |
21 |

You're all set.

22 | 23 |

You will be redirected in a moment. Enjoy Refractor!

24 |
25 | 26 | 34 | {{ template "foot" . }} 35 | {{ end }} -------------------------------------------------------------------------------- /src/auth/templates/verification.html: -------------------------------------------------------------------------------- 1 | 17 | 18 | {{ define "verification" }} 19 | {{ template "head" . }} 20 |
21 |

Email Verification

22 | 23 |
24 | {{ range $message := .Messages }} 25 |
{{ $message.Text }}
26 | {{ end }} 27 | 28 |
29 | {{ range $node := .UiNodes }} 30 | {{ if eq $node.Type "submit" }} 31 | 32 | {{ else }} 33 |
34 |
35 | 36 | 37 |
38 | 39 | {{ if $node.Label }} 40 | 41 | {{ end }} 42 |
43 |
44 | {{ end }} 45 | {{ end }} 46 |
47 |
48 |
49 | {{ template "foot" . }} 50 | {{ end }} -------------------------------------------------------------------------------- /src/domain/api.go: -------------------------------------------------------------------------------- 1 | /* 2 | * This file is part of Refractor. 3 | * 4 | * Refractor is free software: you can redistribute it and/or modify 5 | * it under the terms of the GNU General Public License as published by 6 | * the Free Software Foundation, either version 3 of the License, or 7 | * (at your option) any later version. 8 | * 9 | * This program is distributed in the hope that it will be useful, 10 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 11 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 | * GNU General Public License for more details. 13 | * 14 | * You should have received a copy of the GNU General Public License 15 | * along with this program. If not, see . 16 | */ 17 | 18 | package domain 19 | 20 | import "github.com/labstack/echo/v4" 21 | 22 | type Middleware struct { 23 | ProtectMiddleware echo.MiddlewareFunc 24 | ActivationMiddleware echo.MiddlewareFunc 25 | } 26 | -------------------------------------------------------------------------------- /src/domain/args.go: -------------------------------------------------------------------------------- 1 | /* 2 | * This file is part of Refractor. 3 | * 4 | * Refractor is free software: you can redistribute it and/or modify 5 | * it under the terms of the GNU General Public License as published by 6 | * the Free Software Foundation, either version 3 of the License, or 7 | * (at your option) any later version. 8 | * 9 | * This program is distributed in the hope that it will be useful, 10 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 11 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 | * GNU General Public License for more details. 13 | * 14 | * You should have received a copy of the GNU General Public License 15 | * along with this program. If not, see . 16 | */ 17 | 18 | package domain 19 | 20 | import ( 21 | "fmt" 22 | "strings" 23 | ) 24 | 25 | type UpdateArgs map[string]interface{} 26 | type FindArgs map[string]interface{} 27 | 28 | func (args UpdateArgs) FilterEmptyStrings() UpdateArgs { 29 | for key, val := range args { 30 | fmt.Println(key, val) 31 | var value string 32 | 33 | // Check if this value is a string or a string pointer. If it isn't, skip it. 34 | str, ok := val.(string) 35 | if ok { 36 | value = str 37 | } else { 38 | strPtr, ok := val.(*string) 39 | if ok { 40 | value = *strPtr 41 | } 42 | } 43 | 44 | // If this value is a string, check if it's empty. If it is, remove it from the map. 45 | if strings.TrimSpace(value) == "" { 46 | delete(args, key) 47 | } 48 | } 49 | 50 | return args 51 | } 52 | -------------------------------------------------------------------------------- /src/domain/attachment.go: -------------------------------------------------------------------------------- 1 | /* 2 | * This file is part of Refractor. 3 | * 4 | * Refractor is free software: you can redistribute it and/or modify 5 | * it under the terms of the GNU General Public License as published by 6 | * the Free Software Foundation, either version 3 of the License, or 7 | * (at your option) any later version. 8 | * 9 | * This program is distributed in the hope that it will be useful, 10 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 11 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 | * GNU General Public License for more details. 13 | * 14 | * You should have received a copy of the GNU General Public License 15 | * along with this program. If not, see . 16 | */ 17 | 18 | package domain 19 | 20 | import "context" 21 | 22 | type Attachment struct { 23 | AttachmentID int64 `json:"id"` 24 | InfractionID int64 `json:"infraction_id"` 25 | URL string `json:"url"` 26 | Note string `json:"note"` 27 | } 28 | 29 | type AttachmentRepo interface { 30 | Store(ctx context.Context, attachment *Attachment) error 31 | GetByInfraction(ctx context.Context, infractionID int64) ([]*Attachment, error) 32 | GetByID(ctx context.Context, id int64) (*Attachment, error) 33 | Delete(ctx context.Context, id int64) error 34 | } 35 | 36 | type AttachmentService interface { 37 | Store(c context.Context, attachment *Attachment) error 38 | GetByInfraction(c context.Context, infractionID int64) ([]*Attachment, error) 39 | Delete(c context.Context, id int64) error 40 | } 41 | -------------------------------------------------------------------------------- /src/domain/command_executor.go: -------------------------------------------------------------------------------- 1 | /* 2 | * This file is part of Refractor. 3 | * 4 | * Refractor is free software: you can redistribute it and/or modify 5 | * it under the terms of the GNU General Public License as published by 6 | * the Free Software Foundation, either version 3 of the License, or 7 | * (at your option) any later version. 8 | * 9 | * This program is distributed in the hope that it will be useful, 10 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 11 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 | * GNU General Public License for more details. 13 | * 14 | * You should have received a copy of the GNU General Public License 15 | * along with this program. If not, see . 16 | */ 17 | 18 | package domain 19 | 20 | import ( 21 | "context" 22 | ) 23 | 24 | type CommandPayload interface { 25 | GetCommands() []Command 26 | GetGame() Game 27 | } 28 | 29 | type Command interface { 30 | GetCommand() string 31 | ShouldRunOnAll() bool 32 | GetServerID() int64 33 | } 34 | 35 | type CommandExecutor interface { 36 | PrepareInfractionCommands(ctx context.Context, infraction InfractionPayload, action string, serverID int64) (CommandPayload, error) 37 | QueueCommands(payload CommandPayload) error 38 | StartRunner(terminate chan uint8) 39 | } 40 | 41 | type CustomInfractionPayload struct { 42 | PlayerID string 43 | Platform string 44 | PlayerName string 45 | UserID string 46 | Type string 47 | Duration int64 48 | DurationRemaining int64 49 | Reason string 50 | } 51 | 52 | func (p *CustomInfractionPayload) GetPlayerID() string { 53 | return p.PlayerID 54 | } 55 | 56 | func (p *CustomInfractionPayload) GetPlatform() string { 57 | return p.Platform 58 | } 59 | 60 | func (p *CustomInfractionPayload) GetPlayerName() string { 61 | return p.PlayerName 62 | } 63 | 64 | func (p *CustomInfractionPayload) GetType() string { 65 | return p.Type 66 | } 67 | 68 | func (p *CustomInfractionPayload) GetDuration() int64 { 69 | return p.Duration 70 | } 71 | 72 | func (p *CustomInfractionPayload) GetDurationRemaining() int64 { 73 | return p.DurationRemaining 74 | } 75 | 76 | func (p *CustomInfractionPayload) GetReason() string { 77 | return p.Reason 78 | } 79 | 80 | func (p *CustomInfractionPayload) GetUserID() string { 81 | return p.UserID 82 | } 83 | -------------------------------------------------------------------------------- /src/domain/error.go: -------------------------------------------------------------------------------- 1 | /* 2 | * This file is part of Refractor. 3 | * 4 | * Refractor is free software: you can redistribute it and/or modify 5 | * it under the terms of the GNU General Public License as published by 6 | * the Free Software Foundation, either version 3 of the License, or 7 | * (at your option) any later version. 8 | * 9 | * This program is distributed in the hope that it will be useful, 10 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 11 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 | * GNU General Public License for more details. 13 | * 14 | * You should have received a copy of the GNU General Public License 15 | * along with this program. If not, see . 16 | */ 17 | 18 | package domain 19 | 20 | import ( 21 | "encoding/json" 22 | "fmt" 23 | "github.com/pkg/errors" 24 | ) 25 | 26 | var ( 27 | ErrConflict = errors.New("conflict") // action cannot be performed 28 | ErrInvalid = errors.New("invalid") // validation failed 29 | ErrNotFound = errors.New("not found") // entity does not exist 30 | ErrNoArgs = errors.New("no args") // no arguments provided 31 | ErrInvalidQuery = errors.New("invalid query") // an invalid search/find query was provided 32 | ) 33 | 34 | type ClientError interface { 35 | Error() string 36 | 37 | // ResponseBody returns a response body 38 | ResponseBody() ([]byte, error) 39 | 40 | // ResponseHeaders returns http status code and headers 41 | ResponseHeaders() (int, map[string]string) 42 | } 43 | 44 | // HTTPError implements the ClientError interface. 45 | type HTTPError struct { 46 | Success bool `json:"success"` 47 | Cause error `json:"-"` 48 | Message string `json:"message"` 49 | ValidationErrors interface{} `json:"errors,omitempty"` 50 | Status int `json:"-"` 51 | } 52 | 53 | func (e *HTTPError) Error() string { 54 | if e.Cause == nil { 55 | return e.Message 56 | } 57 | 58 | return fmt.Sprintf("%s : %s", e.Message, e.Cause.Error()) 59 | } 60 | 61 | // ResponseBody returns JSON response body. 62 | func (e *HTTPError) ResponseBody() ([]byte, error) { 63 | body, err := json.Marshal(e) 64 | if err != nil { 65 | return nil, fmt.Errorf("could not parse response body. Error: %v", err) 66 | } 67 | return body, nil 68 | } 69 | 70 | // ResponseHeaders returns http status code and headers. 71 | func (e *HTTPError) ResponseHeaders() (int, map[string]string) { 72 | return e.Status, map[string]string{ 73 | "Content-Type": "application/json; charset=utf-8", 74 | } 75 | } 76 | 77 | func NewHTTPError(err error, status int, detail string) error { 78 | return &HTTPError{ 79 | Success: false, 80 | Cause: err, 81 | Message: detail, 82 | Status: status, 83 | } 84 | } 85 | -------------------------------------------------------------------------------- /src/domain/http.go: -------------------------------------------------------------------------------- 1 | /* 2 | * This file is part of Refractor. 3 | * 4 | * Refractor is free software: you can redistribute it and/or modify 5 | * it under the terms of the GNU General Public License as published by 6 | * the Free Software Foundation, either version 3 of the License, or 7 | * (at your option) any later version. 8 | * 9 | * This program is distributed in the hope that it will be useful, 10 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 11 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 | * GNU General Public License for more details. 13 | * 14 | * You should have received a copy of the GNU General Public License 15 | * along with this program. If not, see . 16 | */ 17 | 18 | package domain 19 | 20 | type Response struct { 21 | Success bool `json:"success"` 22 | Message string `json:"message,omitempty"` 23 | Errors map[string]string `json:"errors,omitempty"` 24 | Payload interface{} `json:"payload,omitempty"` 25 | } 26 | 27 | var ResponseUnauthorized = &Response{ 28 | Success: false, 29 | Message: "You do not have permission to perform this action", 30 | } 31 | -------------------------------------------------------------------------------- /src/domain/mail.go: -------------------------------------------------------------------------------- 1 | /* 2 | * This file is part of Refractor. 3 | * 4 | * Refractor is free software: you can redistribute it and/or modify 5 | * it under the terms of the GNU General Public License as published by 6 | * the Free Software Foundation, either version 3 of the License, or 7 | * (at your option) any later version. 8 | * 9 | * This program is distributed in the hope that it will be useful, 10 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 11 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 | * GNU General Public License for more details. 13 | * 14 | * You should have received a copy of the GNU General Public License 15 | * along with this program. If not, see . 16 | */ 17 | 18 | package domain 19 | 20 | type MailService interface { 21 | SendMail(to []string, sub string, body string) error 22 | SendWelcomeEmail(to, inviterName, link string) error 23 | } 24 | -------------------------------------------------------------------------------- /src/domain/mocks/AttachmentRepo.go: -------------------------------------------------------------------------------- 1 | // Code generated by mockery v0.0.0-dev. DO NOT EDIT. 2 | 3 | package mocks 4 | 5 | import ( 6 | domain "Refractor/domain" 7 | context "context" 8 | 9 | mock "github.com/stretchr/testify/mock" 10 | ) 11 | 12 | // AttachmentRepo is an autogenerated mock type for the AttachmentRepo type 13 | type AttachmentRepo struct { 14 | mock.Mock 15 | } 16 | 17 | // Delete provides a mock function with given fields: ctx, id 18 | func (_m *AttachmentRepo) Delete(ctx context.Context, id int64) error { 19 | ret := _m.Called(ctx, id) 20 | 21 | var r0 error 22 | if rf, ok := ret.Get(0).(func(context.Context, int64) error); ok { 23 | r0 = rf(ctx, id) 24 | } else { 25 | r0 = ret.Error(0) 26 | } 27 | 28 | return r0 29 | } 30 | 31 | // GetByID provides a mock function with given fields: ctx, id 32 | func (_m *AttachmentRepo) GetByID(ctx context.Context, id int64) (*domain.Attachment, error) { 33 | ret := _m.Called(ctx, id) 34 | 35 | var r0 *domain.Attachment 36 | if rf, ok := ret.Get(0).(func(context.Context, int64) *domain.Attachment); ok { 37 | r0 = rf(ctx, id) 38 | } else { 39 | if ret.Get(0) != nil { 40 | r0 = ret.Get(0).(*domain.Attachment) 41 | } 42 | } 43 | 44 | var r1 error 45 | if rf, ok := ret.Get(1).(func(context.Context, int64) error); ok { 46 | r1 = rf(ctx, id) 47 | } else { 48 | r1 = ret.Error(1) 49 | } 50 | 51 | return r0, r1 52 | } 53 | 54 | // GetByInfraction provides a mock function with given fields: ctx, infractionID 55 | func (_m *AttachmentRepo) GetByInfraction(ctx context.Context, infractionID int64) ([]*domain.Attachment, error) { 56 | ret := _m.Called(ctx, infractionID) 57 | 58 | var r0 []*domain.Attachment 59 | if rf, ok := ret.Get(0).(func(context.Context, int64) []*domain.Attachment); ok { 60 | r0 = rf(ctx, infractionID) 61 | } else { 62 | if ret.Get(0) != nil { 63 | r0 = ret.Get(0).([]*domain.Attachment) 64 | } 65 | } 66 | 67 | var r1 error 68 | if rf, ok := ret.Get(1).(func(context.Context, int64) error); ok { 69 | r1 = rf(ctx, infractionID) 70 | } else { 71 | r1 = ret.Error(1) 72 | } 73 | 74 | return r0, r1 75 | } 76 | 77 | // Store provides a mock function with given fields: ctx, attachment 78 | func (_m *AttachmentRepo) Store(ctx context.Context, attachment *domain.Attachment) error { 79 | ret := _m.Called(ctx, attachment) 80 | 81 | var r0 error 82 | if rf, ok := ret.Get(0).(func(context.Context, *domain.Attachment) error); ok { 83 | r0 = rf(ctx, attachment) 84 | } else { 85 | r0 = ret.Error(0) 86 | } 87 | 88 | return r0 89 | } 90 | -------------------------------------------------------------------------------- /src/domain/mocks/AttachmentService.go: -------------------------------------------------------------------------------- 1 | // Code generated by mockery v0.0.0-dev. DO NOT EDIT. 2 | 3 | package mocks 4 | 5 | import ( 6 | domain "Refractor/domain" 7 | context "context" 8 | 9 | mock "github.com/stretchr/testify/mock" 10 | ) 11 | 12 | // AttachmentService is an autogenerated mock type for the AttachmentService type 13 | type AttachmentService struct { 14 | mock.Mock 15 | } 16 | 17 | // Delete provides a mock function with given fields: c, id 18 | func (_m *AttachmentService) Delete(c context.Context, id int64) error { 19 | ret := _m.Called(c, id) 20 | 21 | var r0 error 22 | if rf, ok := ret.Get(0).(func(context.Context, int64) error); ok { 23 | r0 = rf(c, id) 24 | } else { 25 | r0 = ret.Error(0) 26 | } 27 | 28 | return r0 29 | } 30 | 31 | // GetByInfraction provides a mock function with given fields: c, infractionID 32 | func (_m *AttachmentService) GetByInfraction(c context.Context, infractionID int64) ([]*domain.Attachment, error) { 33 | ret := _m.Called(c, infractionID) 34 | 35 | var r0 []*domain.Attachment 36 | if rf, ok := ret.Get(0).(func(context.Context, int64) []*domain.Attachment); ok { 37 | r0 = rf(c, infractionID) 38 | } else { 39 | if ret.Get(0) != nil { 40 | r0 = ret.Get(0).([]*domain.Attachment) 41 | } 42 | } 43 | 44 | var r1 error 45 | if rf, ok := ret.Get(1).(func(context.Context, int64) error); ok { 46 | r1 = rf(c, infractionID) 47 | } else { 48 | r1 = ret.Error(1) 49 | } 50 | 51 | return r0, r1 52 | } 53 | 54 | // Store provides a mock function with given fields: c, attachment 55 | func (_m *AttachmentService) Store(c context.Context, attachment *domain.Attachment) error { 56 | ret := _m.Called(c, attachment) 57 | 58 | var r0 error 59 | if rf, ok := ret.Get(0).(func(context.Context, *domain.Attachment) error); ok { 60 | r0 = rf(c, attachment) 61 | } else { 62 | r0 = ret.Error(0) 63 | } 64 | 65 | return r0 66 | } 67 | -------------------------------------------------------------------------------- /src/domain/mocks/AuthRepo.go: -------------------------------------------------------------------------------- 1 | // Code generated by mockery v0.0.0-dev. DO NOT EDIT. 2 | 3 | package mocks 4 | 5 | import ( 6 | domain "Refractor/domain" 7 | context "context" 8 | 9 | mock "github.com/stretchr/testify/mock" 10 | ) 11 | 12 | // AuthRepo is an autogenerated mock type for the AuthRepo type 13 | type AuthRepo struct { 14 | mock.Mock 15 | } 16 | 17 | // CreateUser provides a mock function with given fields: ctx, userTraits 18 | func (_m *AuthRepo) CreateUser(ctx context.Context, userTraits *domain.Traits) (*domain.AuthUser, error) { 19 | ret := _m.Called(ctx, userTraits) 20 | 21 | var r0 *domain.AuthUser 22 | if rf, ok := ret.Get(0).(func(context.Context, *domain.Traits) *domain.AuthUser); ok { 23 | r0 = rf(ctx, userTraits) 24 | } else { 25 | if ret.Get(0) != nil { 26 | r0 = ret.Get(0).(*domain.AuthUser) 27 | } 28 | } 29 | 30 | var r1 error 31 | if rf, ok := ret.Get(1).(func(context.Context, *domain.Traits) error); ok { 32 | r1 = rf(ctx, userTraits) 33 | } else { 34 | r1 = ret.Error(1) 35 | } 36 | 37 | return r0, r1 38 | } 39 | 40 | // GetAllUsers provides a mock function with given fields: ctx 41 | func (_m *AuthRepo) GetAllUsers(ctx context.Context) ([]*domain.AuthUser, error) { 42 | ret := _m.Called(ctx) 43 | 44 | var r0 []*domain.AuthUser 45 | if rf, ok := ret.Get(0).(func(context.Context) []*domain.AuthUser); ok { 46 | r0 = rf(ctx) 47 | } else { 48 | if ret.Get(0) != nil { 49 | r0 = ret.Get(0).([]*domain.AuthUser) 50 | } 51 | } 52 | 53 | var r1 error 54 | if rf, ok := ret.Get(1).(func(context.Context) error); ok { 55 | r1 = rf(ctx) 56 | } else { 57 | r1 = ret.Error(1) 58 | } 59 | 60 | return r0, r1 61 | } 62 | 63 | // GetRecoveryLink provides a mock function with given fields: ctx, userID 64 | func (_m *AuthRepo) GetRecoveryLink(ctx context.Context, userID string) (string, error) { 65 | ret := _m.Called(ctx, userID) 66 | 67 | var r0 string 68 | if rf, ok := ret.Get(0).(func(context.Context, string) string); ok { 69 | r0 = rf(ctx, userID) 70 | } else { 71 | r0 = ret.Get(0).(string) 72 | } 73 | 74 | var r1 error 75 | if rf, ok := ret.Get(1).(func(context.Context, string) error); ok { 76 | r1 = rf(ctx, userID) 77 | } else { 78 | r1 = ret.Error(1) 79 | } 80 | 81 | return r0, r1 82 | } 83 | 84 | // GetUserByID provides a mock function with given fields: ctx, id 85 | func (_m *AuthRepo) GetUserByID(ctx context.Context, id string) (*domain.AuthUser, error) { 86 | ret := _m.Called(ctx, id) 87 | 88 | var r0 *domain.AuthUser 89 | if rf, ok := ret.Get(0).(func(context.Context, string) *domain.AuthUser); ok { 90 | r0 = rf(ctx, id) 91 | } else { 92 | if ret.Get(0) != nil { 93 | r0 = ret.Get(0).(*domain.AuthUser) 94 | } 95 | } 96 | 97 | var r1 error 98 | if rf, ok := ret.Get(1).(func(context.Context, string) error); ok { 99 | r1 = rf(ctx, id) 100 | } else { 101 | r1 = ret.Error(1) 102 | } 103 | 104 | return r0, r1 105 | } 106 | -------------------------------------------------------------------------------- /src/domain/mocks/AuthService.go: -------------------------------------------------------------------------------- 1 | // Code generated by mockery v0.0.0-dev. DO NOT EDIT. 2 | 3 | package mocks 4 | 5 | import ( 6 | domain "Refractor/domain" 7 | context "context" 8 | 9 | mock "github.com/stretchr/testify/mock" 10 | ) 11 | 12 | // AuthService is an autogenerated mock type for the AuthService type 13 | type AuthService struct { 14 | mock.Mock 15 | } 16 | 17 | // CreateUser provides a mock function with given fields: c, userTraits, inviter 18 | func (_m *AuthService) CreateUser(c context.Context, userTraits *domain.Traits, inviter string) (*domain.AuthUser, error) { 19 | ret := _m.Called(c, userTraits, inviter) 20 | 21 | var r0 *domain.AuthUser 22 | if rf, ok := ret.Get(0).(func(context.Context, *domain.Traits, string) *domain.AuthUser); ok { 23 | r0 = rf(c, userTraits, inviter) 24 | } else { 25 | if ret.Get(0) != nil { 26 | r0 = ret.Get(0).(*domain.AuthUser) 27 | } 28 | } 29 | 30 | var r1 error 31 | if rf, ok := ret.Get(1).(func(context.Context, *domain.Traits, string) error); ok { 32 | r1 = rf(c, userTraits, inviter) 33 | } else { 34 | r1 = ret.Error(1) 35 | } 36 | 37 | return r0, r1 38 | } 39 | -------------------------------------------------------------------------------- /src/domain/mocks/Authorizer.go: -------------------------------------------------------------------------------- 1 | // Code generated by mockery v0.0.0-dev. DO NOT EDIT. 2 | 3 | package mocks 4 | 5 | import ( 6 | bitperms "Refractor/pkg/bitperms" 7 | context "context" 8 | 9 | domain "Refractor/domain" 10 | 11 | mock "github.com/stretchr/testify/mock" 12 | ) 13 | 14 | // Authorizer is an autogenerated mock type for the Authorizer type 15 | type Authorizer struct { 16 | mock.Mock 17 | } 18 | 19 | // GetAuthorizedServers provides a mock function with given fields: ctx, userID, authChecker 20 | func (_m *Authorizer) GetAuthorizedServers(ctx context.Context, userID string, authChecker domain.AuthChecker) ([]int64, error) { 21 | ret := _m.Called(ctx, userID, authChecker) 22 | 23 | var r0 []int64 24 | if rf, ok := ret.Get(0).(func(context.Context, string, domain.AuthChecker) []int64); ok { 25 | r0 = rf(ctx, userID, authChecker) 26 | } else { 27 | if ret.Get(0) != nil { 28 | r0 = ret.Get(0).([]int64) 29 | } 30 | } 31 | 32 | var r1 error 33 | if rf, ok := ret.Get(1).(func(context.Context, string, domain.AuthChecker) error); ok { 34 | r1 = rf(ctx, userID, authChecker) 35 | } else { 36 | r1 = ret.Error(1) 37 | } 38 | 39 | return r0, r1 40 | } 41 | 42 | // GetPermissions provides a mock function with given fields: ctx, scope, userID 43 | func (_m *Authorizer) GetPermissions(ctx context.Context, scope domain.AuthScope, userID string) (*bitperms.Permissions, error) { 44 | ret := _m.Called(ctx, scope, userID) 45 | 46 | var r0 *bitperms.Permissions 47 | if rf, ok := ret.Get(0).(func(context.Context, domain.AuthScope, string) *bitperms.Permissions); ok { 48 | r0 = rf(ctx, scope, userID) 49 | } else { 50 | if ret.Get(0) != nil { 51 | r0 = ret.Get(0).(*bitperms.Permissions) 52 | } 53 | } 54 | 55 | var r1 error 56 | if rf, ok := ret.Get(1).(func(context.Context, domain.AuthScope, string) error); ok { 57 | r1 = rf(ctx, scope, userID) 58 | } else { 59 | r1 = ret.Error(1) 60 | } 61 | 62 | return r0, r1 63 | } 64 | 65 | // HasPermission provides a mock function with given fields: ctx, scope, userID, authChecker 66 | func (_m *Authorizer) HasPermission(ctx context.Context, scope domain.AuthScope, userID string, authChecker domain.AuthChecker) (bool, error) { 67 | ret := _m.Called(ctx, scope, userID, authChecker) 68 | 69 | var r0 bool 70 | if rf, ok := ret.Get(0).(func(context.Context, domain.AuthScope, string, domain.AuthChecker) bool); ok { 71 | r0 = rf(ctx, scope, userID, authChecker) 72 | } else { 73 | r0 = ret.Get(0).(bool) 74 | } 75 | 76 | var r1 error 77 | if rf, ok := ret.Get(1).(func(context.Context, domain.AuthScope, string, domain.AuthChecker) error); ok { 78 | r1 = rf(ctx, scope, userID, authChecker) 79 | } else { 80 | r1 = ret.Error(1) 81 | } 82 | 83 | return r0, r1 84 | } 85 | -------------------------------------------------------------------------------- /src/domain/mocks/ClientCreator.go: -------------------------------------------------------------------------------- 1 | // Code generated by mockery v0.0.0-dev. DO NOT EDIT. 2 | 3 | package mocks 4 | 5 | import ( 6 | domain "Refractor/domain" 7 | 8 | mock "github.com/stretchr/testify/mock" 9 | ) 10 | 11 | // ClientCreator is an autogenerated mock type for the ClientCreator type 12 | type ClientCreator struct { 13 | mock.Mock 14 | } 15 | 16 | // GetClientFromConfig provides a mock function with given fields: game, server 17 | func (_m *ClientCreator) GetClientFromConfig(game domain.Game, server *domain.Server) (domain.RCONClient, error) { 18 | ret := _m.Called(game, server) 19 | 20 | var r0 domain.RCONClient 21 | if rf, ok := ret.Get(0).(func(domain.Game, *domain.Server) domain.RCONClient); ok { 22 | r0 = rf(game, server) 23 | } else { 24 | if ret.Get(0) != nil { 25 | r0 = ret.Get(0).(domain.RCONClient) 26 | } 27 | } 28 | 29 | var r1 error 30 | if rf, ok := ret.Get(1).(func(domain.Game, *domain.Server) error); ok { 31 | r1 = rf(game, server) 32 | } else { 33 | r1 = ret.Error(1) 34 | } 35 | 36 | return r0, r1 37 | } 38 | -------------------------------------------------------------------------------- /src/domain/mocks/CommandExecutor.go: -------------------------------------------------------------------------------- 1 | // Code generated by mockery v0.0.0-dev. DO NOT EDIT. 2 | 3 | package mocks 4 | 5 | import ( 6 | domain "Refractor/domain" 7 | context "context" 8 | 9 | mock "github.com/stretchr/testify/mock" 10 | ) 11 | 12 | // CommandExecutor is an autogenerated mock type for the CommandExecutor type 13 | type CommandExecutor struct { 14 | mock.Mock 15 | } 16 | 17 | // PrepareInfractionCommands provides a mock function with given fields: ctx, infraction, action, serverID 18 | func (_m *CommandExecutor) PrepareInfractionCommands(ctx context.Context, infraction *domain.Infraction, action string, serverID int64) (domain.CommandPayload, error) { 19 | ret := _m.Called(ctx, infraction, action, serverID) 20 | 21 | var r0 domain.CommandPayload 22 | if rf, ok := ret.Get(0).(func(context.Context, *domain.Infraction, string, int64) domain.CommandPayload); ok { 23 | r0 = rf(ctx, infraction, action, serverID) 24 | } else { 25 | if ret.Get(0) != nil { 26 | r0 = ret.Get(0).(domain.CommandPayload) 27 | } 28 | } 29 | 30 | var r1 error 31 | if rf, ok := ret.Get(1).(func(context.Context, *domain.Infraction, string, int64) error); ok { 32 | r1 = rf(ctx, infraction, action, serverID) 33 | } else { 34 | r1 = ret.Error(1) 35 | } 36 | 37 | return r0, r1 38 | } 39 | 40 | // RunCommands provides a mock function with given fields: payload 41 | func (_m *CommandExecutor) RunCommands(payload domain.CommandPayload) error { 42 | ret := _m.Called(payload) 43 | 44 | var r0 error 45 | if rf, ok := ret.Get(0).(func(domain.CommandPayload) error); ok { 46 | r0 = rf(payload) 47 | } else { 48 | r0 = ret.Error(0) 49 | } 50 | 51 | return r0 52 | } 53 | -------------------------------------------------------------------------------- /src/domain/mocks/FlaggedWordRepo.go: -------------------------------------------------------------------------------- 1 | // Code generated by mockery v0.0.0-dev. DO NOT EDIT. 2 | 3 | package mocks 4 | 5 | import ( 6 | domain "Refractor/domain" 7 | context "context" 8 | 9 | mock "github.com/stretchr/testify/mock" 10 | ) 11 | 12 | // FlaggedWordRepo is an autogenerated mock type for the FlaggedWordRepo type 13 | type FlaggedWordRepo struct { 14 | mock.Mock 15 | } 16 | 17 | // Delete provides a mock function with given fields: ctx, id 18 | func (_m *FlaggedWordRepo) Delete(ctx context.Context, id int64) error { 19 | ret := _m.Called(ctx, id) 20 | 21 | var r0 error 22 | if rf, ok := ret.Get(0).(func(context.Context, int64) error); ok { 23 | r0 = rf(ctx, id) 24 | } else { 25 | r0 = ret.Error(0) 26 | } 27 | 28 | return r0 29 | } 30 | 31 | // GetAll provides a mock function with given fields: ctx 32 | func (_m *FlaggedWordRepo) GetAll(ctx context.Context) ([]*domain.FlaggedWord, error) { 33 | ret := _m.Called(ctx) 34 | 35 | var r0 []*domain.FlaggedWord 36 | if rf, ok := ret.Get(0).(func(context.Context) []*domain.FlaggedWord); ok { 37 | r0 = rf(ctx) 38 | } else { 39 | if ret.Get(0) != nil { 40 | r0 = ret.Get(0).([]*domain.FlaggedWord) 41 | } 42 | } 43 | 44 | var r1 error 45 | if rf, ok := ret.Get(1).(func(context.Context) error); ok { 46 | r1 = rf(ctx) 47 | } else { 48 | r1 = ret.Error(1) 49 | } 50 | 51 | return r0, r1 52 | } 53 | 54 | // Store provides a mock function with given fields: ctx, word 55 | func (_m *FlaggedWordRepo) Store(ctx context.Context, word *domain.FlaggedWord) error { 56 | ret := _m.Called(ctx, word) 57 | 58 | var r0 error 59 | if rf, ok := ret.Get(0).(func(context.Context, *domain.FlaggedWord) error); ok { 60 | r0 = rf(ctx, word) 61 | } else { 62 | r0 = ret.Error(0) 63 | } 64 | 65 | return r0 66 | } 67 | 68 | // Update provides a mock function with given fields: ctx, id, newWord 69 | func (_m *FlaggedWordRepo) Update(ctx context.Context, id int64, newWord string) (*domain.FlaggedWord, error) { 70 | ret := _m.Called(ctx, id, newWord) 71 | 72 | var r0 *domain.FlaggedWord 73 | if rf, ok := ret.Get(0).(func(context.Context, int64, string) *domain.FlaggedWord); ok { 74 | r0 = rf(ctx, id, newWord) 75 | } else { 76 | if ret.Get(0) != nil { 77 | r0 = ret.Get(0).(*domain.FlaggedWord) 78 | } 79 | } 80 | 81 | var r1 error 82 | if rf, ok := ret.Get(1).(func(context.Context, int64, string) error); ok { 83 | r1 = rf(ctx, id, newWord) 84 | } else { 85 | r1 = ret.Error(1) 86 | } 87 | 88 | return r0, r1 89 | } 90 | -------------------------------------------------------------------------------- /src/domain/mocks/GameRepo.go: -------------------------------------------------------------------------------- 1 | // Code generated by mockery v0.0.0-dev. DO NOT EDIT. 2 | 3 | package mocks 4 | 5 | import ( 6 | domain "Refractor/domain" 7 | 8 | mock "github.com/stretchr/testify/mock" 9 | ) 10 | 11 | // GameRepo is an autogenerated mock type for the GameRepo type 12 | type GameRepo struct { 13 | mock.Mock 14 | } 15 | 16 | // GetSettings provides a mock function with given fields: game 17 | func (_m *GameRepo) GetSettings(game domain.Game) (*domain.GameSettings, error) { 18 | ret := _m.Called(game) 19 | 20 | var r0 *domain.GameSettings 21 | if rf, ok := ret.Get(0).(func(domain.Game) *domain.GameSettings); ok { 22 | r0 = rf(game) 23 | } else { 24 | if ret.Get(0) != nil { 25 | r0 = ret.Get(0).(*domain.GameSettings) 26 | } 27 | } 28 | 29 | var r1 error 30 | if rf, ok := ret.Get(1).(func(domain.Game) error); ok { 31 | r1 = rf(game) 32 | } else { 33 | r1 = ret.Error(1) 34 | } 35 | 36 | return r0, r1 37 | } 38 | 39 | // SetSettings provides a mock function with given fields: game, settings 40 | func (_m *GameRepo) SetSettings(game domain.Game, settings *domain.GameSettings) error { 41 | ret := _m.Called(game, settings) 42 | 43 | var r0 error 44 | if rf, ok := ret.Get(0).(func(domain.Game, *domain.GameSettings) error); ok { 45 | r0 = rf(game, settings) 46 | } else { 47 | r0 = ret.Error(0) 48 | } 49 | 50 | return r0 51 | } 52 | -------------------------------------------------------------------------------- /src/domain/mocks/MailService.go: -------------------------------------------------------------------------------- 1 | // Code generated by mockery v0.0.0-dev. DO NOT EDIT. 2 | 3 | package mocks 4 | 5 | import mock "github.com/stretchr/testify/mock" 6 | 7 | // MailService is an autogenerated mock type for the MailService type 8 | type MailService struct { 9 | mock.Mock 10 | } 11 | 12 | // SendMail provides a mock function with given fields: to, sub, body 13 | func (_m *MailService) SendMail(to []string, sub string, body string) error { 14 | ret := _m.Called(to, sub, body) 15 | 16 | var r0 error 17 | if rf, ok := ret.Get(0).(func([]string, string, string) error); ok { 18 | r0 = rf(to, sub, body) 19 | } else { 20 | r0 = ret.Error(0) 21 | } 22 | 23 | return r0 24 | } 25 | 26 | // SendWelcomeEmail provides a mock function with given fields: to, inviterName, link 27 | func (_m *MailService) SendWelcomeEmail(to string, inviterName string, link string) error { 28 | ret := _m.Called(to, inviterName, link) 29 | 30 | var r0 error 31 | if rf, ok := ret.Get(0).(func(string, string, string) error); ok { 32 | r0 = rf(to, inviterName, link) 33 | } else { 34 | r0 = ret.Error(0) 35 | } 36 | 37 | return r0 38 | } 39 | -------------------------------------------------------------------------------- /src/domain/mocks/PlayerNameRepo.go: -------------------------------------------------------------------------------- 1 | // Code generated by mockery v0.0.0-dev. DO NOT EDIT. 2 | 3 | package mocks 4 | 5 | import ( 6 | domain "Refractor/domain" 7 | context "context" 8 | 9 | mock "github.com/stretchr/testify/mock" 10 | ) 11 | 12 | // PlayerNameRepo is an autogenerated mock type for the PlayerNameRepo type 13 | type PlayerNameRepo struct { 14 | mock.Mock 15 | } 16 | 17 | // GetNames provides a mock function with given fields: ctx, id, platform 18 | func (_m *PlayerNameRepo) GetNames(ctx context.Context, id string, platform string) (string, []string, error) { 19 | ret := _m.Called(ctx, id, platform) 20 | 21 | var r0 string 22 | if rf, ok := ret.Get(0).(func(context.Context, string, string) string); ok { 23 | r0 = rf(ctx, id, platform) 24 | } else { 25 | r0 = ret.Get(0).(string) 26 | } 27 | 28 | var r1 []string 29 | if rf, ok := ret.Get(1).(func(context.Context, string, string) []string); ok { 30 | r1 = rf(ctx, id, platform) 31 | } else { 32 | if ret.Get(1) != nil { 33 | r1 = ret.Get(1).([]string) 34 | } 35 | } 36 | 37 | var r2 error 38 | if rf, ok := ret.Get(2).(func(context.Context, string, string) error); ok { 39 | r2 = rf(ctx, id, platform) 40 | } else { 41 | r2 = ret.Error(2) 42 | } 43 | 44 | return r0, r1, r2 45 | } 46 | 47 | // Store provides a mock function with given fields: ctx, id, platform, name 48 | func (_m *PlayerNameRepo) Store(ctx context.Context, id string, platform string, name string) error { 49 | ret := _m.Called(ctx, id, platform, name) 50 | 51 | var r0 error 52 | if rf, ok := ret.Get(0).(func(context.Context, string, string, string) error); ok { 53 | r0 = rf(ctx, id, platform, name) 54 | } else { 55 | r0 = ret.Error(0) 56 | } 57 | 58 | return r0 59 | } 60 | 61 | // UpdateName provides a mock function with given fields: ctx, player, newName 62 | func (_m *PlayerNameRepo) UpdateName(ctx context.Context, player *domain.Player, newName string) error { 63 | ret := _m.Called(ctx, player, newName) 64 | 65 | var r0 error 66 | if rf, ok := ret.Get(0).(func(context.Context, *domain.Player, string) error); ok { 67 | r0 = rf(ctx, player, newName) 68 | } else { 69 | r0 = ret.Error(0) 70 | } 71 | 72 | return r0 73 | } 74 | -------------------------------------------------------------------------------- /src/domain/mocks/PlayerStatsService.go: -------------------------------------------------------------------------------- 1 | // Code generated by mockery v0.0.0-dev. DO NOT EDIT. 2 | 3 | package mocks 4 | 5 | import ( 6 | domain "Refractor/domain" 7 | context "context" 8 | 9 | mock "github.com/stretchr/testify/mock" 10 | ) 11 | 12 | // PlayerStatsService is an autogenerated mock type for the PlayerStatsService type 13 | type PlayerStatsService struct { 14 | mock.Mock 15 | } 16 | 17 | // GetInfractionCount provides a mock function with given fields: c, platform, playerID 18 | func (_m *PlayerStatsService) GetInfractionCount(c context.Context, platform string, playerID string) (int, error) { 19 | ret := _m.Called(c, platform, playerID) 20 | 21 | var r0 int 22 | if rf, ok := ret.Get(0).(func(context.Context, string, string) int); ok { 23 | r0 = rf(c, platform, playerID) 24 | } else { 25 | r0 = ret.Get(0).(int) 26 | } 27 | 28 | var r1 error 29 | if rf, ok := ret.Get(1).(func(context.Context, string, string) error); ok { 30 | r1 = rf(c, platform, playerID) 31 | } else { 32 | r1 = ret.Error(1) 33 | } 34 | 35 | return r0, r1 36 | } 37 | 38 | // GetInfractionCountSince provides a mock function with given fields: c, platform, playerID, sinceMinutes 39 | func (_m *PlayerStatsService) GetInfractionCountSince(c context.Context, platform string, playerID string, sinceMinutes int) (int, error) { 40 | ret := _m.Called(c, platform, playerID, sinceMinutes) 41 | 42 | var r0 int 43 | if rf, ok := ret.Get(0).(func(context.Context, string, string, int) int); ok { 44 | r0 = rf(c, platform, playerID, sinceMinutes) 45 | } else { 46 | r0 = ret.Get(0).(int) 47 | } 48 | 49 | var r1 error 50 | if rf, ok := ret.Get(1).(func(context.Context, string, string, int) error); ok { 51 | r1 = rf(c, platform, playerID, sinceMinutes) 52 | } else { 53 | r1 = ret.Error(1) 54 | } 55 | 56 | return r0, r1 57 | } 58 | 59 | // GetPlayerPayload provides a mock function with given fields: c, platform, playerID, game 60 | func (_m *PlayerStatsService) GetPlayerPayload(c context.Context, platform string, playerID string, game domain.Game) (*domain.PlayerPayload, error) { 61 | ret := _m.Called(c, platform, playerID, game) 62 | 63 | var r0 *domain.PlayerPayload 64 | if rf, ok := ret.Get(0).(func(context.Context, string, string, domain.Game) *domain.PlayerPayload); ok { 65 | r0 = rf(c, platform, playerID, game) 66 | } else { 67 | if ret.Get(0) != nil { 68 | r0 = ret.Get(0).(*domain.PlayerPayload) 69 | } 70 | } 71 | 72 | var r1 error 73 | if rf, ok := ret.Get(1).(func(context.Context, string, string, domain.Game) error); ok { 74 | r1 = rf(c, platform, playerID, game) 75 | } else { 76 | r1 = ret.Error(1) 77 | } 78 | 79 | return r0, r1 80 | } 81 | -------------------------------------------------------------------------------- /src/domain/mocks/RCONClient.go: -------------------------------------------------------------------------------- 1 | // Code generated by mockery v0.0.0-dev. DO NOT EDIT. 2 | 3 | package mocks 4 | 5 | import ( 6 | domain "Refractor/domain" 7 | 8 | rcon "github.com/refractorgscm/rcon" 9 | mock "github.com/stretchr/testify/mock" 10 | 11 | sync "sync" 12 | ) 13 | 14 | // RCONClient is an autogenerated mock type for the RCONClient type 15 | type RCONClient struct { 16 | mock.Mock 17 | } 18 | 19 | // Close provides a mock function with given fields: 20 | func (_m *RCONClient) Close() error { 21 | ret := _m.Called() 22 | 23 | var r0 error 24 | if rf, ok := ret.Get(0).(func() error); ok { 25 | r0 = rf() 26 | } else { 27 | r0 = ret.Error(0) 28 | } 29 | 30 | return r0 31 | } 32 | 33 | // Connect provides a mock function with given fields: 34 | func (_m *RCONClient) Connect() error { 35 | ret := _m.Called() 36 | 37 | var r0 error 38 | if rf, ok := ret.Get(0).(func() error); ok { 39 | r0 = rf() 40 | } else { 41 | r0 = ret.Error(0) 42 | } 43 | 44 | return r0 45 | } 46 | 47 | // GetGame provides a mock function with given fields: 48 | func (_m *RCONClient) GetGame() domain.Game { 49 | ret := _m.Called() 50 | 51 | var r0 domain.Game 52 | if rf, ok := ret.Get(0).(func() domain.Game); ok { 53 | r0 = rf() 54 | } else { 55 | if ret.Get(0) != nil { 56 | r0 = ret.Get(0).(domain.Game) 57 | } 58 | } 59 | 60 | return r0 61 | } 62 | 63 | // RunCommand provides a mock function with given fields: _a0 64 | func (_m *RCONClient) RunCommand(_a0 string) (string, error) { 65 | ret := _m.Called(_a0) 66 | 67 | var r0 string 68 | if rf, ok := ret.Get(0).(func(string) string); ok { 69 | r0 = rf(_a0) 70 | } else { 71 | r0 = ret.Get(0).(string) 72 | } 73 | 74 | var r1 error 75 | if rf, ok := ret.Get(1).(func(string) error); ok { 76 | r1 = rf(_a0) 77 | } else { 78 | r1 = ret.Error(1) 79 | } 80 | 81 | return r0, r1 82 | } 83 | 84 | // SetBroadcastChecker provides a mock function with given fields: handlerFunc 85 | func (_m *RCONClient) SetBroadcastChecker(handlerFunc rcon.BroadcastMessageChecker) { 86 | _m.Called(handlerFunc) 87 | } 88 | 89 | // SetBroadcastHandler provides a mock function with given fields: handlerFunc 90 | func (_m *RCONClient) SetBroadcastHandler(handlerFunc rcon.BroadcastHandler) { 91 | _m.Called(handlerFunc) 92 | } 93 | 94 | // SetDisconnectHandler provides a mock function with given fields: handlerFunc 95 | func (_m *RCONClient) SetDisconnectHandler(handlerFunc rcon.DisconnectHandler) { 96 | _m.Called(handlerFunc) 97 | } 98 | 99 | // WaitGroup provides a mock function with given fields: 100 | func (_m *RCONClient) WaitGroup() *sync.WaitGroup { 101 | ret := _m.Called() 102 | 103 | var r0 *sync.WaitGroup 104 | if rf, ok := ret.Get(0).(func() *sync.WaitGroup); ok { 105 | r0 = rf() 106 | } else { 107 | if ret.Get(0) != nil { 108 | r0 = ret.Get(0).(*sync.WaitGroup) 109 | } 110 | } 111 | 112 | return r0 113 | } 114 | -------------------------------------------------------------------------------- /src/domain/platform.go: -------------------------------------------------------------------------------- 1 | /* 2 | * This file is part of Refractor. 3 | * 4 | * Refractor is free software: you can redistribute it and/or modify 5 | * it under the terms of the GNU General Public License as published by 6 | * the Free Software Foundation, either version 3 of the License, or 7 | * (at your option) any later version. 8 | * 9 | * This program is distributed in the hope that it will be useful, 10 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 11 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 | * GNU General Public License for more details. 13 | * 14 | * You should have received a copy of the GNU General Public License 15 | * along with this program. If not, see . 16 | */ 17 | 18 | package domain 19 | 20 | var AllPlatforms = []string{ 21 | "playfab", 22 | "mojang", 23 | } 24 | 25 | type Platform interface { 26 | GetName() string 27 | GetDisplayName() string 28 | } 29 | -------------------------------------------------------------------------------- /src/domain/player_stats.go: -------------------------------------------------------------------------------- 1 | /* 2 | * This file is part of Refractor. 3 | * 4 | * Refractor is free software: you can redistribute it and/or modify 5 | * it under the terms of the GNU General Public License as published by 6 | * the Free Software Foundation, either version 3 of the License, or 7 | * (at your option) any later version. 8 | * 9 | * This program is distributed in the hope that it will be useful, 10 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 11 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 | * GNU General Public License for more details. 13 | * 14 | * You should have received a copy of the GNU General Public License 15 | * along with this program. If not, see . 16 | */ 17 | 18 | package domain 19 | 20 | import ( 21 | "context" 22 | ) 23 | 24 | type PlayerStatsService interface { 25 | GetInfractionCount(c context.Context, platform, playerID string) (int, error) 26 | GetInfractionCountSince(c context.Context, platform, playerID string, sinceMinutes int) (int, error) 27 | GetPlayerPayload(c context.Context, platform, playerID string, game Game) (*PlayerPayload, error) 28 | } 29 | -------------------------------------------------------------------------------- /src/domain/querybuilder.go: -------------------------------------------------------------------------------- 1 | /* 2 | * This file is part of Refractor. 3 | * 4 | * Refractor is free software: you can redistribute it and/or modify 5 | * it under the terms of the GNU General Public License as published by 6 | * the Free Software Foundation, either version 3 of the License, or 7 | * (at your option) any later version. 8 | * 9 | * This program is distributed in the hope that it will be useful, 10 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 11 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 | * GNU General Public License for more details. 13 | * 14 | * You should have received a copy of the GNU General Public License 15 | * along with this program. If not, see . 16 | */ 17 | 18 | package domain 19 | 20 | type QueryBuilder interface { 21 | BuildExistsQuery(table string, args map[string]interface{}) (string, []interface{}) 22 | BuildFindQuery(table string, args map[string]interface{}) (string, []interface{}) 23 | BuildUpdateQuery(table string, id interface{}, idName string, args map[string]interface{}, returnFields []string) (string, []interface{}) 24 | BuildUpdateQueryComposite(table string, ids []interface{}, idNames []string, args map[string]interface{}) (string, []interface{}) 25 | } 26 | -------------------------------------------------------------------------------- /src/domain/rcon.go: -------------------------------------------------------------------------------- 1 | /* 2 | * This file is part of Refractor. 3 | * 4 | * Refractor is free software: you can redistribute it and/or modify 5 | * it under the terms of the GNU General Public License as published by 6 | * the Free Software Foundation, either version 3 of the License, or 7 | * (at your option) any later version. 8 | * 9 | * This program is distributed in the hope that it will be useful, 10 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 11 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 | * GNU General Public License for more details. 13 | * 14 | * You should have received a copy of the GNU General Public License 15 | * along with this program. If not, see . 16 | */ 17 | 18 | package domain 19 | 20 | import ( 21 | "Refractor/pkg/broadcast" 22 | "github.com/refractorgscm/rcon" 23 | "sync" 24 | ) 25 | 26 | type ClientCreator interface { 27 | GetClientFromConfig(game Game, server *Server) (RCONClient, error) 28 | } 29 | 30 | type RCONClient interface { 31 | RunCommand(string) (string, error) 32 | Connect() error 33 | WaitGroup() *sync.WaitGroup 34 | SetBroadcastHandler(handlerFunc rcon.BroadcastHandler) 35 | SetDisconnectHandler(handlerFunc rcon.DisconnectHandler) 36 | SetBroadcastChecker(handlerFunc rcon.BroadcastMessageChecker) 37 | GetGame() Game 38 | Close() error 39 | } 40 | 41 | type OnlinePlayer struct { 42 | PlayerID string `json:"player_id"` 43 | Name string `json:"name"` 44 | } 45 | 46 | type BroadcastSubscriber func(fields broadcast.Fields, serverID int64, game Game) 47 | type PlayerListUpdateSubscriber func(serverID int64, players []*OnlinePlayer, game Game) 48 | type ServerStatusSubscriber func(serverID int64, status string) 49 | type ChatReceiveSubscriber func(body *ChatReceiveBody, serverID int64, game Game) 50 | 51 | type RCONService interface { 52 | CreateClient(server *Server) error 53 | GetClients() map[int64]RCONClient 54 | DeleteClient(serverID int64) 55 | GetServerClient(serverID int64) RCONClient 56 | RefreshPlayerList(serverID int64, game Game) error 57 | StartReconnectRoutine(serverID int64, data *ServerData) 58 | SubscribeJoin(sub BroadcastSubscriber) 59 | SubscribeQuit(sub BroadcastSubscriber) 60 | SubscribePlayerListUpdate(sub PlayerListUpdateSubscriber) 61 | SubscribeServerStatus(sub ServerStatusSubscriber) 62 | SubscribeChat(sub ChatReceiveSubscriber) 63 | SubscribeModeratorAction(sub BroadcastSubscriber) 64 | SendChatMessage(body *ChatSendBody) 65 | HandleServerUpdate(server *Server) 66 | } 67 | -------------------------------------------------------------------------------- /src/domain/search.go: -------------------------------------------------------------------------------- 1 | /* 2 | * This file is part of Refractor. 3 | * 4 | * Refractor is free software: you can redistribute it and/or modify 5 | * it under the terms of the GNU General Public License as published by 6 | * the Free Software Foundation, either version 3 of the License, or 7 | * (at your option) any later version. 8 | * 9 | * This program is distributed in the hope that it will be useful, 10 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 11 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 | * GNU General Public License for more details. 13 | * 14 | * You should have received a copy of the GNU General Public License 15 | * along with this program. If not, see . 16 | */ 17 | 18 | package domain 19 | 20 | import "context" 21 | 22 | type SearchService interface { 23 | SearchPlayers(c context.Context, term, searchType, platform string, limit, offset int) (int, []*Player, error) 24 | SearchInfractions(c context.Context, args FindArgs, limit, offset int) (int, []*Infraction, error) 25 | SearchChatMessages(c context.Context, args FindArgs, limit, offset int) (int, []*ChatMessage, error) 26 | } 27 | -------------------------------------------------------------------------------- /src/domain/stats.go: -------------------------------------------------------------------------------- 1 | /* 2 | * This file is part of Refractor. 3 | * 4 | * Refractor is free software: you can redistribute it and/or modify 5 | * it under the terms of the GNU General Public License as published by 6 | * the Free Software Foundation, either version 3 of the License, or 7 | * (at your option) any later version. 8 | * 9 | * This program is distributed in the hope that it will be useful, 10 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 11 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 | * GNU General Public License for more details. 13 | * 14 | * You should have received a copy of the GNU General Public License 15 | * along with this program. If not, see . 16 | */ 17 | 18 | package domain 19 | 20 | import ( 21 | "context" 22 | "time" 23 | ) 24 | 25 | type Stats struct { 26 | TotalPlayers int `json:"total_players"` 27 | NewPlayersLastDay int `json:"new_players_last_day"` 28 | UniquePlayersLastDay int `json:"unique_players_last_day"` 29 | TotalInfractions int `json:"total_infractions"` 30 | NewInfractionsLastDay int `json:"new_infractions_last_day"` 31 | TotalChatMessages int `json:"total_chat_messages"` 32 | TotalFlaggedChatMessages int `json:"total_flagged_chat_messages"` 33 | NewChatMessagesLastDay int `json:"new_chat_messages_last_day"` 34 | } 35 | 36 | type StatsRepo interface { 37 | GetTotalPlayers(ctx context.Context) (int, error) 38 | GetTotalInfractions(ctx context.Context) (int, error) 39 | GetTotalNewPlayersInRange(ctx context.Context, start, end time.Time) (int, error) 40 | GetTotalNewInfractionsInRange(ctx context.Context, start, end time.Time) (int, error) 41 | GetUniquePlayersInRange(ctx context.Context, start, end time.Time) (int, error) 42 | GetTotalChatMessages(ctx context.Context) (int, error) 43 | GetTotalChatMessagesInRange(ctx context.Context, start, end time.Time) (int, error) 44 | } 45 | 46 | type StatsService interface { 47 | GetStats(c context.Context) (*Stats, error) 48 | } 49 | -------------------------------------------------------------------------------- /src/domain/user.go: -------------------------------------------------------------------------------- 1 | /* 2 | * This file is part of Refractor. 3 | * 4 | * Refractor is free software: you can redistribute it and/or modify 5 | * it under the terms of the GNU General Public License as published by 6 | * the Free Software Foundation, either version 3 of the License, or 7 | * (at your option) any later version. 8 | * 9 | * This program is distributed in the hope that it will be useful, 10 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 11 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 | * GNU General Public License for more details. 13 | * 14 | * You should have received a copy of the GNU General Public License 15 | * along with this program. If not, see . 16 | */ 17 | 18 | package domain 19 | 20 | import ( 21 | "context" 22 | ) 23 | 24 | type User struct { 25 | ID string `json:"id"` 26 | Username string `json:"username"` 27 | Permissions string `json:"permissions"` 28 | Groups []*Group `json:"groups"` 29 | UserMeta *UserMeta `json:"meta"` 30 | } 31 | 32 | type UserMeta struct { 33 | ID string `json:"id"` 34 | InitialUsername string `json:"initial_username"` 35 | Username string `json:"username"` 36 | Deactivated bool `json:"deactivated"` 37 | } 38 | 39 | // UserMetaRepo is the interface to handle the storing of UserMeta data. This is NOT an auth repository and only contains 40 | // relevant metadata for Refractor. No user identities are stored in a UserMetaRepo! 41 | type UserMetaRepo interface { 42 | Store(ctx context.Context, userInfo *UserMeta) error 43 | GetByID(ctx context.Context, userID string) (*UserMeta, error) 44 | Update(ctx context.Context, userID string, args UpdateArgs) (*UserMeta, error) 45 | IsDeactivated(ctx context.Context, userID string) (bool, error) 46 | GetUsername(ctx context.Context, userID string) (string, error) 47 | LinkPlayer(ctx context.Context, userID, platform, playerID string) error 48 | UnlinkPlayer(ctx context.Context, userID, platform, playerID string) error 49 | GetLinkedPlayers(ctx context.Context, userID string) ([]*Player, error) 50 | } 51 | 52 | type UserService interface { 53 | GetAllUsers(c context.Context) ([]*User, error) 54 | GetByID(c context.Context, userID string) (*User, error) 55 | DeactivateUser(c context.Context, userID string) error 56 | ReactivateUser(c context.Context, userID string) error 57 | LinkPlayer(c context.Context, userID, platform, playerID string) error 58 | UnlinkPlayer(c context.Context, userID, platform, playerID string) error 59 | GetLinkedPlayers(c context.Context, userID string) ([]*Player, error) 60 | } 61 | -------------------------------------------------------------------------------- /src/domain/validation.go: -------------------------------------------------------------------------------- 1 | /* 2 | * This file is part of Refractor. 3 | * 4 | * Refractor is free software: you can redistribute it and/or modify 5 | * it under the terms of the GNU General Public License as published by 6 | * the Free Software Foundation, either version 3 of the License, or 7 | * (at your option) any later version. 8 | * 9 | * This program is distributed in the hope that it will be useful, 10 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 11 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 | * GNU General Public License for more details. 13 | * 14 | * You should have received a copy of the GNU General Public License 15 | * along with this program. If not, see . 16 | */ 17 | 18 | package domain 19 | 20 | type Validable interface { 21 | Validate() error 22 | } 23 | -------------------------------------------------------------------------------- /src/domain/websocket.go: -------------------------------------------------------------------------------- 1 | /* 2 | * This file is part of Refractor. 3 | * 4 | * Refractor is free software: you can redistribute it and/or modify 5 | * it under the terms of the GNU General Public License as published by 6 | * the Free Software Foundation, either version 3 of the License, or 7 | * (at your option) any later version. 8 | * 9 | * This program is distributed in the hope that it will be useful, 10 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 11 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 | * GNU General Public License for more details. 13 | * 14 | * You should have received a copy of the GNU General Public License 15 | * along with this program. If not, see . 16 | */ 17 | 18 | package domain 19 | 20 | import ( 21 | "Refractor/pkg/broadcast" 22 | "net" 23 | ) 24 | 25 | type WebsocketMessage struct { 26 | Type string `json:"type"` 27 | Body interface{} `json:"body"` 28 | } 29 | 30 | type WebsocketDirectMessage struct { 31 | ClientID int64 32 | Message *WebsocketMessage 33 | } 34 | 35 | type ChatSendBody struct { 36 | ServerID int64 `json:"server_id"` 37 | Message string `json:"message"` 38 | Sender string `json:"sender"` 39 | 40 | // SentByUser is true if this message was sent by another user 41 | SentByUser bool `json:"sent_by_user"` 42 | } 43 | 44 | type ChatSendSubscriber func(body *ChatSendBody) 45 | 46 | type WebsocketService interface { 47 | CreateClient(userID string, conn net.Conn) 48 | StartPool() 49 | Broadcast(message *WebsocketMessage) 50 | BroadcastServerMessage(message *WebsocketMessage, serverID int64, authChecker AuthChecker) error 51 | SendDirectMessage(message *WebsocketMessage, userID string) 52 | HandlePlayerJoin(fields broadcast.Fields, serverID int64, game Game) 53 | HandlePlayerQuit(fields broadcast.Fields, serverID int64, game Game) 54 | HandleServerStatusChange(serverID int64, status string) 55 | HandlePlayerListUpdate(serverID int64, players []*OnlinePlayer, game Game) 56 | HandleInfractionCreate(infraction *Infraction) 57 | SubscribeChatSend(sub ChatSendSubscriber) 58 | } 59 | -------------------------------------------------------------------------------- /src/go.mod: -------------------------------------------------------------------------------- 1 | module Refractor 2 | 3 | go 1.16 4 | 5 | require ( 6 | github.com/DATA-DOG/go-sqlmock v1.5.0 7 | github.com/asaskevich/govalidator v0.0.0-20210307081110-f21760c49a8d // indirect 8 | github.com/franela/goblin v0.0.0-20211003143422-0a4f594942bf 9 | github.com/go-gomail/gomail v0.0.0-20160411212932-81ebce5c23df 10 | github.com/go-ozzo/ozzo-validation v3.6.0+incompatible 11 | github.com/gobwas/ws v1.1.0 12 | github.com/golang-migrate/migrate/v4 v4.14.2-0.20210521165626-8a1a8534dc64 13 | github.com/gorilla/schema v1.2.0 14 | github.com/guregu/null v4.0.0+incompatible 15 | github.com/jackc/pgx/v4 v4.10.1 16 | github.com/joho/godotenv v1.3.0 17 | github.com/labstack/echo/v4 v4.6.1 18 | github.com/lib/pq v1.8.0 19 | github.com/onsi/gomega v1.16.0 20 | github.com/ory/kratos-client-go v0.7.0-alpha.1 21 | github.com/patrickmn/go-cache v2.1.0+incompatible 22 | github.com/pkg/errors v0.9.1 23 | github.com/refractorgscm/rcon v1.1.1 24 | github.com/stretchr/testify v1.7.0 25 | go.uber.org/zap v1.18.1 26 | google.golang.org/genproto v0.0.0-20210602131652-f16073e35f0c // indirect 27 | gopkg.in/alexcesaro/quotedprintable.v3 v3.0.0-20150716171945-2caba252f4dc // indirect 28 | gopkg.in/gomail.v2 v2.0.0-20160411212932-81ebce5c23df // indirect 29 | ) 30 | -------------------------------------------------------------------------------- /src/internal/auth/service/auth_service.go: -------------------------------------------------------------------------------- 1 | /* 2 | * This file is part of Refractor. 3 | * 4 | * Refractor is free software: you can redistribute it and/or modify 5 | * it under the terms of the GNU General Public License as published by 6 | * the Free Software Foundation, either version 3 of the License, or 7 | * (at your option) any later version. 8 | * 9 | * This program is distributed in the hope that it will be useful, 10 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 11 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 | * GNU General Public License for more details. 13 | * 14 | * You should have received a copy of the GNU General Public License 15 | * along with this program. If not, see . 16 | */ 17 | 18 | package service 19 | 20 | import ( 21 | "Refractor/domain" 22 | "context" 23 | "go.uber.org/zap" 24 | "time" 25 | ) 26 | 27 | type authService struct { 28 | repo domain.AuthRepo 29 | metaRepo domain.UserMetaRepo 30 | mailService domain.MailService 31 | timeout time.Duration 32 | logger *zap.Logger 33 | } 34 | 35 | func NewAuthService(repo domain.AuthRepo, mr domain.UserMetaRepo, mailService domain.MailService, to time.Duration, log *zap.Logger) domain.AuthService { 36 | return &authService{ 37 | repo: repo, 38 | metaRepo: mr, 39 | mailService: mailService, 40 | timeout: to, 41 | logger: log, 42 | } 43 | } 44 | 45 | func (s *authService) CreateUser(c context.Context, userTraits *domain.Traits, inviter string) (*domain.AuthUser, error) { 46 | ctx, cancel := context.WithTimeout(c, s.timeout) 47 | defer cancel() 48 | 49 | // Create the user 50 | user, err := s.repo.CreateUser(ctx, userTraits) 51 | if err != nil { 52 | return nil, err 53 | } 54 | 55 | s.logger.Info("User created", 56 | zap.String("User ID", user.Identity.Id), 57 | zap.String("Username", userTraits.Username), 58 | ) 59 | 60 | // Create the user's metadata 61 | if err := s.metaRepo.Store(ctx, &domain.UserMeta{ 62 | ID: user.Identity.Id, 63 | InitialUsername: user.Traits.Username, 64 | Username: user.Traits.Username, 65 | Deactivated: false, 66 | }); err != nil { 67 | return nil, err 68 | } 69 | 70 | // Generate a new recovery link for the user so they can set their password 71 | recoveryLink, err := s.repo.GetRecoveryLink(ctx, user.Identity.Id) 72 | if err != nil { 73 | return nil, err 74 | } 75 | 76 | // Send a welcome email containing the recovery link 77 | if err := s.mailService.SendWelcomeEmail(user.Traits.Email, inviter, recoveryLink); err != nil { 78 | return nil, err 79 | } 80 | 81 | s.logger.Info("Welcome email sent", 82 | zap.String("User ID", user.Identity.Id), 83 | zap.String("Username", userTraits.Username), 84 | ) 85 | 86 | return user, nil 87 | } 88 | -------------------------------------------------------------------------------- /src/internal/command_executor/infraction_command.go: -------------------------------------------------------------------------------- 1 | /* 2 | * This file is part of Refractor. 3 | * 4 | * Refractor is free software: you can redistribute it and/or modify 5 | * it under the terms of the GNU General Public License as published by 6 | * the Free Software Foundation, either version 3 of the License, or 7 | * (at your option) any later version. 8 | * 9 | * This program is distributed in the hope that it will be useful, 10 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 11 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 | * GNU General Public License for more details. 13 | * 14 | * You should have received a copy of the GNU General Public License 15 | * along with this program. If not, see . 16 | */ 17 | 18 | package command_executor 19 | 20 | import "Refractor/domain" 21 | 22 | type infractionCommandPayload struct { 23 | Commands []domain.Command 24 | Game domain.Game 25 | } 26 | 27 | func newInfractionCommandPayload(cmds []domain.Command, game domain.Game) domain.CommandPayload { 28 | return &infractionCommandPayload{cmds, game} 29 | } 30 | 31 | func (ic *infractionCommandPayload) GetCommands() []domain.Command { 32 | return ic.Commands 33 | } 34 | 35 | func (ic *infractionCommandPayload) GetGame() domain.Game { 36 | return ic.Game 37 | } 38 | 39 | type infractionCommand struct { 40 | Command string 41 | RunOnAll bool 42 | ServerID int64 43 | } 44 | 45 | func (i *infractionCommand) GetCommand() string { 46 | return i.Command 47 | } 48 | 49 | func (i *infractionCommand) ShouldRunOnAll() bool { 50 | return i.RunOnAll 51 | } 52 | 53 | func (i *infractionCommand) GetServerID() int64 { 54 | return i.ServerID 55 | } 56 | -------------------------------------------------------------------------------- /src/internal/game/service/game_service.go: -------------------------------------------------------------------------------- 1 | /* 2 | * This file is part of Refractor. 3 | * 4 | * Refractor is free software: you can redistribute it and/or modify 5 | * it under the terms of the GNU General Public License as published by 6 | * the Free Software Foundation, either version 3 of the License, or 7 | * (at your option) any later version. 8 | * 9 | * This program is distributed in the hope that it will be useful, 10 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 11 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 | * GNU General Public License for more details. 13 | * 14 | * You should have received a copy of the GNU General Public License 15 | * along with this program. If not, see . 16 | */ 17 | 18 | package service 19 | 20 | import ( 21 | "Refractor/domain" 22 | "time" 23 | ) 24 | 25 | type gameService struct { 26 | repo domain.GameRepo 27 | timeout time.Duration 28 | games map[string]domain.Game 29 | } 30 | 31 | func NewGameService(gr domain.GameRepo, to time.Duration) domain.GameService { 32 | return &gameService{ 33 | repo: gr, 34 | timeout: to, 35 | games: map[string]domain.Game{}, 36 | } 37 | } 38 | 39 | func (s *gameService) AddGame(game domain.Game) { 40 | s.games[game.GetName()] = game 41 | 42 | domain.AllGames = append(domain.AllGames, game.GetName()) 43 | } 44 | 45 | func (s *gameService) GetAllGames() []domain.Game { 46 | var games []domain.Game 47 | 48 | for _, game := range s.games { 49 | games = append(games, game) 50 | } 51 | 52 | return games 53 | } 54 | 55 | func (s *gameService) GameExists(name string) bool { 56 | return s.games[name] != nil 57 | } 58 | 59 | func (s *gameService) GetGame(name string) (domain.Game, error) { 60 | if !s.GameExists(name) { 61 | return nil, domain.ErrNotFound 62 | } 63 | 64 | return s.games[name], nil 65 | } 66 | 67 | func (s *gameService) GetGameSettings(game domain.Game) (*domain.GameSettings, error) { 68 | settings, err := s.repo.GetSettings(game) 69 | if err != nil { 70 | return nil, err 71 | } 72 | 73 | return settings, nil 74 | } 75 | 76 | func (s *gameService) GetGameSettingsByName(gameName string) (*domain.GameSettings, error) { 77 | game, err := s.GetGame(gameName) 78 | if err != nil { 79 | return nil, err 80 | } 81 | 82 | settings, err := s.repo.GetSettings(game) 83 | if err != nil { 84 | return nil, err 85 | } 86 | 87 | return settings, nil 88 | } 89 | 90 | func (s *gameService) SetGameSettings(game domain.Game, settings *domain.GameSettings) error { 91 | if err := s.repo.SetSettings(game, settings); err != nil { 92 | return err 93 | } 94 | 95 | return nil 96 | } 97 | -------------------------------------------------------------------------------- /src/internal/infraction/types/ban.go: -------------------------------------------------------------------------------- 1 | /* 2 | * This file is part of Refractor. 3 | * 4 | * Refractor is free software: you can redistribute it and/or modify 5 | * it under the terms of the GNU General Public License as published by 6 | * the Free Software Foundation, either version 3 of the License, or 7 | * (at your option) any later version. 8 | * 9 | * This program is distributed in the hope that it will be useful, 10 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 11 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 | * GNU General Public License for more details. 13 | * 14 | * You should have received a copy of the GNU General Public License 15 | * along with this program. If not, see . 16 | */ 17 | 18 | package types 19 | 20 | import "Refractor/domain" 21 | 22 | type Ban struct{} 23 | 24 | func (w *Ban) Name() string { 25 | return domain.InfractionTypeBan 26 | } 27 | 28 | func (w *Ban) AllowedUpdateFields() []string { 29 | return []string{"Reason", "Duration", "Repealed"} 30 | } 31 | -------------------------------------------------------------------------------- /src/internal/infraction/types/kick.go: -------------------------------------------------------------------------------- 1 | /* 2 | * This file is part of Refractor. 3 | * 4 | * Refractor is free software: you can redistribute it and/or modify 5 | * it under the terms of the GNU General Public License as published by 6 | * the Free Software Foundation, either version 3 of the License, or 7 | * (at your option) any later version. 8 | * 9 | * This program is distributed in the hope that it will be useful, 10 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 11 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 | * GNU General Public License for more details. 13 | * 14 | * You should have received a copy of the GNU General Public License 15 | * along with this program. If not, see . 16 | */ 17 | 18 | package types 19 | 20 | import "Refractor/domain" 21 | 22 | type Kick struct{} 23 | 24 | func (w *Kick) Name() string { 25 | return domain.InfractionTypeKick 26 | } 27 | 28 | func (w *Kick) AllowedUpdateFields() []string { 29 | return []string{"Reason", "Repealed"} 30 | } 31 | -------------------------------------------------------------------------------- /src/internal/infraction/types/mute.go: -------------------------------------------------------------------------------- 1 | /* 2 | * This file is part of Refractor. 3 | * 4 | * Refractor is free software: you can redistribute it and/or modify 5 | * it under the terms of the GNU General Public License as published by 6 | * the Free Software Foundation, either version 3 of the License, or 7 | * (at your option) any later version. 8 | * 9 | * This program is distributed in the hope that it will be useful, 10 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 11 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 | * GNU General Public License for more details. 13 | * 14 | * You should have received a copy of the GNU General Public License 15 | * along with this program. If not, see . 16 | */ 17 | 18 | package types 19 | 20 | import "Refractor/domain" 21 | 22 | type Mute struct{} 23 | 24 | func (w *Mute) Name() string { 25 | return domain.InfractionTypeMute 26 | } 27 | 28 | func (w *Mute) AllowedUpdateFields() []string { 29 | return []string{"Reason", "Duration", "Repealed"} 30 | } 31 | -------------------------------------------------------------------------------- /src/internal/infraction/types/warning.go: -------------------------------------------------------------------------------- 1 | /* 2 | * This file is part of Refractor. 3 | * 4 | * Refractor is free software: you can redistribute it and/or modify 5 | * it under the terms of the GNU General Public License as published by 6 | * the Free Software Foundation, either version 3 of the License, or 7 | * (at your option) any later version. 8 | * 9 | * This program is distributed in the hope that it will be useful, 10 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 11 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 | * GNU General Public License for more details. 13 | * 14 | * You should have received a copy of the GNU General Public License 15 | * along with this program. If not, see . 16 | */ 17 | 18 | package types 19 | 20 | import "Refractor/domain" 21 | 22 | type Warning struct{} 23 | 24 | func (w *Warning) Name() string { 25 | return domain.InfractionTypeWarning 26 | } 27 | 28 | func (w *Warning) AllowedUpdateFields() []string { 29 | return []string{"Reason", "Repealed"} 30 | } 31 | -------------------------------------------------------------------------------- /src/internal/mail/templates/welcome.html: -------------------------------------------------------------------------------- 1 | 17 | 18 |

Hello!

19 | 20 |

You've been invited by {{ .Inviter }} to join Refractor

21 | 22 |

Please click the link below to finish setting up your account.

23 | 24 | {{ .Link }} 25 | 26 |

If this email was sent to you by mistake, please disregard it.

-------------------------------------------------------------------------------- /src/internal/player/delivery/http/player_handler.go: -------------------------------------------------------------------------------- 1 | /* 2 | * This file is part of Refractor. 3 | * 4 | * Refractor is free software: you can redistribute it and/or modify 5 | * it under the terms of the GNU General Public License as published by 6 | * the Free Software Foundation, either version 3 of the License, or 7 | * (at your option) any later version. 8 | * 9 | * This program is distributed in the hope that it will be useful, 10 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 11 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 | * GNU General Public License for more details. 13 | * 14 | * You should have received a copy of the GNU General Public License 15 | * along with this program. If not, see . 16 | */ 17 | 18 | package http 19 | 20 | import ( 21 | "Refractor/authcheckers" 22 | "Refractor/domain" 23 | "Refractor/pkg/api/middleware" 24 | "github.com/labstack/echo/v4" 25 | "go.uber.org/zap" 26 | "net/http" 27 | "strings" 28 | ) 29 | 30 | type playerHandler struct { 31 | service domain.PlayerService 32 | authorizer domain.Authorizer 33 | logger *zap.Logger 34 | } 35 | 36 | func ApplyPlayerHandler(apiGroup *echo.Group, s domain.PlayerService, a domain.Authorizer, mware domain.Middleware, log *zap.Logger) { 37 | handler := &playerHandler{ 38 | service: s, 39 | authorizer: a, 40 | logger: log, 41 | } 42 | 43 | // Create the server routing group 44 | playerGroup := apiGroup.Group("/players", mware.ProtectMiddleware, mware.ActivationMiddleware) 45 | 46 | // Create an enforcer to authorize the user on the various endpoints 47 | enforcer := middleware.NewEnforcer(a, domain.AuthScope{ 48 | Type: domain.AuthObjRefractor, 49 | }, log) 50 | 51 | playerGroup.GET("/:platform/:id", handler.GetPlayer, enforcer.CheckAuth(authcheckers.CanViewPlayerRecords)) 52 | } 53 | 54 | func (h *playerHandler) GetPlayer(c echo.Context) error { 55 | platform := strings.ToLower(c.Param("platform")) 56 | id := c.Param("id") 57 | 58 | validPlatform := false 59 | for _, p := range domain.AllPlatforms { 60 | if p == platform { 61 | validPlatform = true 62 | break 63 | } 64 | } 65 | 66 | if !validPlatform { 67 | return c.JSON(http.StatusBadRequest, &domain.Response{ 68 | Success: false, 69 | Message: "Invalid platform", 70 | }) 71 | } 72 | 73 | player, err := h.service.GetPlayer(c.Request().Context(), id, platform) 74 | if err != nil { 75 | return err 76 | } 77 | 78 | return c.JSON(http.StatusOK, &domain.Response{ 79 | Success: true, 80 | Message: "Player found", 81 | Payload: player, 82 | }) 83 | } 84 | -------------------------------------------------------------------------------- /src/internal/rcon/clientcreator/clientcreator.go: -------------------------------------------------------------------------------- 1 | /* 2 | * This file is part of Refractor. 3 | * 4 | * Refractor is free software: you can redistribute it and/or modify 5 | * it under the terms of the GNU General Public License as published by 6 | * the Free Software Foundation, either version 3 of the License, or 7 | * (at your option) any later version. 8 | * 9 | * This program is distributed in the hope that it will be useful, 10 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 11 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 | * GNU General Public License for more details. 13 | * 14 | * You should have received a copy of the GNU General Public License 15 | * along with this program. If not, see . 16 | */ 17 | 18 | package clientcreator 19 | 20 | import ( 21 | "Refractor/domain" 22 | "encoding/binary" 23 | "github.com/refractorgscm/rcon" 24 | "strconv" 25 | "sync" 26 | ) 27 | 28 | type clientCreator struct{} 29 | 30 | type Client struct { 31 | game domain.Game 32 | lock sync.Mutex 33 | Server *domain.Server 34 | *rcon.Client 35 | } 36 | 37 | func (c *Client) RunCommand(cmd string) (string, error) { 38 | c.lock.Lock() 39 | defer c.lock.Unlock() 40 | 41 | return c.ExecCommand(cmd) 42 | } 43 | 44 | func (c *Client) GetGame() domain.Game { 45 | return c.game 46 | } 47 | 48 | func NewClientCreator() domain.ClientCreator { 49 | return &clientCreator{} 50 | } 51 | 52 | func (c *clientCreator) GetClientFromConfig(game domain.Game, server *domain.Server) (domain.RCONClient, error) { 53 | port, err := strconv.ParseUint(server.RCONPort, 10, 16) 54 | if err != nil { 55 | return nil, err 56 | } 57 | 58 | rconSettings := game.GetRCONSettings() 59 | 60 | // Create RCON client 61 | client := rcon.NewClient(&rcon.Config{ 62 | Host: server.Address, 63 | Port: uint16(port), 64 | Password: server.RCONPassword, 65 | EndianMode: binary.LittleEndian, 66 | BroadcastChecker: rconSettings.BroadcastChecker, 67 | RestrictedPacketIDs: rconSettings.RestrictedPacketIDs, 68 | }, nil) 69 | 70 | return &Client{ 71 | game: game, 72 | Server: server, 73 | Client: client, 74 | }, nil 75 | } 76 | -------------------------------------------------------------------------------- /src/internal/stats/delivery/http/stats_handler.go: -------------------------------------------------------------------------------- 1 | /* 2 | * This file is part of Refractor. 3 | * 4 | * Refractor is free software: you can redistribute it and/or modify 5 | * it under the terms of the GNU General Public License as published by 6 | * the Free Software Foundation, either version 3 of the License, or 7 | * (at your option) any later version. 8 | * 9 | * This program is distributed in the hope that it will be useful, 10 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 11 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 | * GNU General Public License for more details. 13 | * 14 | * You should have received a copy of the GNU General Public License 15 | * along with this program. If not, see . 16 | */ 17 | 18 | package http 19 | 20 | import ( 21 | "Refractor/domain" 22 | "github.com/labstack/echo/v4" 23 | "go.uber.org/zap" 24 | "net/http" 25 | ) 26 | 27 | type statsHandler struct { 28 | service domain.StatsService 29 | authorizer domain.Authorizer 30 | logger *zap.Logger 31 | } 32 | 33 | func ApplyStatsHandler(apiGroup *echo.Group, s domain.StatsService, a domain.Authorizer, 34 | mware domain.Middleware, log *zap.Logger) { 35 | handler := &statsHandler{ 36 | service: s, 37 | authorizer: a, 38 | logger: log, 39 | } 40 | 41 | // Create the stats routing group 42 | statsGroup := apiGroup.Group("/stats", mware.ProtectMiddleware, mware.ActivationMiddleware) 43 | 44 | statsGroup.GET("/", handler.GetStats) 45 | } 46 | 47 | func (h *statsHandler) GetStats(c echo.Context) error { 48 | stats, err := h.service.GetStats(c.Request().Context()) 49 | if err != nil { 50 | return err 51 | } 52 | 53 | return c.JSON(http.StatusOK, &domain.Response{ 54 | Success: true, 55 | Payload: stats, 56 | }) 57 | } 58 | -------------------------------------------------------------------------------- /src/internal/watchdog/rconserver.go: -------------------------------------------------------------------------------- 1 | /* 2 | * This file is part of Refractor. 3 | * 4 | * Refractor is free software: you can redistribute it and/or modify 5 | * it under the terms of the GNU General Public License as published by 6 | * the Free Software Foundation, either version 3 of the License, or 7 | * (at your option) any later version. 8 | * 9 | * This program is distributed in the hope that it will be useful, 10 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 11 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 | * GNU General Public License for more details. 13 | * 14 | * You should have received a copy of the GNU General Public License 15 | * along with this program. If not, see . 16 | */ 17 | 18 | package watchdog 19 | 20 | import ( 21 | "Refractor/domain" 22 | "context" 23 | "go.uber.org/zap" 24 | "time" 25 | ) 26 | 27 | func StartRCONServerWatchdog(rconService domain.RCONService, serverService domain.ServerService, log *zap.Logger) error { 28 | for { 29 | // Run every 15 seconds 30 | time.Sleep(time.Second * 15) 31 | 32 | rconClients := rconService.GetClients() 33 | allServerData, err := serverService.GetAllServerData() 34 | if err != nil { 35 | log.Error("Watchdog routine could not get all server data", zap.Error(err)) 36 | return err 37 | } 38 | 39 | if len(rconClients) != len(allServerData) { 40 | for _, serverData := range allServerData { 41 | client := rconClients[serverData.ServerID] 42 | 43 | // Check if an RCON client exists for this server. If not, create one 44 | if client == nil { 45 | if !serverData.ReconnectInProgress { 46 | server, err := serverService.GetByID(context.TODO(), serverData.ServerID) 47 | if err != nil || server == nil { 48 | log.Error( 49 | "Watchdog routine could not get server data", 50 | zap.Int64("Server", serverData.ServerID), 51 | zap.Error(err), 52 | ) 53 | continue 54 | } 55 | 56 | // Start reconnection routine 57 | log.Info("Reconnect routine not started. Starting...", zap.Int64("Server", server.ID)) 58 | go rconService.StartReconnectRoutine(server.ID, serverData) 59 | serverData.ReconnectInProgress = true 60 | } 61 | } 62 | } 63 | } 64 | } 65 | } 66 | -------------------------------------------------------------------------------- /src/internal/websocket/delivery/http/websocket_handler.go: -------------------------------------------------------------------------------- 1 | /* 2 | * This file is part of Refractor. 3 | * 4 | * Refractor is free software: you can redistribute it and/or modify 5 | * it under the terms of the GNU General Public License as published by 6 | * the Free Software Foundation, either version 3 of the License, or 7 | * (at your option) any later version. 8 | * 9 | * This program is distributed in the hope that it will be useful, 10 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 11 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 | * GNU General Public License for more details. 13 | * 14 | * You should have received a copy of the GNU General Public License 15 | * along with this program. If not, see . 16 | */ 17 | 18 | package http 19 | 20 | import ( 21 | "Refractor/domain" 22 | "Refractor/pkg/websocket" 23 | "fmt" 24 | "github.com/labstack/echo/v4" 25 | "go.uber.org/zap" 26 | ) 27 | 28 | type websocketHandler struct { 29 | service domain.WebsocketService 30 | logger *zap.Logger 31 | } 32 | 33 | func ApplyWebsocketHandler(echo *echo.Echo, ws domain.WebsocketService, mware domain.Middleware, log *zap.Logger) { 34 | handler := &websocketHandler{ 35 | service: ws, 36 | logger: log, 37 | } 38 | 39 | echo.Any("/ws", handler.WebsocketHandler, mware.ProtectMiddleware, mware.ActivationMiddleware) 40 | } 41 | 42 | func (h *websocketHandler) WebsocketHandler(c echo.Context) error { 43 | user, ok := c.Get("user").(*domain.AuthUser) 44 | if !ok { 45 | return fmt.Errorf("could not cast user as *domain.AuthUser") 46 | } 47 | 48 | conn, err := websocket.Upgrade(c.Response(), c.Request()) 49 | if err != nil { 50 | h.logger.Error("Could not upgrade websocket request", zap.String("User ID", user.Identity.Id), zap.Error(err)) 51 | return err 52 | } 53 | 54 | // Create a client for this server 55 | h.service.CreateClient(user.Identity.Id, conn) 56 | 57 | return nil 58 | } 59 | -------------------------------------------------------------------------------- /src/migrations/20210707174342_create_update_modified_at_function.down.sql: -------------------------------------------------------------------------------- 1 | /* 2 | * This file is part of Refractor. 3 | * 4 | * Refractor is free software: you can redistribute it and/or modify 5 | * it under the terms of the GNU General Public License as published by 6 | * the Free Software Foundation, either version 3 of the License, or 7 | * (at your option) any later version. 8 | * 9 | * This program is distributed in the hope that it will be useful, 10 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 11 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 | * GNU General Public License for more details. 13 | * 14 | * You should have received a copy of the GNU General Public License 15 | * along with this program. If not, see . 16 | */ 17 | 18 | DROP FUNCTION IF EXISTS update_modified_at_column(); -------------------------------------------------------------------------------- /src/migrations/20210707174342_create_update_modified_at_function.up.sql: -------------------------------------------------------------------------------- 1 | /* 2 | * This file is part of Refractor. 3 | * 4 | * Refractor is free software: you can redistribute it and/or modify 5 | * it under the terms of the GNU General Public License as published by 6 | * the Free Software Foundation, either version 3 of the License, or 7 | * (at your option) any later version. 8 | * 9 | * This program is distributed in the hope that it will be useful, 10 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 11 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 | * GNU General Public License for more details. 13 | * 14 | * You should have received a copy of the GNU General Public License 15 | * along with this program. If not, see . 16 | */ 17 | 18 | CREATE OR REPLACE FUNCTION update_modified_at_column() 19 | RETURNS TRIGGER AS $$ 20 | BEGIN 21 | NEW.ModifiedAt = now(); 22 | RETURN NEW; 23 | END; 24 | $$ LANGUAGE 'plpgsql'; -------------------------------------------------------------------------------- /src/migrations/20210710155956_create_groups_table.down.sql: -------------------------------------------------------------------------------- 1 | /* 2 | * This file is part of Refractor. 3 | * 4 | * Refractor is free software: you can redistribute it and/or modify 5 | * it under the terms of the GNU General Public License as published by 6 | * the Free Software Foundation, either version 3 of the License, or 7 | * (at your option) any later version. 8 | * 9 | * This program is distributed in the hope that it will be useful, 10 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 11 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 | * GNU General Public License for more details. 13 | * 14 | * You should have received a copy of the GNU General Public License 15 | * along with this program. If not, see . 16 | */ 17 | 18 | DROP TABLE IF EXISTS Groups; -------------------------------------------------------------------------------- /src/migrations/20210710155956_create_groups_table.up.sql: -------------------------------------------------------------------------------- 1 | /* 2 | * This file is part of Refractor. 3 | * 4 | * Refractor is free software: you can redistribute it and/or modify 5 | * it under the terms of the GNU General Public License as published by 6 | * the Free Software Foundation, either version 3 of the License, or 7 | * (at your option) any later version. 8 | * 9 | * This program is distributed in the hope that it will be useful, 10 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 11 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 | * GNU General Public License for more details. 13 | * 14 | * You should have received a copy of the GNU General Public License 15 | * along with this program. If not, see . 16 | */ 17 | 18 | CREATE TABLE IF NOT EXISTS Groups( 19 | GroupID SERIAL PRIMARY KEY, 20 | Name VARCHAR(20) NOT NULL, 21 | Color INT NOT NULL DEFAULT CAST(x'e0e0e0' AS INT), 22 | Position INT NOT NULL, 23 | Permissions VARCHAR(20) NOT NULL, 24 | CreatedAt TIMESTAMP DEFAULT CURRENT_TIMESTAMP, 25 | ModifiedAt TIMESTAMP 26 | ); 27 | 28 | DROP TRIGGER IF EXISTS update_groups_modat ON Groups; 29 | CREATE TRIGGER update_groups_modat BEFORE UPDATE ON Groups 30 | FOR EACH ROW EXECUTE PROCEDURE update_modified_at_column(); -------------------------------------------------------------------------------- /src/migrations/20210710155960_create_usergroups_table.down.sql: -------------------------------------------------------------------------------- 1 | /* 2 | * This file is part of Refractor. 3 | * 4 | * Refractor is free software: you can redistribute it and/or modify 5 | * it under the terms of the GNU General Public License as published by 6 | * the Free Software Foundation, either version 3 of the License, or 7 | * (at your option) any later version. 8 | * 9 | * This program is distributed in the hope that it will be useful, 10 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 11 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 | * GNU General Public License for more details. 13 | * 14 | * You should have received a copy of the GNU General Public License 15 | * along with this program. If not, see . 16 | */ 17 | 18 | DROP TABLE IF EXISTS UserGroups; -------------------------------------------------------------------------------- /src/migrations/20210710155960_create_usergroups_table.up.sql: -------------------------------------------------------------------------------- 1 | /* 2 | * This file is part of Refractor. 3 | * 4 | * Refractor is free software: you can redistribute it and/or modify 5 | * it under the terms of the GNU General Public License as published by 6 | * the Free Software Foundation, either version 3 of the License, or 7 | * (at your option) any later version. 8 | * 9 | * This program is distributed in the hope that it will be useful, 10 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 11 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 | * GNU General Public License for more details. 13 | * 14 | * You should have received a copy of the GNU General Public License 15 | * along with this program. If not, see . 16 | */ 17 | 18 | CREATE TABLE IF NOT EXISTS UserGroups( 19 | UserID VARCHAR(36) NOT NULL, 20 | GroupID SERIAL NOT NULL, 21 | 22 | PRIMARY KEY (UserID, GroupID), 23 | FOREIGN KEY (GroupID) REFERENCES Groups(GroupID) ON DELETE CASCADE 24 | ) -------------------------------------------------------------------------------- /src/migrations/20210710161007_create_servers_table.down.sql: -------------------------------------------------------------------------------- 1 | /* 2 | * This file is part of Refractor. 3 | * 4 | * Refractor is free software: you can redistribute it and/or modify 5 | * it under the terms of the GNU General Public License as published by 6 | * the Free Software Foundation, either version 3 of the License, or 7 | * (at your option) any later version. 8 | * 9 | * This program is distributed in the hope that it will be useful, 10 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 11 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 | * GNU General Public License for more details. 13 | * 14 | * You should have received a copy of the GNU General Public License 15 | * along with this program. If not, see . 16 | */ 17 | 18 | DROP TABLE IF EXISTS Servers; -------------------------------------------------------------------------------- /src/migrations/20210710161007_create_servers_table.up.sql: -------------------------------------------------------------------------------- 1 | /* 2 | * This file is part of Refractor. 3 | * 4 | * Refractor is free software: you can redistribute it and/or modify 5 | * it under the terms of the GNU General Public License as published by 6 | * the Free Software Foundation, either version 3 of the License, or 7 | * (at your option) any later version. 8 | * 9 | * This program is distributed in the hope that it will be useful, 10 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 11 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 | * GNU General Public License for more details. 13 | * 14 | * You should have received a copy of the GNU General Public License 15 | * along with this program. If not, see . 16 | */ 17 | 18 | CREATE TABLE IF NOT EXISTS Servers( 19 | ServerID SERIAL NOT NULL PRIMARY KEY, 20 | Game VARCHAR(32) NOT NULL, 21 | Name VARCHAR(20) NOT NULL, 22 | Address VARCHAR(15) NOT NULL, 23 | RCONPort VARCHAR(5) NOT NULL, 24 | RCONPassword BYTEA NOT NULL, 25 | Deactivated BOOLEAN DEFAULT FALSE, 26 | CreatedAt TIMESTAMP DEFAULT CURRENT_TIMESTAMP, 27 | ModifiedAt TIMESTAMP 28 | ); 29 | 30 | DROP TRIGGER IF EXISTS update_servers_modat ON Servers; 31 | CREATE TRIGGER update_servers_modat BEFORE UPDATE ON Servers 32 | FOR EACH ROW EXECUTE PROCEDURE update_modified_at_column(); -------------------------------------------------------------------------------- /src/migrations/20210712140232_create_servergroups_table.down.sql: -------------------------------------------------------------------------------- 1 | /* 2 | * This file is part of Refractor. 3 | * 4 | * Refractor is free software: you can redistribute it and/or modify 5 | * it under the terms of the GNU General Public License as published by 6 | * the Free Software Foundation, either version 3 of the License, or 7 | * (at your option) any later version. 8 | * 9 | * This program is distributed in the hope that it will be useful, 10 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 11 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 | * GNU General Public License for more details. 13 | * 14 | * You should have received a copy of the GNU General Public License 15 | * along with this program. If not, see . 16 | */ 17 | 18 | DROP TABLE IF EXISTS ServerGroups; -------------------------------------------------------------------------------- /src/migrations/20210712140232_create_servergroups_table.up.sql: -------------------------------------------------------------------------------- 1 | /* 2 | * This file is part of Refractor. 3 | * 4 | * Refractor is free software: you can redistribute it and/or modify 5 | * it under the terms of the GNU General Public License as published by 6 | * the Free Software Foundation, either version 3 of the License, or 7 | * (at your option) any later version. 8 | * 9 | * This program is distributed in the hope that it will be useful, 10 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 11 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 | * GNU General Public License for more details. 13 | * 14 | * You should have received a copy of the GNU General Public License 15 | * along with this program. If not, see . 16 | */ 17 | 18 | CREATE TABLE IF NOT EXISTS ServerGroups( 19 | ServerID SERIAL NOT NULL, 20 | GroupID SERIAL NOT NULL, 21 | AllowOverrides VARCHAR(20) NOT NULL DEFAULT '0', 22 | DenyOverrides VARCHAR(20) NOT NULL DEFAULT '0', 23 | 24 | PRIMARY KEY (ServerID, GroupID), 25 | FOREIGN KEY (ServerID) REFERENCES Servers(ServerID), 26 | FOREIGN KEY (GroupID) REFERENCES Groups(GroupID) ON DELETE CASCADE 27 | ) -------------------------------------------------------------------------------- /src/migrations/20210717152944_create_useroverrides_table.down.sql: -------------------------------------------------------------------------------- 1 | /* 2 | * This file is part of Refractor. 3 | * 4 | * Refractor is free software: you can redistribute it and/or modify 5 | * it under the terms of the GNU General Public License as published by 6 | * the Free Software Foundation, either version 3 of the License, or 7 | * (at your option) any later version. 8 | * 9 | * This program is distributed in the hope that it will be useful, 10 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 11 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 | * GNU General Public License for more details. 13 | * 14 | * You should have received a copy of the GNU General Public License 15 | * along with this program. If not, see . 16 | */ 17 | 18 | DROP TABLE IF EXISTS UserOverrides; -------------------------------------------------------------------------------- /src/migrations/20210717152944_create_useroverrides_table.up.sql: -------------------------------------------------------------------------------- 1 | /* 2 | * This file is part of Refractor. 3 | * 4 | * Refractor is free software: you can redistribute it and/or modify 5 | * it under the terms of the GNU General Public License as published by 6 | * the Free Software Foundation, either version 3 of the License, or 7 | * (at your option) any later version. 8 | * 9 | * This program is distributed in the hope that it will be useful, 10 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 11 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 | * GNU General Public License for more details. 13 | * 14 | * You should have received a copy of the GNU General Public License 15 | * along with this program. If not, see . 16 | */ 17 | 18 | CREATE TABLE IF NOT EXISTS UserOverrides( 19 | UserID VARCHAR(36) UNIQUE NOT NULL, 20 | AllowOverrides VARCHAR(20) NOT NULL DEFAULT '0', 21 | DenyOverrides VARCHAR(20) NOT NULL DEFAULT '0' 22 | ) -------------------------------------------------------------------------------- /src/migrations/20210720160756_create_groups_reorder_func.down.sql: -------------------------------------------------------------------------------- 1 | DROP TYPE reorder_groups_info; -------------------------------------------------------------------------------- /src/migrations/20210720160756_create_groups_reorder_func.up.sql: -------------------------------------------------------------------------------- 1 | DO $$ BEGIN 2 | CREATE TYPE reorder_groups_info AS ( 3 | GroupID INT, 4 | NewPos INT 5 | ); 6 | EXCEPTION 7 | WHEN duplicate_object THEN NULL; 8 | END $$; 9 | 10 | CREATE OR REPLACE FUNCTION reorder_groups(newpos reorder_groups_info[]) RETURNS VOID LANGUAGE plpgsql AS $$ 11 | DECLARE ginfo reorder_groups_info; 12 | BEGIN 13 | FOREACH ginfo IN ARRAY newpos 14 | LOOP 15 | UPDATE Groups SET Position = ginfo.NewPos WHERE GroupID = ginfo.GroupID; 16 | END LOOP; 17 | END; $$; -------------------------------------------------------------------------------- /src/migrations/20210727131757_create_usermeta_table.down.sql: -------------------------------------------------------------------------------- 1 | /* 2 | * This file is part of Refractor. 3 | * 4 | * Refractor is free software: you can redistribute it and/or modify 5 | * it under the terms of the GNU General Public License as published by 6 | * the Free Software Foundation, either version 3 of the License, or 7 | * (at your option) any later version. 8 | * 9 | * This program is distributed in the hope that it will be useful, 10 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 11 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 | * GNU General Public License for more details. 13 | * 14 | * You should have received a copy of the GNU General Public License 15 | * along with this program. If not, see . 16 | */ 17 | 18 | DROP TABLE IF EXISTS UserMeta; -------------------------------------------------------------------------------- /src/migrations/20210727131757_create_usermeta_table.up.sql: -------------------------------------------------------------------------------- 1 | /* 2 | * This file is part of Refractor. 3 | * 4 | * Refractor is free software: you can redistribute it and/or modify 5 | * it under the terms of the GNU General Public License as published by 6 | * the Free Software Foundation, either version 3 of the License, or 7 | * (at your option) any later version. 8 | * 9 | * This program is distributed in the hope that it will be useful, 10 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 11 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 | * GNU General Public License for more details. 13 | * 14 | * You should have received a copy of the GNU General Public License 15 | * along with this program. If not, see . 16 | */ 17 | 18 | /* The UserMeta is for recording user info as well as other metadata not currently supported by Ory Kratos (the identity 19 | management solution we are using). Storing this data separately allows us to keep track of contextual info which may 20 | be useful to Refractor admins. This table also contains the 'Deactivated' property which allows us to block user 21 | requests if an account needs to be deactivated without having to delete their account. 22 | */ 23 | CREATE TABLE IF NOT EXISTS UserMeta( 24 | UserID VARCHAR(36) NOT NULL PRIMARY KEY, 25 | InitialUsername VARCHAR(20) NOT NULL, 26 | Username VARCHAR(20) NOT NULL, 27 | Deactivated BOOLEAN DEFAULT FALSE 28 | ) -------------------------------------------------------------------------------- /src/migrations/20210821133942_create_players_table.down.sql: -------------------------------------------------------------------------------- 1 | /* 2 | * This file is part of Refractor. 3 | * 4 | * Refractor is free software: you can redistribute it and/or modify 5 | * it under the terms of the GNU General Public License as published by 6 | * the Free Software Foundation, either version 3 of the License, or 7 | * (at your option) any later version. 8 | * 9 | * This program is distributed in the hope that it will be useful, 10 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 11 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 | * GNU General Public License for more details. 13 | * 14 | * You should have received a copy of the GNU General Public License 15 | * along with this program. If not, see . 16 | */ 17 | 18 | DROP TABLE IF EXISTS Players; -------------------------------------------------------------------------------- /src/migrations/20210821133942_create_players_table.up.sql: -------------------------------------------------------------------------------- 1 | /* 2 | * This file is part of Refractor. 3 | * 4 | * Refractor is free software: you can redistribute it and/or modify 5 | * it under the terms of the GNU General Public License as published by 6 | * the Free Software Foundation, either version 3 of the License, or 7 | * (at your option) any later version. 8 | * 9 | * This program is distributed in the hope that it will be useful, 10 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 11 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 | * GNU General Public License for more details. 13 | * 14 | * You should have received a copy of the GNU General Public License 15 | * along with this program. If not, see . 16 | */ 17 | 18 | CREATE TABLE IF NOT EXISTS Players( 19 | PlayerID VARCHAR(80) NOT NULL, 20 | Platform VARCHAR(128) NOT NULL, 21 | Watched BOOLEAN DEFAULT FALSE, 22 | LastSeen TIMESTAMP DEFAULT CURRENT_TIMESTAMP, 23 | CreatedAt TIMESTAMP DEFAULT CURRENT_TIMESTAMP, 24 | ModifiedAt TIMESTAMP, 25 | 26 | PRIMARY KEY (PlayerID, Platform) 27 | ); 28 | 29 | DROP TRIGGER IF EXISTS update_players_modat ON Players; 30 | CREATE TRIGGER update_players_modat BEFORE UPDATE ON Players 31 | FOR EACH ROW EXECUTE PROCEDURE update_modified_at_column(); -------------------------------------------------------------------------------- /src/migrations/20210821135938_create_playernames_table.down.sql: -------------------------------------------------------------------------------- 1 | /* 2 | * This file is part of Refractor. 3 | * 4 | * Refractor is free software: you can redistribute it and/or modify 5 | * it under the terms of the GNU General Public License as published by 6 | * the Free Software Foundation, either version 3 of the License, or 7 | * (at your option) any later version. 8 | * 9 | * This program is distributed in the hope that it will be useful, 10 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 11 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 | * GNU General Public License for more details. 13 | * 14 | * You should have received a copy of the GNU General Public License 15 | * along with this program. If not, see . 16 | */ 17 | 18 | DROP TABLE IF EXISTS PlayerNames; -------------------------------------------------------------------------------- /src/migrations/20210821135938_create_playernames_table.up.sql: -------------------------------------------------------------------------------- 1 | /* 2 | * This file is part of Refractor. 3 | * 4 | * Refractor is free software: you can redistribute it and/or modify 5 | * it under the terms of the GNU General Public License as published by 6 | * the Free Software Foundation, either version 3 of the License, or 7 | * (at your option) any later version. 8 | * 9 | * This program is distributed in the hope that it will be useful, 10 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 11 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 | * GNU General Public License for more details. 13 | * 14 | * You should have received a copy of the GNU General Public License 15 | * along with this program. If not, see . 16 | */ 17 | 18 | CREATE TABLE IF NOT EXISTS PlayerNames( 19 | PlayerID VARCHAR(80) NOT NULL, 20 | Platform VARCHAR(128) NOT NULL, 21 | Name VARCHAR(128) NOT NULL, 22 | DateRecorded TIMESTAMP NOT NULL, 23 | 24 | PRIMARY KEY (PlayerID, Platform, Name) 25 | ); -------------------------------------------------------------------------------- /src/migrations/20210830202202_create_infractions_table.down.sql: -------------------------------------------------------------------------------- 1 | /* 2 | * This file is part of Refractor. 3 | * 4 | * Refractor is free software: you can redistribute it and/or modify 5 | * it under the terms of the GNU General Public License as published by 6 | * the Free Software Foundation, either version 3 of the License, or 7 | * (at your option) any later version. 8 | * 9 | * This program is distributed in the hope that it will be useful, 10 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 11 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 | * GNU General Public License for more details. 13 | * 14 | * You should have received a copy of the GNU General Public License 15 | * along with this program. If not, see . 16 | */ 17 | 18 | DROP TABLE IF EXISTS Infractions; -------------------------------------------------------------------------------- /src/migrations/20210830202202_create_infractions_table.up.sql: -------------------------------------------------------------------------------- 1 | /* 2 | * This file is part of Refractor. 3 | * 4 | * Refractor is free software: you can redistribute it and/or modify 5 | * it under the terms of the GNU General Public License as published by 6 | * the Free Software Foundation, either version 3 of the License, or 7 | * (at your option) any later version. 8 | * 9 | * This program is distributed in the hope that it will be useful, 10 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 11 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 | * GNU General Public License for more details. 13 | * 14 | * You should have received a copy of the GNU General Public License 15 | * along with this program. If not, see . 16 | */ 17 | 18 | DO $$ BEGIN 19 | CREATE TYPE InfractionType AS ENUM ('WARNING', 'MUTE', 'KICK', 'BAN'); 20 | EXCEPTION 21 | WHEN duplicate_object THEN null; 22 | END $$; 23 | 24 | CREATE TABLE IF NOT EXISTS Infractions( 25 | InfractionID SERIAL NOT NULL PRIMARY KEY, 26 | PlayerID VARCHAR(80) NOT NULL, 27 | Platform VARCHAR(128) NOT NULL, 28 | UserID VARCHAR(36), 29 | ServerID SERIAL NOT NULL, 30 | Type InfractionType NOT NULL, 31 | Reason TEXT NOT NULL DEFAULT '', 32 | Duration INT, 33 | SystemAction BOOLEAN DEFAULT FALSE, 34 | CreatedAt TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP, 35 | ModifiedAt TIMESTAMP, 36 | 37 | FOREIGN KEY (PlayerID, Platform) REFERENCES Players (PlayerID, Platform), 38 | FOREIGN KEY (ServerID) References Servers (ServerID) 39 | ); 40 | 41 | DROP TRIGGER IF EXISTS update_infractions_modat ON Infractions; 42 | CREATE TRIGGER update_infractions_modat BEFORE UPDATE ON Infractions 43 | FOR EACH ROW EXECUTE PROCEDURE update_modified_at_column(); -------------------------------------------------------------------------------- /src/migrations/20210908163101_create_attachments_table.down.sql: -------------------------------------------------------------------------------- 1 | /* 2 | * This file is part of Refractor. 3 | * 4 | * Refractor is free software: you can redistribute it and/or modify 5 | * it under the terms of the GNU General Public License as published by 6 | * the Free Software Foundation, either version 3 of the License, or 7 | * (at your option) any later version. 8 | * 9 | * This program is distributed in the hope that it will be useful, 10 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 11 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 | * GNU General Public License for more details. 13 | * 14 | * You should have received a copy of the GNU General Public License 15 | * along with this program. If not, see . 16 | */ 17 | 18 | DROP TABLE IF EXISTS Attachments; -------------------------------------------------------------------------------- /src/migrations/20210908163101_create_attachments_table.up.sql: -------------------------------------------------------------------------------- 1 | /* 2 | * This file is part of Refractor. 3 | * 4 | * Refractor is free software: you can redistribute it and/or modify 5 | * it under the terms of the GNU General Public License as published by 6 | * the Free Software Foundation, either version 3 of the License, or 7 | * (at your option) any later version. 8 | * 9 | * This program is distributed in the hope that it will be useful, 10 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 11 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 | * GNU General Public License for more details. 13 | * 14 | * You should have received a copy of the GNU General Public License 15 | * along with this program. If not, see . 16 | */ 17 | 18 | CREATE TABLE IF NOT EXISTS Attachments( 19 | AttachmentID SERIAL NOT NULL PRIMARY KEY, 20 | InfractionID SERIAL NOT NULL, 21 | URL VARCHAR(512) NOT NULL, 22 | Note TEXT DEFAULT '', 23 | 24 | FOREIGN KEY (InfractionID) REFERENCES Infractions (InfractionID) ON DELETE CASCADE 25 | ) -------------------------------------------------------------------------------- /src/migrations/20210915174147_search_player_by_name_func.down.sql: -------------------------------------------------------------------------------- 1 | /* 2 | * This file is part of Refractor. 3 | * 4 | * Refractor is free software: you can redistribute it and/or modify 5 | * it under the terms of the GNU General Public License as published by 6 | * the Free Software Foundation, either version 3 of the License, or 7 | * (at your option) any later version. 8 | * 9 | * This program is distributed in the hope that it will be useful, 10 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 11 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 | * GNU General Public License for more details. 13 | * 14 | * You should have received a copy of the GNU General Public License 15 | * along with this program. If not, see . 16 | */ 17 | 18 | DROP TYPE playerNameSearchResult; 19 | 20 | DROP FUNCTION IF EXISTS search_player_names(VARCHAR, INT, INT); -------------------------------------------------------------------------------- /src/migrations/20210915174147_search_player_by_name_func.up.sql: -------------------------------------------------------------------------------- 1 | /* 2 | * This file is part of Refractor. 3 | * 4 | * Refractor is free software: you can redistribute it and/or modify 5 | * it under the terms of the GNU General Public License as published by 6 | * the Free Software Foundation, either version 3 of the License, or 7 | * (at your option) any later version. 8 | * 9 | * This program is distributed in the hope that it will be useful, 10 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 11 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 | * GNU General Public License for more details. 13 | * 14 | * You should have received a copy of the GNU General Public License 15 | * along with this program. If not, see . 16 | */ 17 | 18 | DO $$ BEGIN 19 | CREATE TYPE playerNameSearchResult AS ( 20 | PlayerID varchar(80), 21 | Platform varchar(128), 22 | LastSeen timestamp, 23 | Name varchar(128) 24 | ); 25 | EXCEPTION 26 | WHEN duplicate_object THEN null; 27 | END $$; 28 | 29 | create or replace function search_player_names(term varchar, limt int, offst int) 30 | returns table ( 31 | playerid varchar, 32 | platform varchar, 33 | lastseen timestamp, 34 | playername varchar 35 | ) language plpgsql as $$ 36 | declare looprow playerNameSearchResult; 37 | declare tmp playerNameSearchResult; 38 | begin 39 | for looprow in select pn.playerid, pn.platform from playernames pn 40 | where lower(name) like concat('%', lower(term), '%') 41 | group by pn.playerid, pn.platform 42 | limit limt offset offst 43 | loop 44 | select p.playerid, p.platform, p.lastseen, pn.name into tmp from playernames pn 45 | inner join players p on p.playerid = pn.playerid and p.platform = pn.platform 46 | where pn.playerid = looprow.playerid 47 | and pn.platform = looprow.platform 48 | order by daterecorded desc 49 | limit 1; 50 | 51 | playerid := tmp.playerid; 52 | platform := tmp.platform; 53 | lastseen := tmp.lastseen; 54 | playername := tmp.name; 55 | 56 | return next; 57 | end loop; 58 | end; $$; -------------------------------------------------------------------------------- /src/migrations/20210926161615_create_chatmessages_table.down.sql: -------------------------------------------------------------------------------- 1 | /* 2 | * This file is part of Refractor. 3 | * 4 | * Refractor is free software: you can redistribute it and/or modify 5 | * it under the terms of the GNU General Public License as published by 6 | * the Free Software Foundation, either version 3 of the License, or 7 | * (at your option) any later version. 8 | * 9 | * This program is distributed in the hope that it will be useful, 10 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 11 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 | * GNU General Public License for more details. 13 | * 14 | * You should have received a copy of the GNU General Public License 15 | * along with this program. If not, see . 16 | */ 17 | 18 | DROP TABLE IF EXISTS ChatMessages; 19 | DROP TRIGGER IF EXISTS update_chatmessages_modat ON ChatMessages; -------------------------------------------------------------------------------- /src/migrations/20210926161615_create_chatmessages_table.up.sql: -------------------------------------------------------------------------------- 1 | /* 2 | * This file is part of Refractor. 3 | * 4 | * Refractor is free software: you can redistribute it and/or modify 5 | * it under the terms of the GNU General Public License as published by 6 | * the Free Software Foundation, either version 3 of the License, or 7 | * (at your option) any later version. 8 | * 9 | * This program is distributed in the hope that it will be useful, 10 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 11 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 | * GNU General Public License for more details. 13 | * 14 | * You should have received a copy of the GNU General Public License 15 | * along with this program. If not, see . 16 | */ 17 | 18 | CREATE TABLE IF NOT EXISTS ChatMessages ( 19 | MessageID SERIAL NOT NULL PRIMARY KEY, 20 | PlayerID VARCHAR(80) NOT NULL, 21 | Platform VARCHAR(128) NOT NULL, 22 | ServerID SERIAL NOT NULL, 23 | Message TEXT NOT NULL, 24 | Flagged BOOLEAN DEFAULT FALSE, 25 | CreatedAt TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP, 26 | ModifiedAt TIMESTAMP, 27 | 28 | FOREIGN KEY (PlayerID, Platform) REFERENCES Players (PlayerID, Platform), 29 | FOREIGN KEY (ServerID) REFERENCES Servers (ServerID) 30 | ); 31 | 32 | DROP TRIGGER IF EXISTS update_chatmessages_modat ON ChatMessages; 33 | CREATE TRIGGER update_chatmessages_modat BEFORE UPDATE ON ChatMessages 34 | FOR EACH ROW EXECUTE PROCEDURE update_modified_at_column(); -------------------------------------------------------------------------------- /src/migrations/20210929185052_chatmessages_search_setup.down.sql: -------------------------------------------------------------------------------- 1 | /* 2 | * This file is part of Refractor. 3 | * 4 | * Refractor is free software: you can redistribute it and/or modify 5 | * it under the terms of the GNU General Public License as published by 6 | * the Free Software Foundation, either version 3 of the License, or 7 | * (at your option) any later version. 8 | * 9 | * This program is distributed in the hope that it will be useful, 10 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 11 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 | * GNU General Public License for more details. 13 | * 14 | * You should have received a copy of the GNU General Public License 15 | * along with this program. If not, see . 16 | */ 17 | 18 | alter table ChatMessages drop MessageVectors; 19 | 20 | drop function if exists update_chatmessage_vectors(); 21 | 22 | drop trigger if exists update_chatmessages_msgvecs on ChatMessages; -------------------------------------------------------------------------------- /src/migrations/20210929185052_chatmessages_search_setup.up.sql: -------------------------------------------------------------------------------- 1 | /* 2 | * This file is part of Refractor. 3 | * 4 | * Refractor is free software: you can redistribute it and/or modify 5 | * it under the terms of the GNU General Public License as published by 6 | * the Free Software Foundation, either version 3 of the License, or 7 | * (at your option) any later version. 8 | * 9 | * This program is distributed in the hope that it will be useful, 10 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 11 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 | * GNU General Public License for more details. 13 | * 14 | * You should have received a copy of the GNU General Public License 15 | * along with this program. If not, see . 16 | */ 17 | 18 | alter table ChatMessages add column if not exists MessageVectors tsvector; 19 | create index if not exists idx_search_message_vectors on ChatMessages using gin(MessageVectors); 20 | update ChatMessages set MessageVectors = to_tsvector(Message); 21 | 22 | create or replace function update_chatmessage_vectors() 23 | returns trigger as $$ 24 | begin 25 | new.MessageVectors = to_tsvector(new.Message); 26 | return new; 27 | end; 28 | $$ language 'plpgsql'; 29 | 30 | drop trigger if exists update_chatmessages_msgvecs on ChatMessages; 31 | create trigger update_chatmessages_msgvecs before update of Message on ChatMessages 32 | for each row execute procedure update_chatmessage_vectors(); -------------------------------------------------------------------------------- /src/migrations/20211003133238_create_flaggedwords_table.down.sql: -------------------------------------------------------------------------------- 1 | /* 2 | * This file is part of Refractor. 3 | * 4 | * Refractor is free software: you can redistribute it and/or modify 5 | * it under the terms of the GNU General Public License as published by 6 | * the Free Software Foundation, either version 3 of the License, or 7 | * (at your option) any later version. 8 | * 9 | * This program is distributed in the hope that it will be useful, 10 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 11 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 | * GNU General Public License for more details. 13 | * 14 | * You should have received a copy of the GNU General Public License 15 | * along with this program. If not, see . 16 | */ 17 | 18 | DROP TABLE IF EXISTS FlaggedWords; -------------------------------------------------------------------------------- /src/migrations/20211003133238_create_flaggedwords_table.up.sql: -------------------------------------------------------------------------------- 1 | /* 2 | * This file is part of Refractor. 3 | * 4 | * Refractor is free software: you can redistribute it and/or modify 5 | * it under the terms of the GNU General Public License as published by 6 | * the Free Software Foundation, either version 3 of the License, or 7 | * (at your option) any later version. 8 | * 9 | * This program is distributed in the hope that it will be useful, 10 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 11 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 | * GNU General Public License for more details. 13 | * 14 | * You should have received a copy of the GNU General Public License 15 | * along with this program. If not, see . 16 | */ 17 | 18 | CREATE TABLE IF NOT EXISTS FlaggedWords ( 19 | WordID SERIAL NOT NULL PRIMARY KEY, 20 | Word VARCHAR(128) NOT NULL 21 | ) -------------------------------------------------------------------------------- /src/migrations/20211011132959_create_infractionchatmessages_table.down.sql: -------------------------------------------------------------------------------- 1 | /* 2 | * This file is part of Refractor. 3 | * 4 | * Refractor is free software: you can redistribute it and/or modify 5 | * it under the terms of the GNU General Public License as published by 6 | * the Free Software Foundation, either version 3 of the License, or 7 | * (at your option) any later version. 8 | * 9 | * This program is distributed in the hope that it will be useful, 10 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 11 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 | * GNU General Public License for more details. 13 | * 14 | * You should have received a copy of the GNU General Public License 15 | * along with this program. If not, see . 16 | */ 17 | 18 | DROP TABLE IF EXISTS InfractionChatMessages; -------------------------------------------------------------------------------- /src/migrations/20211011132959_create_infractionchatmessages_table.up.sql: -------------------------------------------------------------------------------- 1 | /* 2 | * This file is part of Refractor. 3 | * 4 | * Refractor is free software: you can redistribute it and/or modify 5 | * it under the terms of the GNU General Public License as published by 6 | * the Free Software Foundation, either version 3 of the License, or 7 | * (at your option) any later version. 8 | * 9 | * This program is distributed in the hope that it will be useful, 10 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 11 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 | * GNU General Public License for more details. 13 | * 14 | * You should have received a copy of the GNU General Public License 15 | * along with this program. If not, see . 16 | */ 17 | 18 | CREATE TABLE IF NOT EXISTS InfractionChatMessages ( 19 | InfractionID SERIAL NOT NULL, 20 | MessageID SERIAL NOT NULL, 21 | 22 | FOREIGN KEY (InfractionID) REFERENCES Infractions (InfractionID) ON DELETE CASCADE, 23 | FOREIGN KEY (MessageID) REFERENCES ChatMessages (MessageID) ON DELETE CASCADE 24 | ) -------------------------------------------------------------------------------- /src/migrations/20211015125247_create_userplayers_table.down.sql: -------------------------------------------------------------------------------- 1 | /* 2 | * This file is part of Refractor. 3 | * 4 | * Refractor is free software: you can redistribute it and/or modify 5 | * it under the terms of the GNU General Public License as published by 6 | * the Free Software Foundation, either version 3 of the License, or 7 | * (at your option) any later version. 8 | * 9 | * This program is distributed in the hope that it will be useful, 10 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 11 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 | * GNU General Public License for more details. 13 | * 14 | * You should have received a copy of the GNU General Public License 15 | * along with this program. If not, see . 16 | */ 17 | 18 | DROP TABLE IF EXISTS UserPlayers; -------------------------------------------------------------------------------- /src/migrations/20211015125247_create_userplayers_table.up.sql: -------------------------------------------------------------------------------- 1 | /* 2 | * This file is part of Refractor. 3 | * 4 | * Refractor is free software: you can redistribute it and/or modify 5 | * it under the terms of the GNU General Public License as published by 6 | * the Free Software Foundation, either version 3 of the License, or 7 | * (at your option) any later version. 8 | * 9 | * This program is distributed in the hope that it will be useful, 10 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 11 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 | * GNU General Public License for more details. 13 | * 14 | * You should have received a copy of the GNU General Public License 15 | * along with this program. If not, see . 16 | */ 17 | 18 | CREATE TABLE IF NOT EXISTS UserPlayers( 19 | UserID VARCHAR(36) NOT NULL, 20 | Platform VARCHAR(128) NOT NULL, 21 | PlayerID VARCHAR(80) NOT NULL, 22 | 23 | PRIMARY KEY (Platform, PlayerID) 24 | ) -------------------------------------------------------------------------------- /src/migrations/20211017134801_infraction_repeal_setup.down.sql: -------------------------------------------------------------------------------- 1 | /* 2 | * This file is part of Refractor. 3 | * 4 | * Refractor is free software: you can redistribute it and/or modify 5 | * it under the terms of the GNU General Public License as published by 6 | * the Free Software Foundation, either version 3 of the License, or 7 | * (at your option) any later version. 8 | * 9 | * This program is distributed in the hope that it will be useful, 10 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 11 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 | * GNU General Public License for more details. 13 | * 14 | * You should have received a copy of the GNU General Public License 15 | * along with this program. If not, see . 16 | */ 17 | 18 | alter table Infractions drop column if exists Repealed; -------------------------------------------------------------------------------- /src/migrations/20211017134801_infraction_repeal_setup.up.sql: -------------------------------------------------------------------------------- 1 | /* 2 | * This file is part of Refractor. 3 | * 4 | * Refractor is free software: you can redistribute it and/or modify 5 | * it under the terms of the GNU General Public License as published by 6 | * the Free Software Foundation, either version 3 of the License, or 7 | * (at your option) any later version. 8 | * 9 | * This program is distributed in the hope that it will be useful, 10 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 11 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 | * GNU General Public License for more details. 13 | * 14 | * You should have received a copy of the GNU General Public License 15 | * along with this program. If not, see . 16 | */ 17 | 18 | alter table Infractions add column if not exists Repealed boolean not null default false; -------------------------------------------------------------------------------- /src/migrations/20211018175905_install_systemtables_extension.down.sql: -------------------------------------------------------------------------------- 1 | /* 2 | * This file is part of Refractor. 3 | * 4 | * Refractor is free software: you can redistribute it and/or modify 5 | * it under the terms of the GNU General Public License as published by 6 | * the Free Software Foundation, either version 3 of the License, or 7 | * (at your option) any later version. 8 | * 9 | * This program is distributed in the hope that it will be useful, 10 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 11 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 | * GNU General Public License for more details. 13 | * 14 | * You should have received a copy of the GNU General Public License 15 | * along with this program. If not, see . 16 | */ 17 | 18 | DROP EXTENSION IF EXISTS tsm_system_rows; -------------------------------------------------------------------------------- /src/migrations/20211018175905_install_systemtables_extension.up.sql: -------------------------------------------------------------------------------- 1 | /* 2 | * This file is part of Refractor. 3 | * 4 | * Refractor is free software: you can redistribute it and/or modify 5 | * it under the terms of the GNU General Public License as published by 6 | * the Free Software Foundation, either version 3 of the License, or 7 | * (at your option) any later version. 8 | * 9 | * This program is distributed in the hope that it will be useful, 10 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 11 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 | * GNU General Public License for more details. 13 | * 14 | * You should have received a copy of the GNU General Public License 15 | * along with this program. If not, see . 16 | */ 17 | 18 | CREATE EXTENSION IF NOT EXISTS tsm_system_rows; -------------------------------------------------------------------------------- /src/migrations/20211114003439_adjust_permanent_infraction_durations.down.sql: -------------------------------------------------------------------------------- 1 | /* 2 | * This file is part of Refractor. 3 | * 4 | * Refractor is free software: you can redistribute it and/or modify 5 | * it under the terms of the GNU General Public License as published by 6 | * the Free Software Foundation, either version 3 of the License, or 7 | * (at your option) any later version. 8 | * 9 | * This program is distributed in the hope that it will be useful, 10 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 11 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 | * GNU General Public License for more details. 13 | * 14 | * You should have received a copy of the GNU General Public License 15 | * along with this program. If not, see . 16 | */ 17 | 18 | UPDATE Infractions SET Duration = 0 WHERE Duration = -1; -------------------------------------------------------------------------------- /src/migrations/20211114003439_adjust_permanent_infraction_durations.up.sql: -------------------------------------------------------------------------------- 1 | /* 2 | * This file is part of Refractor. 3 | * 4 | * Refractor is free software: you can redistribute it and/or modify 5 | * it under the terms of the GNU General Public License as published by 6 | * the Free Software Foundation, either version 3 of the License, or 7 | * (at your option) any later version. 8 | * 9 | * This program is distributed in the hope that it will be useful, 10 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 11 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 | * GNU General Public License for more details. 13 | * 14 | * You should have received a copy of the GNU General Public License 15 | * along with this program. If not, see . 16 | */ 17 | 18 | UPDATE Infractions SET Duration = -1 WHERE Duration = 0; -------------------------------------------------------------------------------- /src/params/attachment.go: -------------------------------------------------------------------------------- 1 | /* 2 | * This file is part of Refractor. 3 | * 4 | * Refractor is free software: you can redistribute it and/or modify 5 | * it under the terms of the GNU General Public License as published by 6 | * the Free Software Foundation, either version 3 of the License, or 7 | * (at your option) any later version. 8 | * 9 | * This program is distributed in the hope that it will be useful, 10 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 11 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 | * GNU General Public License for more details. 13 | * 14 | * You should have received a copy of the GNU General Public License 15 | * along with this program. If not, see . 16 | */ 17 | 18 | package params 19 | 20 | import ( 21 | "Refractor/params/rules" 22 | validation "github.com/go-ozzo/ozzo-validation" 23 | ) 24 | 25 | type CreateAttachmentParams struct { 26 | URL string `json:"url" form:"url"` 27 | Note string `json:"note" form:"note"` 28 | } 29 | 30 | func (body CreateAttachmentParams) Validate() error { 31 | return ValidateStruct(&body, 32 | validation.Field(&body.URL, rules.AttachmentURLRules.Prepend(validation.Required)...), 33 | validation.Field(&body.Note, rules.AttachmentNoteRules...), 34 | ) 35 | } 36 | -------------------------------------------------------------------------------- /src/params/flagged_word.go: -------------------------------------------------------------------------------- 1 | /* 2 | * This file is part of Refractor. 3 | * 4 | * Refractor is free software: you can redistribute it and/or modify 5 | * it under the terms of the GNU General Public License as published by 6 | * the Free Software Foundation, either version 3 of the License, or 7 | * (at your option) any later version. 8 | * 9 | * This program is distributed in the hope that it will be useful, 10 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 11 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 | * GNU General Public License for more details. 13 | * 14 | * You should have received a copy of the GNU General Public License 15 | * along with this program. If not, see . 16 | */ 17 | 18 | package params 19 | 20 | import ( 21 | validation "github.com/go-ozzo/ozzo-validation" 22 | ) 23 | 24 | type CreateFlaggedWordParams struct { 25 | Word string `json:"word"` 26 | } 27 | 28 | func (body CreateFlaggedWordParams) Validate() error { 29 | return ValidateStruct(&body, 30 | validation.Field(&body.Word, validation.Required, validation.Length(1, 100))) 31 | } 32 | 33 | type UpdateFlaggedWordParams struct { 34 | Word *string `json:"word"` 35 | } 36 | 37 | func (body UpdateFlaggedWordParams) Validate() error { 38 | return ValidateStruct(&body, 39 | validation.Field(&body.Word, validation.Length(1, 100))) 40 | } 41 | -------------------------------------------------------------------------------- /src/params/helpers.go: -------------------------------------------------------------------------------- 1 | /* 2 | * This file is part of Refractor. 3 | * 4 | * Refractor is free software: you can redistribute it and/or modify 5 | * it under the terms of the GNU General Public License as published by 6 | * the Free Software Foundation, either version 3 of the License, or 7 | * (at your option) any later version. 8 | * 9 | * This program is distributed in the hope that it will be useful, 10 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 11 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 | * GNU General Public License for more details. 13 | * 14 | * You should have received a copy of the GNU General Public License 15 | * along with this program. If not, see . 16 | */ 17 | 18 | package params 19 | 20 | import validation "github.com/go-ozzo/ozzo-validation" 21 | 22 | // appendRules takes in a slice of validation.Rule, copies it, appends the extra rules provided **to the beginning** of 23 | // the slice and then returns the result. The original slice is not modified. 24 | func appendRules(rules []validation.Rule, extras ...validation.Rule) []validation.Rule { 25 | tmp := make([]validation.Rule, len(rules), len(rules)+len(extras)) 26 | copy(tmp, rules) 27 | return append(extras, tmp...) 28 | } 29 | -------------------------------------------------------------------------------- /src/params/rules/rulegroup.go: -------------------------------------------------------------------------------- 1 | /* 2 | * This file is part of Refractor. 3 | * 4 | * Refractor is free software: you can redistribute it and/or modify 5 | * it under the terms of the GNU General Public License as published by 6 | * the Free Software Foundation, either version 3 of the License, or 7 | * (at your option) any later version. 8 | * 9 | * This program is distributed in the hope that it will be useful, 10 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 11 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 | * GNU General Public License for more details. 13 | * 14 | * You should have received a copy of the GNU General Public License 15 | * along with this program. If not, see . 16 | */ 17 | 18 | package rules 19 | 20 | import ( 21 | validation "github.com/go-ozzo/ozzo-validation" 22 | ) 23 | 24 | type RuleGroup []validation.Rule 25 | 26 | // Prepend adds additional rules to the start of the RuleGroup. It does not modify the original, it simply returns a 27 | // copy with the additional rules prepended. 28 | func (rg RuleGroup) Prepend(rules ...validation.Rule) RuleGroup { 29 | tmp := make([]validation.Rule, len(rules), len(rules)+len(rg)) 30 | copy(tmp, rules) 31 | return append(tmp, rg...) 32 | } 33 | 34 | // Append adds additional rules to the end of the RuleGroup. It does not modify the original, it simply returns a 35 | // copy with the additional rules appended. 36 | func (rg RuleGroup) Append(rules ...validation.Rule) RuleGroup { 37 | tmp := make([]validation.Rule, len(rg), len(rg)+len(rules)) 38 | copy(tmp, rg) 39 | return append(tmp, rules...) 40 | } 41 | -------------------------------------------------------------------------------- /src/params/rules/rules.go: -------------------------------------------------------------------------------- 1 | /* 2 | * This file is part of Refractor. 3 | * 4 | * Refractor is free software: you can redistribute it and/or modify 5 | * it under the terms of the GNU General Public License as published by 6 | * the Free Software Foundation, either version 3 of the License, or 7 | * (at your option) any later version. 8 | * 9 | * This program is distributed in the hope that it will be useful, 10 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 11 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 | * GNU General Public License for more details. 13 | * 14 | * You should have received a copy of the GNU General Public License 15 | * along with this program. If not, see . 16 | */ 17 | 18 | package rules 19 | 20 | import ( 21 | "Refractor/domain" 22 | "Refractor/params/validators" 23 | validation "github.com/go-ozzo/ozzo-validation" 24 | "github.com/go-ozzo/ozzo-validation/is" 25 | "math" 26 | "regexp" 27 | ) 28 | 29 | var PlatformRules = RuleGroup{ 30 | validation.Length(1, 128), 31 | validation.By(validators.ValueInStrArray(domain.AllPlatforms)), 32 | } 33 | 34 | var PlayerIDRules = RuleGroup{ 35 | validation.Length(1, 80), 36 | } 37 | 38 | var InfractionReasonRules = RuleGroup{ 39 | validation.Length(1, 1024), 40 | } 41 | 42 | var InfractionDurationRules = RuleGroup{ 43 | validation.Min(-1), 44 | validation.Max(math.MaxInt32), 45 | } 46 | 47 | var attachmentUrlPattern = regexp.MustCompile(".(jpeg|jpg|gif|png)$") 48 | var AttachmentURLRules = RuleGroup{ 49 | is.RequestURL, 50 | validation.Match(attachmentUrlPattern), 51 | } 52 | 53 | var AttachmentNoteRules = RuleGroup{ 54 | validation.Length(1, 512), 55 | } 56 | 57 | var SearchOffsetRules = RuleGroup{ 58 | validation.Min(0), 59 | validation.Max(math.MaxInt32), 60 | } 61 | 62 | var SearchLimitRules = RuleGroup{ 63 | validation.Min(0), 64 | validation.Max(100), 65 | } 66 | 67 | var UserIDRules = RuleGroup{ 68 | is.UUIDv4, 69 | } 70 | -------------------------------------------------------------------------------- /src/params/server.go: -------------------------------------------------------------------------------- 1 | /* 2 | * This file is part of Refractor. 3 | * 4 | * Refractor is free software: you can redistribute it and/or modify 5 | * it under the terms of the GNU General Public License as published by 6 | * the Free Software Foundation, either version 3 of the License, or 7 | * (at your option) any later version. 8 | * 9 | * This program is distributed in the hope that it will be useful, 10 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 11 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 | * GNU General Public License for more details. 13 | * 14 | * You should have received a copy of the GNU General Public License 15 | * along with this program. If not, see . 16 | */ 17 | 18 | package params 19 | 20 | import ( 21 | validation "github.com/go-ozzo/ozzo-validation" 22 | "github.com/go-ozzo/ozzo-validation/is" 23 | "strings" 24 | ) 25 | 26 | type CreateServerParams struct { 27 | Game string `form:"game" json:"game"` 28 | Name string `form:"name" json:"name"` 29 | Address string `form:"address" json:"address"` 30 | RCONPort string `form:"rcon_port" json:"rcon_port"` 31 | RCONPassword string `form:"rcon_password" json:"rcon_password"` 32 | } 33 | 34 | func (body CreateServerParams) Validate() error { 35 | body.Game = strings.TrimSpace(body.Game) 36 | body.Name = strings.TrimSpace(body.Name) 37 | body.Address = strings.TrimSpace(body.Address) 38 | body.RCONPort = strings.TrimSpace(body.RCONPort) 39 | body.RCONPassword = strings.TrimSpace(body.RCONPassword) 40 | 41 | return ValidateStruct(&body, 42 | validation.Field(&body.Game, validation.Required, validation.Length(1, 32)), 43 | validation.Field(&body.Name, validation.Required, validation.Length(1, 20)), 44 | validation.Field(&body.Address, validation.Required, is.IPv4), 45 | validation.Field(&body.RCONPort, validation.Required, is.Port), 46 | validation.Field(&body.RCONPassword, validation.Required, validation.Length(1, 128)), 47 | ) 48 | } 49 | 50 | type UpdateServerParams struct { 51 | Game *string `json:"game" form:"game"` 52 | Name *string `json:"name" form:"name"` 53 | Address *string `json:"address" form:"address"` 54 | RCONPort *string `json:"rcon_port" form:"rcon_port"` 55 | RCONPassword *string `json:"rcon_password" form:"rcon_password"` 56 | } 57 | 58 | func (body UpdateServerParams) Validate() error { 59 | return ValidateStruct(&body, 60 | validation.Field(&body.Game, validation.By(stringPointerNotEmpty), validation.Length(1, 32)), 61 | validation.Field(&body.Name, validation.By(stringPointerNotEmpty), validation.Length(1, 20)), 62 | validation.Field(&body.Address, validation.By(stringPointerNotEmpty), is.IPv4), 63 | validation.Field(&body.RCONPort, validation.By(stringPointerNotEmpty), is.Port), 64 | validation.Field(&body.RCONPassword, validation.By(stringPointerNotEmpty), validation.Length(1, 128)), 65 | ) 66 | } 67 | -------------------------------------------------------------------------------- /src/params/user.go: -------------------------------------------------------------------------------- 1 | /* 2 | * This file is part of Refractor. 3 | * 4 | * Refractor is free software: you can redistribute it and/or modify 5 | * it under the terms of the GNU General Public License as published by 6 | * the Free Software Foundation, either version 3 of the License, or 7 | * (at your option) any later version. 8 | * 9 | * This program is distributed in the hope that it will be useful, 10 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 11 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 | * GNU General Public License for more details. 13 | * 14 | * You should have received a copy of the GNU General Public License 15 | * along with this program. If not, see . 16 | */ 17 | 18 | package params 19 | 20 | import ( 21 | "Refractor/params/rules" 22 | validation "github.com/go-ozzo/ozzo-validation" 23 | "github.com/go-ozzo/ozzo-validation/is" 24 | "strings" 25 | ) 26 | 27 | type CreateUserParams struct { 28 | Username string `json:"username" form:"username"` 29 | Email string `json:"email" form:"email"` 30 | } 31 | 32 | func (body CreateUserParams) Validate() error { 33 | body.Username = strings.TrimSpace(body.Username) 34 | body.Email = strings.TrimSpace(body.Email) 35 | 36 | return ValidateStruct(&body, 37 | validation.Field(&body.Username, validation.Required, validation.Length(1, 20)), 38 | validation.Field(&body.Email, validation.Required, is.Email), 39 | ) 40 | } 41 | 42 | type LinkPlayerParams struct { 43 | UserID string `json:"user_id" form:"user_id"` 44 | Platform string `json:"platform" form:"platform"` 45 | PlayerID string `json:"player_id" form:"player_id"` 46 | } 47 | 48 | func (body LinkPlayerParams) Validate() error { 49 | body.UserID = strings.TrimSpace(body.UserID) 50 | body.Platform = strings.TrimSpace(body.Platform) 51 | body.PlayerID = strings.TrimSpace(body.PlayerID) 52 | 53 | return ValidateStruct(&body, 54 | validation.Field(&body.UserID, rules.UserIDRules.Prepend(validation.Required)...), 55 | validation.Field(&body.Platform, rules.PlatformRules.Prepend(validation.Required)...), 56 | validation.Field(&body.PlayerID, rules.PlayerIDRules.Prepend(validation.Required)...)) 57 | } 58 | -------------------------------------------------------------------------------- /src/params/validator.go: -------------------------------------------------------------------------------- 1 | /* 2 | * This file is part of Refractor. 3 | * 4 | * Refractor is free software: you can redistribute it and/or modify 5 | * it under the terms of the GNU General Public License as published by 6 | * the Free Software Foundation, either version 3 of the License, or 7 | * (at your option) any later version. 8 | * 9 | * This program is distributed in the hope that it will be useful, 10 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 11 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 | * GNU General Public License for more details. 13 | * 14 | * You should have received a copy of the GNU General Public License 15 | * along with this program. If not, see . 16 | */ 17 | 18 | package params 19 | 20 | import ( 21 | "Refractor/domain" 22 | "encoding/json" 23 | "fmt" 24 | validation "github.com/go-ozzo/ozzo-validation" 25 | "net/http" 26 | "strings" 27 | ) 28 | 29 | // ValidateStruct is a wrapper function which calls the wrapError function around validation.ValidateStruct. 30 | func ValidateStruct(structPtr interface{}, fields ...*validation.FieldRules) error { 31 | return wrapError(validation.ValidateStruct(structPtr, fields...)) 32 | } 33 | 34 | func wrapError(err error) error { 35 | if err == nil { 36 | return err 37 | } 38 | 39 | // If err is already an http error, just return it 40 | if _, ok := err.(*domain.HTTPError); ok { 41 | return err 42 | } 43 | 44 | httpError := &domain.HTTPError{ 45 | Cause: domain.ErrInvalid, 46 | Message: "Input errors exist", 47 | Status: http.StatusBadRequest, 48 | } 49 | 50 | data, err := json.Marshal(err) 51 | if err != nil { 52 | return err 53 | } 54 | 55 | err = json.Unmarshal(data, &httpError.ValidationErrors) 56 | if err != nil { 57 | return err 58 | } 59 | 60 | return httpError 61 | } 62 | 63 | // stringPointerNotEmpty is a custom validation rule which first checks if the string pointer is nil. If it is, it does 64 | // not return an error since this is expected behaviour. If it's not nil, it checks if it's empty. If it isn't empty, it 65 | // does not return an error. If it is empty, it returns an error. 66 | func stringPointerNotEmpty(val interface{}) error { 67 | str, _ := val.(*string) 68 | 69 | if str == nil { 70 | return nil 71 | } 72 | 73 | if strings.TrimSpace(*str) == "" { 74 | return fmt.Errorf("cannot be an empty string") 75 | } 76 | 77 | return nil 78 | } 79 | -------------------------------------------------------------------------------- /src/params/validators/inArr.go: -------------------------------------------------------------------------------- 1 | /* 2 | * This file is part of Refractor. 3 | * 4 | * Refractor is free software: you can redistribute it and/or modify 5 | * it under the terms of the GNU General Public License as published by 6 | * the Free Software Foundation, either version 3 of the License, or 7 | * (at your option) any later version. 8 | * 9 | * This program is distributed in the hope that it will be useful, 10 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 11 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 | * GNU General Public License for more details. 13 | * 14 | * You should have received a copy of the GNU General Public License 15 | * along with this program. If not, see . 16 | */ 17 | 18 | package validators 19 | 20 | import ( 21 | "fmt" 22 | validation "github.com/go-ozzo/ozzo-validation" 23 | "github.com/pkg/errors" 24 | ) 25 | 26 | func ValueInStrArray(arr []string) validation.RuleFunc { 27 | return func(value interface{}) error { 28 | value, _ = value.(string) 29 | 30 | if value == "" { 31 | return nil 32 | } 33 | 34 | for _, val := range arr { 35 | if val == value { 36 | return nil 37 | } 38 | } 39 | 40 | return errors.New(fmt.Sprintf("must be one of: %v", arr)) 41 | } 42 | } 43 | 44 | func PtrValueInStrArray(arr []string) validation.RuleFunc { 45 | return func(value interface{}) error { 46 | strValPtr, _ := value.(*string) 47 | 48 | if strValPtr == nil { 49 | return nil 50 | } 51 | 52 | strVal := *strValPtr 53 | 54 | if strVal == "" { 55 | return nil 56 | } 57 | 58 | for _, val := range arr { 59 | if val == strVal { 60 | return nil 61 | } 62 | } 63 | 64 | return errors.New(fmt.Sprintf("must be one of: %v", arr)) 65 | } 66 | } 67 | -------------------------------------------------------------------------------- /src/pkg/aeshelper/aes.go: -------------------------------------------------------------------------------- 1 | /* 2 | * This file is part of Refractor. 3 | * 4 | * Refractor is free software: you can redistribute it and/or modify 5 | * it under the terms of the GNU General Public License as published by 6 | * the Free Software Foundation, either version 3 of the License, or 7 | * (at your option) any later version. 8 | * 9 | * This program is distributed in the hope that it will be useful, 10 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 11 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 | * GNU General Public License for more details. 13 | * 14 | * You should have received a copy of the GNU General Public License 15 | * along with this program. If not, see . 16 | */ 17 | 18 | package aeshelper 19 | 20 | import ( 21 | "crypto/aes" 22 | "crypto/cipher" 23 | "crypto/rand" 24 | "fmt" 25 | "io" 26 | ) 27 | 28 | func Encrypt(data []byte, key string) ([]byte, error) { 29 | // Generate a new AES cipher using our key 30 | c, err := aes.NewCipher([]byte(key)) 31 | if err != nil { 32 | return nil, err 33 | } 34 | 35 | // Use GCM (Galois/Counter Mode) for symetric encryption 36 | gcm, err := cipher.NewGCM(c) 37 | if err != nil { 38 | return nil, err 39 | } 40 | 41 | // Create the nonce 42 | nonce := make([]byte, gcm.NonceSize()) 43 | if _, err := io.ReadFull(rand.Reader, nonce); err != nil { 44 | return nil, err 45 | } 46 | 47 | // Encrypt the data 48 | return gcm.Seal(nonce, nonce, data, nil), nil 49 | } 50 | 51 | func Decrypt(data []byte, key string) ([]byte, error) { 52 | // Generate a new AES cipher using our key 53 | c, err := aes.NewCipher([]byte(key)) 54 | if err != nil { 55 | return nil, err 56 | } 57 | 58 | // Use GCM (Galois/Counter Mode) for symetric encryption 59 | gcm, err := cipher.NewGCM(c) 60 | if err != nil { 61 | return nil, err 62 | } 63 | 64 | // Check nonce 65 | nonceSize := gcm.NonceSize() 66 | if len(data) < nonceSize { 67 | return nil, fmt.Errorf("data length < nonce") 68 | } 69 | 70 | // Decrypt data 71 | nonce, data := data[:nonceSize], data[nonceSize:] 72 | decrypted, err := gcm.Open(nil, nonce, data, nil) 73 | if err != nil { 74 | return nil, err 75 | } 76 | 77 | return decrypted, nil 78 | } 79 | -------------------------------------------------------------------------------- /src/pkg/api/errorhandler.go: -------------------------------------------------------------------------------- 1 | /* 2 | * This file is part of Refractor. 3 | * 4 | * Refractor is free software: you can redistribute it and/or modify 5 | * it under the terms of the GNU General Public License as published by 6 | * the Free Software Foundation, either version 3 of the License, or 7 | * (at your option) any later version. 8 | * 9 | * This program is distributed in the hope that it will be useful, 10 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 11 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 | * GNU General Public License for more details. 13 | * 14 | * You should have received a copy of the GNU General Public License 15 | * along with this program. If not, see . 16 | */ 17 | 18 | package api 19 | 20 | import ( 21 | "Refractor/domain" 22 | "github.com/labstack/echo/v4" 23 | "github.com/pkg/errors" 24 | "go.uber.org/zap" 25 | "net/http" 26 | ) 27 | 28 | func GetEchoErrorHandler(logger *zap.Logger) echo.HTTPErrorHandler { 29 | return func(err error, c echo.Context) { 30 | // If this error is a custom http error, treat it as such 31 | if httpError, ok := err.(*domain.HTTPError); ok { 32 | body, err := httpError.ResponseBody() 33 | if err != nil { 34 | c.Logger().Error(err) 35 | return 36 | } 37 | 38 | code, _ := httpError.ResponseHeaders() 39 | 40 | err = c.JSONBlob(code, body) 41 | if err != nil { 42 | c.Logger().Error(err) 43 | return 44 | } 45 | } else if echoErr, ok := err.(*echo.HTTPError); ok { 46 | err := c.JSON(echoErr.Code, domain.Response{ 47 | Success: false, 48 | Message: echoErr.Message.(string), 49 | }) 50 | if err != nil { 51 | c.Logger().Error(err) 52 | return 53 | } 54 | return 55 | } else if errors.Cause(err) == domain.ErrNotFound { 56 | // If this error is domain.ErrNotFound, send back a generic 404 Not Found response message 57 | err := c.JSON(http.StatusNotFound, domain.Response{ 58 | Success: false, 59 | Message: "Not found", 60 | }) 61 | if err != nil { 62 | c.Logger().Error(err) 63 | return 64 | } 65 | return 66 | } else { 67 | // If this error is not a custom http error, assume it's an internal error. 68 | // We log it and then send back an internal server error message to the user. 69 | logger.Error("An error occurred", zap.Error(err)) 70 | 71 | type intErr struct { 72 | Message string `json:"message"` 73 | } 74 | 75 | err := c.JSON(http.StatusInternalServerError, intErr{Message: "Internal server error"}) 76 | if err != nil { 77 | c.Logger().Error(err) 78 | return 79 | } 80 | } 81 | } 82 | } 83 | -------------------------------------------------------------------------------- /src/pkg/api/permissions.go: -------------------------------------------------------------------------------- 1 | /* 2 | * This file is part of Refractor. 3 | * 4 | * Refractor is free software: you can redistribute it and/or modify 5 | * it under the terms of the GNU General Public License as published by 6 | * the Free Software Foundation, either version 3 of the License, or 7 | * (at your option) any later version. 8 | * 9 | * This program is distributed in the hope that it will be useful, 10 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 11 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 | * GNU General Public License for more details. 13 | * 14 | * You should have received a copy of the GNU General Public License 15 | * along with this program. If not, see . 16 | */ 17 | 18 | package api 19 | 20 | import ( 21 | "Refractor/domain" 22 | "Refractor/pkg/bitperms" 23 | "Refractor/pkg/perms" 24 | "context" 25 | ) 26 | 27 | // CheckPermissions is a wrapper function which provides automatic checking of if a user is a super admin. 28 | func CheckPermissions(ctx context.Context, a domain.Authorizer, scope domain.AuthScope, userID string, authChecker domain.AuthChecker) (bool, error) { 29 | hasPermission, err := a.HasPermission(ctx, scope, userID, func(permissions *bitperms.Permissions) (bool, error) { 30 | if permissions.CheckFlag(perms.GetFlag(perms.FlagSuperAdmin)) { 31 | return true, nil 32 | } 33 | 34 | return authChecker(permissions) 35 | }) 36 | if err != nil { 37 | return false, err 38 | } 39 | 40 | return hasPermission, nil 41 | } 42 | -------------------------------------------------------------------------------- /src/pkg/api/request.go: -------------------------------------------------------------------------------- 1 | /* 2 | * This file is part of Refractor. 3 | * 4 | * Refractor is free software: you can redistribute it and/or modify 5 | * it under the terms of the GNU General Public License as published by 6 | * the Free Software Foundation, either version 3 of the License, or 7 | * (at your option) any later version. 8 | * 9 | * This program is distributed in the hope that it will be useful, 10 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 11 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 | * GNU General Public License for more details. 13 | * 14 | * You should have received a copy of the GNU General Public License 15 | * along with this program. If not, see . 16 | */ 17 | 18 | package api 19 | 20 | import ( 21 | "Refractor/domain" 22 | ) 23 | 24 | func ValidateRequestBody(body domain.Validable) (bool, error) { 25 | err := body.Validate() 26 | if err != nil { 27 | return false, err 28 | } 29 | 30 | return true, nil 31 | } 32 | -------------------------------------------------------------------------------- /src/pkg/broadcast/broadcast.go: -------------------------------------------------------------------------------- 1 | /* 2 | * This file is part of Refractor. 3 | * 4 | * Refractor is free software: you can redistribute it and/or modify 5 | * it under the terms of the GNU General Public License as published by 6 | * the Free Software Foundation, either version 3 of the License, or 7 | * (at your option) any later version. 8 | * 9 | * This program is distributed in the hope that it will be useful, 10 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 11 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 | * GNU General Public License for more details. 13 | * 14 | * You should have received a copy of the GNU General Public License 15 | * along with this program. If not, see . 16 | */ 17 | 18 | package broadcast 19 | 20 | import ( 21 | "Refractor/pkg/regexutils" 22 | "regexp" 23 | ) 24 | 25 | type Fields map[string]string 26 | 27 | type Broadcast struct { 28 | Type string 29 | Fields Fields 30 | } 31 | 32 | const ( 33 | TypeJoin = "JOIN" 34 | TypeQuit = "QUIT" 35 | TypeChat = "CHAT" 36 | TypeMute = "MUTE" 37 | TypeKick = "KICK" 38 | TypeBan = "BAN" 39 | ) 40 | 41 | func GetBroadcastType(broadcast string, patterns map[string]*regexp.Regexp) *Broadcast { 42 | for bcastType, pattern := range patterns { 43 | if pattern.MatchString(broadcast) { 44 | namedMatches := regexutils.MapNamedMatches(pattern, broadcast) 45 | 46 | return &Broadcast{ 47 | Type: bcastType, 48 | Fields: namedMatches, 49 | } 50 | } 51 | } 52 | 53 | return nil 54 | } 55 | -------------------------------------------------------------------------------- /src/pkg/broadcast/broadcast_test.go: -------------------------------------------------------------------------------- 1 | /* 2 | * This file is part of Refractor. 3 | * 4 | * Refractor is free software: you can redistribute it and/or modify 5 | * it under the terms of the GNU General Public License as published by 6 | * the Free Software Foundation, either version 3 of the License, or 7 | * (at your option) any later version. 8 | * 9 | * This program is distributed in the hope that it will be useful, 10 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 11 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 | * GNU General Public License for more details. 13 | * 14 | * You should have received a copy of the GNU General Public License 15 | * along with this program. If not, see . 16 | */ 17 | 18 | package broadcast 19 | 20 | import ( 21 | "reflect" 22 | "regexp" 23 | "testing" 24 | ) 25 | 26 | var ( 27 | mordhauJoinPattern = regexp.MustCompile("^Login: (?P[0-9\\.-]+): (?P.+) \\((?P[0-9a-fA-F]+)\\) logged in$") 28 | mordhauQuitPattern = regexp.MustCompile("^Login: (?P[0-9\\.-]+): (?P.+) \\((?P[0-9a-fA-F]+)\\) logged out$") 29 | ) 30 | 31 | func TestGetBroadcastType(t *testing.T) { 32 | type args struct { 33 | broadcast string 34 | patterns map[string]*regexp.Regexp 35 | } 36 | tests := []struct { 37 | name string 38 | args args 39 | want *Broadcast 40 | }{ 41 | { 42 | name: "broadcast.gettype.mordhau.1", 43 | args: args{ 44 | broadcast: "Login: 2021.01.01-00.00.00: Test (52DAB212C79F5EC) logged in", 45 | patterns: map[string]*regexp.Regexp{ 46 | TypeJoin: mordhauJoinPattern, 47 | TypeQuit: mordhauQuitPattern, 48 | }, 49 | }, 50 | want: &Broadcast{ 51 | Type: "JOIN", 52 | Fields: map[string]string{ 53 | "date": "2021.01.01-00.00.00", 54 | "name": "Test", 55 | "playfabid": "52DAB212C79F5EC", 56 | }, 57 | }, 58 | }, 59 | { 60 | name: "broadcast.gettype.mordhau.2", 61 | args: args{ 62 | broadcast: "Login: 3000.01.05-00.30.30: Us#rWith* WeIrDN@mE (537AB82CF9F82A5) logged out", 63 | patterns: map[string]*regexp.Regexp{ 64 | TypeJoin: mordhauJoinPattern, 65 | TypeQuit: mordhauQuitPattern, 66 | }, 67 | }, 68 | want: &Broadcast{ 69 | Type: "QUIT", 70 | Fields: map[string]string{ 71 | "date": "3000.01.05-00.30.30", 72 | "name": "Us#rWith* WeIrDN@mE", 73 | "playfabid": "537AB82CF9F82A5", 74 | }, 75 | }, 76 | }, 77 | { 78 | name: "broadcast.gettype.mordhau.3", 79 | args: args{ 80 | broadcast: "invalid broadcast. no match!", 81 | patterns: map[string]*regexp.Regexp{ 82 | TypeJoin: mordhauJoinPattern, 83 | TypeQuit: mordhauQuitPattern, 84 | }, 85 | }, 86 | want: nil, 87 | }, 88 | } 89 | for _, tt := range tests { 90 | t.Run(tt.name, func(t *testing.T) { 91 | if got := GetBroadcastType(tt.args.broadcast, tt.args.patterns); !reflect.DeepEqual(got, tt.want) { 92 | t.Errorf("GetBroadcastType() = %v, want %v", got, tt.want) 93 | } 94 | }) 95 | } 96 | } 97 | -------------------------------------------------------------------------------- /src/pkg/env/env.go: -------------------------------------------------------------------------------- 1 | /* 2 | * This file is part of Refractor. 3 | * 4 | * Refractor is free software: you can redistribute it and/or modify 5 | * it under the terms of the GNU General Public License as published by 6 | * the Free Software Foundation, either version 3 of the License, or 7 | * (at your option) any later version. 8 | * 9 | * This program is distributed in the hope that it will be useful, 10 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 11 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 | * GNU General Public License for more details. 13 | * 14 | * You should have received A copy of the GNU General Public License 15 | * along with this program. If not, see . 16 | */ 17 | 18 | package env 19 | 20 | import ( 21 | "fmt" 22 | "os" 23 | ) 24 | 25 | type Env struct { 26 | missingVars []string 27 | } 28 | 29 | func RequireEnv(varName string) *Env { 30 | _, exists := os.LookupEnv(varName) 31 | 32 | env := &Env{ 33 | missingVars: []string{}, 34 | } 35 | 36 | if !exists { 37 | env.missingVars = append(env.missingVars, varName) 38 | } 39 | 40 | return env 41 | } 42 | 43 | func (e *Env) RequireEnv(varName string) *Env { 44 | _, exists := os.LookupEnv(varName) 45 | 46 | if !exists { 47 | e.missingVars = append(e.missingVars, varName) 48 | } 49 | 50 | return e 51 | } 52 | 53 | func (e *Env) GetError() error { 54 | if len(e.missingVars) > 0 { 55 | builtError := "The following required environment variables are missing:\n" 56 | 57 | for _, name := range e.missingVars { 58 | builtError += " - " + name + "\n" 59 | } 60 | 61 | builtError += "Please set them then restart the application." 62 | 63 | return fmt.Errorf(builtError) 64 | } 65 | 66 | return nil 67 | } 68 | -------------------------------------------------------------------------------- /src/pkg/env/env_test.go: -------------------------------------------------------------------------------- 1 | /* 2 | * This file is part of Refractor. 3 | * 4 | * Refractor is free software: you can redistribute it and/or modify 5 | * it under the terms of the GNU General Public License as published by 6 | * the Free Software Foundation, either version 3 of the License, or 7 | * (at your option) any later version. 8 | * 9 | * This program is distributed in the hope that it will be useful, 10 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 11 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 | * GNU General Public License for more details. 13 | * 14 | * You should have received a copy of the GNU General Public License 15 | * along with this program. If not, see . 16 | */ 17 | 18 | package env 19 | 20 | import ( 21 | "github.com/franela/goblin" 22 | . "github.com/onsi/gomega" 23 | "os" 24 | "testing" 25 | ) 26 | 27 | func Test(t *testing.T) { 28 | g := goblin.Goblin(t) 29 | 30 | // Special hook for gomega 31 | RegisterFailHandler(func(m string, _ ...int) { g.Fail(m) }) 32 | 33 | g.Describe("RequireEnv()", func() { 34 | g.It("Adds a new missing env variable", func() { 35 | env := RequireEnv("TEST_1") 36 | 37 | Expect(env.missingVars).To(ContainElement("TEST_1")) 38 | }) 39 | 40 | g.It("Adds a new missing env variable when chained", func() { 41 | env := RequireEnv("TEST_1"). 42 | RequireEnv("TEST_2") 43 | 44 | Expect(env.missingVars).To(ContainElements("TEST_1", "TEST_2")) 45 | }) 46 | 47 | g.It("Does not add an existing env variable", func() { 48 | err := os.Setenv("ENV_TEST_VAR_18263782", "true") 49 | Expect(err).To(BeNil()) 50 | 51 | env := RequireEnv("ENV_TEST_VAR_18263782") 52 | Expect(env.missingVars).ToNot(ContainElement("ENV_TEST_VAR_18263782")) 53 | }) 54 | }) 55 | 56 | g.Describe("GetError()", func() { 57 | g.It("Outputs an error message when one or more env variables are missing", func() { 58 | err := RequireEnv("TEST_1").RequireEnv("TEST_2").GetError() 59 | 60 | Expect(err).ToNot(BeNil()) 61 | }) 62 | 63 | g.It("Outputs an error which contains a list of missing env variables", func() { 64 | err := os.Setenv("ENV_TEST_VAR_18263783", "true") 65 | Expect(err).To(BeNil()) 66 | 67 | err = RequireEnv("TEST_1"). 68 | RequireEnv("ENV_TEST_VAR_18263783"). 69 | RequireEnv("TEST_2"). 70 | GetError() 71 | 72 | Expect(err).ToNot(BeNil()) 73 | Expect(err.Error()).To(ContainSubstring("TEST_1")) 74 | Expect(err.Error()).To(ContainSubstring("TEST_2")) 75 | Expect(err.Error()).ToNot(ContainSubstring("ENV_TEST_VAR_18263783")) 76 | }) 77 | }) 78 | } 79 | -------------------------------------------------------------------------------- /src/pkg/pointer/depointer.go: -------------------------------------------------------------------------------- 1 | /* 2 | * This file is part of Refractor. 3 | * 4 | * Refractor is free software: you can redistribute it and/or modify 5 | * it under the terms of the GNU General Public License as published by 6 | * the Free Software Foundation, either version 3 of the License, or 7 | * (at your option) any later version. 8 | * 9 | * This program is distributed in the hope that it will be useful, 10 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 11 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 | * GNU General Public License for more details. 13 | * 14 | * You should have received a copy of the GNU General Public License 15 | * along with this program. If not, see . 16 | */ 17 | 18 | package pointer 19 | 20 | import "reflect" 21 | 22 | // DePointer takes in an interface{} and checks if it's a pointer or not. If it is a pointer, it dereferences it and 23 | // returns the dereferenced interface. If it is not a pointer, it just returns the value. 24 | func DePointer(val interface{}) interface{} { 25 | v := reflect.ValueOf(val) 26 | if v.Kind() == reflect.Ptr { 27 | return v.Elem().Interface() 28 | } 29 | 30 | return val 31 | } 32 | -------------------------------------------------------------------------------- /src/pkg/pointer/depointer_test.go: -------------------------------------------------------------------------------- 1 | /* 2 | * This file is part of Refractor. 3 | * 4 | * Refractor is free software: you can redistribute it and/or modify 5 | * it under the terms of the GNU General Public License as published by 6 | * the Free Software Foundation, either version 3 of the License, or 7 | * (at your option) any later version. 8 | * 9 | * This program is distributed in the hope that it will be useful, 10 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 11 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 | * GNU General Public License for more details. 13 | * 14 | * You should have received a copy of the GNU General Public License 15 | * along with this program. If not, see . 16 | */ 17 | 18 | package pointer 19 | 20 | import ( 21 | "github.com/franela/goblin" 22 | . "github.com/onsi/gomega" 23 | "testing" 24 | ) 25 | 26 | func Test(t *testing.T) { 27 | g := goblin.Goblin(t) 28 | 29 | // Special hook for gomega 30 | RegisterFailHandler(func(m string, _ ...int) { g.Fail(m) }) 31 | 32 | g.Describe("DePointer()", func() { 33 | g.Describe("A pointer was passed in", func() { 34 | g.It("Should return the de-referenced value", func() { 35 | var testStr = "test" 36 | 37 | res := DePointer(&testStr) 38 | 39 | Expect(res).To(Equal(testStr)) 40 | }) 41 | }) 42 | 43 | g.Describe("A non-pointer was passed in", func() { 44 | g.It("Should return the passed in value", func() { 45 | var testStr = "test" 46 | 47 | res := DePointer(testStr) 48 | 49 | Expect(res).To(Equal(testStr)) 50 | }) 51 | }) 52 | }) 53 | } 54 | -------------------------------------------------------------------------------- /src/pkg/querybuilders/psqlqb/postgres_querybuilder_test.go: -------------------------------------------------------------------------------- 1 | /* 2 | * This file is part of Refractor. 3 | * 4 | * Refractor is free software: you can redistribute it and/or modify 5 | * it under the terms of the GNU General Public License as published by 6 | * the Free Software Foundation, either version 3 of the License, or 7 | * (at your option) any later version. 8 | * 9 | * This program is distributed in the hope that it will be useful, 10 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 11 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 | * GNU General Public License for more details. 13 | * 14 | * You should have received a copy of the GNU General Public License 15 | * along with this program. If not, see . 16 | */ 17 | 18 | package psqlqb 19 | 20 | import ( 21 | "Refractor/domain" 22 | "fmt" 23 | "github.com/franela/goblin" 24 | . "github.com/onsi/gomega" 25 | "testing" 26 | ) 27 | 28 | func Test(t *testing.T) { 29 | g := goblin.Goblin(t) 30 | 31 | // Special hook for gomega 32 | RegisterFailHandler(func(m string, _ ...int) { g.Fail(m) }) 33 | 34 | g.Describe("Postgres Query Builder", func() { 35 | var qbl domain.QueryBuilder 36 | 37 | g.BeforeEach(func() { 38 | qbl = NewPostgresQueryBuilder() 39 | }) 40 | 41 | g.Describe("BuildUpdateQueryComposite()", func() { 42 | g.It("Should return the expected query and values", func() { 43 | var table = "TestTable" 44 | 45 | updateArgs := domain.UpdateArgs{ 46 | "Watched": true, 47 | } 48 | 49 | query, values := qbl.BuildUpdateQueryComposite(table, []interface{}{"ID1", "ID2"}, []string{"Key1", "Key2"}, updateArgs) 50 | 51 | expectedQuery := "UPDATE TestTable SET Watched = $1 WHERE Key1 = $2 AND Key2 = $3 RETURNING *;" 52 | 53 | fmt.Println(query) 54 | fmt.Println(expectedQuery) 55 | 56 | Expect(query).To(Equal(expectedQuery)) 57 | Expect(values).To(Equal([]interface{}{true, "ID1", "ID2"})) 58 | }) 59 | }) 60 | }) 61 | } 62 | -------------------------------------------------------------------------------- /src/pkg/regexutils/named.go: -------------------------------------------------------------------------------- 1 | /* 2 | * This file is part of Refractor. 3 | * 4 | * Refractor is free software: you can redistribute it and/or modify 5 | * it under the terms of the GNU General Public License as published by 6 | * the Free Software Foundation, either version 3 of the License, or 7 | * (at your option) any later version. 8 | * 9 | * This program is distributed in the hope that it will be useful, 10 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 11 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 | * GNU General Public License for more details. 13 | * 14 | * You should have received a copy of the GNU General Public License 15 | * along with this program. If not, see . 16 | */ 17 | 18 | package regexutils 19 | 20 | import "regexp" 21 | 22 | func MapNamedMatches(pattern *regexp.Regexp, data string) map[string]string { 23 | matches := pattern.FindStringSubmatch(data) 24 | 25 | if len(matches) < 1 { 26 | return nil 27 | } 28 | 29 | matches = matches[1:] // skip first match since it's the entire match, not just the submatches 30 | 31 | namedMatches := map[string]string{} 32 | 33 | for i, name := range pattern.SubexpNames() { 34 | // skip the first global match 35 | if i == 0 { 36 | continue 37 | } 38 | 39 | namedMatches[name] = matches[i-1] 40 | } 41 | 42 | return namedMatches 43 | } 44 | -------------------------------------------------------------------------------- /src/pkg/regexutils/named_test.go: -------------------------------------------------------------------------------- 1 | /* 2 | * This file is part of Refractor. 3 | * 4 | * Refractor is free software: you can redistribute it and/or modify 5 | * it under the terms of the GNU General Public License as published by 6 | * the Free Software Foundation, either version 3 of the License, or 7 | * (at your option) any later version. 8 | * 9 | * This program is distributed in the hope that it will be useful, 10 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 11 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 | * GNU General Public License for more details. 13 | * 14 | * You should have received a copy of the GNU General Public License 15 | * along with this program. If not, see . 16 | */ 17 | 18 | package regexutils 19 | 20 | import ( 21 | "github.com/stretchr/testify/assert" 22 | "regexp" 23 | "testing" 24 | ) 25 | 26 | func TestMapNamedMatches(t *testing.T) { 27 | type args struct { 28 | pattern *regexp.Regexp 29 | data string 30 | } 31 | tests := []struct { 32 | name string 33 | args args 34 | want map[string]string 35 | }{ 36 | { 37 | name: "regexutils.namedmatches.1", 38 | args: args{ 39 | pattern: regexp.MustCompile("^(?P[0-9]+)$"), 40 | data: "1", 41 | }, 42 | want: map[string]string{ 43 | "ID": "1", 44 | }, 45 | }, 46 | { 47 | name: "regexutils.namedmatches.2", 48 | args: args{ 49 | pattern: regexp.MustCompile("^(?P[0-9]+),(?P[0-9a-zA-Z]+)$"), 50 | data: "1,test", 51 | }, 52 | want: map[string]string{ 53 | "ID": "1", 54 | "Username": "test", 55 | }, 56 | }, 57 | } 58 | for _, tt := range tests { 59 | t.Run(tt.name, func(t *testing.T) { 60 | fields := MapNamedMatches(tt.args.pattern, tt.args.data) 61 | 62 | assert.Equal(t, tt.want, fields) 63 | }) 64 | } 65 | } 66 | -------------------------------------------------------------------------------- /src/pkg/structutils/reflection.go: -------------------------------------------------------------------------------- 1 | /* 2 | * This file is part of Refractor. 3 | * 4 | * Refractor is free software: you can redistribute it and/or modify 5 | * it under the terms of the GNU General Public License as published by 6 | * the Free Software Foundation, either version 3 of the License, or 7 | * (at your option) any later version. 8 | * 9 | * This program is distributed in the hope that it will be useful, 10 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 11 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 | * GNU General Public License for more details. 13 | * 14 | * You should have received A copy of the GNU General Public License 15 | * along with this program. If not, see . 16 | */ 17 | 18 | package structutils 19 | 20 | import ( 21 | "fmt" 22 | "reflect" 23 | ) 24 | 25 | // GetNonNilFieldMap looks through all fields on A struct, and returns A map[string]interface{} with the field name 26 | // being the key and the value being the interface for all fields with non-nil values. 27 | func GetNonNilFieldMap(targetStruct interface{}) (map[string]interface{}, error) { 28 | // If this is A pointer to A struct, use the getNonNilFieldMapPointer helper function 29 | v := reflect.ValueOf(targetStruct) 30 | if v.Kind() == reflect.Ptr { 31 | return getNonNilFieldMapPointer(v) 32 | } 33 | 34 | return getNonNilFieldMapValue(v) 35 | } 36 | 37 | func getNonNilFieldMapPointer(v reflect.Value) (map[string]interface{}, error) { 38 | values := map[string]interface{}{} 39 | 40 | // Dereference the pointer and check if it's A struct type 41 | v = v.Elem() 42 | if v.Kind() != reflect.Struct { 43 | return values, fmt.Errorf("pointer did not reference A struct type") 44 | } 45 | 46 | t := v.Type() 47 | for i := 0; i < t.NumField(); i++ { 48 | field := t.Field(i) 49 | 50 | // Skip nil fields 51 | if v.Field(i).IsNil() { 52 | continue 53 | } 54 | 55 | values[field.Name] = v.Field(i).Interface() 56 | } 57 | 58 | return values, nil 59 | } 60 | 61 | func getNonNilFieldMapValue(v reflect.Value) (map[string]interface{}, error) { 62 | values := map[string]interface{}{} 63 | 64 | if v.Kind() != reflect.Struct { 65 | return values, fmt.Errorf("passed in value was not A struct") 66 | } 67 | 68 | t := v.Type() 69 | for i := 0; i < t.NumField(); i++ { 70 | field := t.Field(i) 71 | 72 | // Skip nil fields 73 | if v.Field(i).IsNil() { 74 | continue 75 | } 76 | 77 | values[field.Name] = v.Field(i).Interface() 78 | } 79 | 80 | return values, nil 81 | } 82 | -------------------------------------------------------------------------------- /src/pkg/structutils/reflection_test.go: -------------------------------------------------------------------------------- 1 | /* 2 | * This file is part of Refractor. 3 | * 4 | * Refractor is free software: you can redistribute it and/or modify 5 | * it under the terms of the GNU General Public License as published by 6 | * the Free Software Foundation, either version 3 of the License, or 7 | * (at your option) any later version. 8 | * 9 | * This program is distributed in the hope that it will be useful, 10 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 11 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 | * GNU General Public License for more details. 13 | * 14 | * You should have received A copy of the GNU General Public License 15 | * along with this program. If not, see . 16 | */ 17 | 18 | package structutils 19 | 20 | import ( 21 | "github.com/franela/goblin" 22 | . "github.com/onsi/gomega" 23 | "testing" 24 | ) 25 | 26 | type testType struct { 27 | A *int 28 | B *string 29 | C *float64 30 | D *string 31 | } 32 | 33 | func Test(t *testing.T) { 34 | g := goblin.Goblin(t) 35 | 36 | // Special hook for gomega 37 | RegisterFailHandler(func(m string, _ ...int) { g.Fail(m) }) 38 | 39 | a := 1 40 | b := "test" 41 | c := 3.14 42 | 43 | var testStructPtr = &testType{ 44 | A: &a, 45 | B: &b, 46 | C: &c, 47 | D: nil, 48 | } 49 | 50 | var testStruct = testType{ 51 | A: &a, 52 | B: &b, 53 | C: &c, 54 | D: nil, 55 | } 56 | 57 | var expectedOutput = map[string]interface{}{ 58 | "A": &a, 59 | "B": &b, 60 | "C": &c, 61 | } 62 | 63 | g.Describe("GetNonNilFieldMap()", func() { 64 | g.Describe("A valid struct value was passed in", func() { 65 | g.It("Should not return an error", func() { 66 | _, err := GetNonNilFieldMap(testStruct) 67 | 68 | Expect(err).To(BeNil()) 69 | }) 70 | 71 | g.It("Should return a map containing the non-nil keys and values", func() { 72 | output, _ := GetNonNilFieldMap(testStructPtr) 73 | 74 | Expect(output).To(Equal(expectedOutput)) 75 | }) 76 | }) 77 | 78 | g.Describe("A valid struct pointer was passed in", func() { 79 | g.It("Should not return an error", func() { 80 | _, err := GetNonNilFieldMap(testStructPtr) 81 | 82 | Expect(err).To(BeNil()) 83 | }) 84 | 85 | g.It("Should return a map containing the non-nil keys and values", func() { 86 | output, _ := GetNonNilFieldMap(testStructPtr) 87 | 88 | Expect(output).To(Equal(expectedOutput)) 89 | }) 90 | }) 91 | 92 | g.Describe("A non struct or struct pointer type was passed in", func() { 93 | g.It("Should return an error", func() { 94 | _, err := GetNonNilFieldMap("invalid type") 95 | 96 | Expect(err).ToNot(BeNil()) 97 | }) 98 | 99 | g.It("Should return an empty map", func() { 100 | output, _ := GetNonNilFieldMap("invalid type") 101 | 102 | Expect(output).To(Equal(map[string]interface{}{})) 103 | }) 104 | }) 105 | }) 106 | } 107 | -------------------------------------------------------------------------------- /src/pkg/tmpl/renderer.go: -------------------------------------------------------------------------------- 1 | /* 2 | * This file is part of Refractor. 3 | * 4 | * Refractor is free software: you can redistribute it and/or modify 5 | * it under the terms of the GNU General Public License as published by 6 | * the Free Software Foundation, either version 3 of the License, or 7 | * (at your option) any later version. 8 | * 9 | * This program is distributed in the hope that it will be useful, 10 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 11 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 | * GNU General Public License for more details. 13 | * 14 | * You should have received a copy of the GNU General Public License 15 | * along with this program. If not, see . 16 | */ 17 | 18 | package tmpl 19 | 20 | import ( 21 | "github.com/labstack/echo/v4" 22 | "html/template" 23 | "io" 24 | "strings" 25 | ) 26 | 27 | type Renderer struct { 28 | template *template.Template 29 | debug bool 30 | location string 31 | } 32 | 33 | func (t *Renderer) ReloadTemplates() { 34 | funcMap := template.FuncMap{ 35 | "Capitalize": strings.Title, 36 | } 37 | 38 | t.template = template.Must(template.New("main").Funcs(funcMap).ParseGlob(t.location)) 39 | } 40 | 41 | func (t *Renderer) Render(w io.Writer, name string, data interface{}, c echo.Context) error { 42 | if t.debug { 43 | t.ReloadTemplates() 44 | } 45 | 46 | return t.template.ExecuteTemplate(w, name, data) 47 | } 48 | 49 | func NewRenderer(location string, debug bool) *Renderer { 50 | tpl := new(Renderer) 51 | tpl.location = location 52 | tpl.debug = debug 53 | 54 | tpl.ReloadTemplates() 55 | 56 | return tpl 57 | } 58 | -------------------------------------------------------------------------------- /src/pkg/websocket/upgrader.go: -------------------------------------------------------------------------------- 1 | /* 2 | * This file is part of Refractor. 3 | * 4 | * Refractor is free software: you can redistribute it and/or modify 5 | * it under the terms of the GNU General Public License as published by 6 | * the Free Software Foundation, either version 3 of the License, or 7 | * (at your option) any later version. 8 | * 9 | * This program is distributed in the hope that it will be useful, 10 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 11 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 | * GNU General Public License for more details. 13 | * 14 | * You should have received a copy of the GNU General Public License 15 | * along with this program. If not, see . 16 | */ 17 | 18 | package websocket 19 | 20 | import ( 21 | "github.com/gobwas/ws" 22 | "net" 23 | "net/http" 24 | ) 25 | 26 | func Upgrade(w http.ResponseWriter, r *http.Request) (net.Conn, error) { 27 | conn, _, _, err := ws.UpgradeHTTP(r, w) 28 | if err != nil { 29 | return nil, err 30 | } 31 | 32 | return conn, nil 33 | } 34 | -------------------------------------------------------------------------------- /src/pkg/whitelist/whitelist.go: -------------------------------------------------------------------------------- 1 | /* 2 | * This file is part of Refractor. 3 | * 4 | * Refractor is free software: you can redistribute it and/or modify 5 | * it under the terms of the GNU General Public License as published by 6 | * the Free Software Foundation, either version 3 of the License, or 7 | * (at your option) any later version. 8 | * 9 | * This program is distributed in the hope that it will be useful, 10 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 11 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 | * GNU General Public License for more details. 13 | * 14 | * You should have received a copy of the GNU General Public License 15 | * along with this program. If not, see . 16 | */ 17 | 18 | package whitelist 19 | 20 | type StringKeyMap []string 21 | 22 | func (m StringKeyMap) FilterKeys(input map[string]interface{}) map[string]interface{} { 23 | for k, _ := range input { 24 | allowedKey := false 25 | for _, whitelistKey := range m { 26 | if k == whitelistKey { 27 | allowedKey = true 28 | break 29 | } 30 | } 31 | 32 | if !allowedKey { 33 | delete(input, k) 34 | } 35 | } 36 | 37 | return input 38 | } 39 | -------------------------------------------------------------------------------- /src/pkg/whitelist/whitelist_test.go: -------------------------------------------------------------------------------- 1 | /* 2 | * This file is part of Refractor. 3 | * 4 | * Refractor is free software: you can redistribute it and/or modify 5 | * it under the terms of the GNU General Public License as published by 6 | * the Free Software Foundation, either version 3 of the License, or 7 | * (at your option) any later version. 8 | * 9 | * This program is distributed in the hope that it will be useful, 10 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 11 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 | * GNU General Public License for more details. 13 | * 14 | * You should have received a copy of the GNU General Public License 15 | * along with this program. If not, see . 16 | */ 17 | 18 | package whitelist 19 | 20 | import ( 21 | "github.com/franela/goblin" 22 | . "github.com/onsi/gomega" 23 | "testing" 24 | ) 25 | 26 | func Test(t *testing.T) { 27 | g := goblin.Goblin(t) 28 | 29 | // Special hook for gomega 30 | RegisterFailHandler(func(m string, _ ...int) { g.Fail(m) }) 31 | 32 | g.Describe("Whitelist test", func() { 33 | g.Describe("StringKeyMap", func() { 34 | g.Describe("FilterKeys()", func() { 35 | var input map[string]interface{} 36 | 37 | g.BeforeEach(func() { 38 | input = map[string]interface{}{ 39 | "Key1": "val1", 40 | "Key2": "val1", 41 | "Key3": "val1", 42 | "Key4": "val1", 43 | } 44 | }) 45 | 46 | g.It("Should remove fields with non-whitelisted keys", func() { 47 | wl := StringKeyMap{ 48 | "Key1", 49 | "Key3", 50 | } 51 | 52 | expected := map[string]interface{}{ 53 | "Key1": "val1", 54 | "Key3": "val1", 55 | } 56 | 57 | output := wl.FilterKeys(input) 58 | 59 | Expect(output).To(Equal(expected)) 60 | }) 61 | }) 62 | }) 63 | }) 64 | } 65 | -------------------------------------------------------------------------------- /src/platforms/mojang/mojang.go: -------------------------------------------------------------------------------- 1 | /* 2 | * This file is part of Refractor. 3 | * 4 | * Refractor is free software: you can redistribute it and/or modify 5 | * it under the terms of the GNU General Public License as published by 6 | * the Free Software Foundation, either version 3 of the License, or 7 | * (at your option) any later version. 8 | * 9 | * This program is distributed in the hope that it will be useful, 10 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 11 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 | * GNU General Public License for more details. 13 | * 14 | * You should have received a copy of the GNU General Public License 15 | * along with this program. If not, see . 16 | */ 17 | 18 | package mojang 19 | 20 | import "Refractor/domain" 21 | 22 | type mojang struct{} 23 | 24 | func NewMojangPlatform() domain.Platform { 25 | return &mojang{} 26 | } 27 | 28 | func (p *mojang) GetDisplayName() string { 29 | return "Mojang" 30 | } 31 | 32 | func (p *mojang) GetName() string { 33 | return "mojang" 34 | } 35 | -------------------------------------------------------------------------------- /src/platforms/playfab/playfab.go: -------------------------------------------------------------------------------- 1 | /* 2 | * This file is part of Refractor. 3 | * 4 | * Refractor is free software: you can redistribute it and/or modify 5 | * it under the terms of the GNU General Public License as published by 6 | * the Free Software Foundation, either version 3 of the License, or 7 | * (at your option) any later version. 8 | * 9 | * This program is distributed in the hope that it will be useful, 10 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 11 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 | * GNU General Public License for more details. 13 | * 14 | * You should have received a copy of the GNU General Public License 15 | * along with this program. If not, see . 16 | */ 17 | 18 | package playfab 19 | 20 | import "Refractor/domain" 21 | 22 | type playfab struct{} 23 | 24 | func NewPlayfabPlatform() domain.Platform { 25 | return &playfab{} 26 | } 27 | 28 | func (p *playfab) GetDisplayName() string { 29 | return "PlayFab" 30 | } 31 | 32 | func (p *playfab) GetName() string { 33 | return "playfab" 34 | } 35 | -------------------------------------------------------------------------------- /update.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | echo "This script will checkout the latest tagged version from both the Refractor and Refractor-Svelte repositories." 4 | 5 | echo "" 6 | echo "Checking out latest tag of backend service..." 7 | git fetch --tags 8 | latestTag=$(git describe --tags `git rev-list --tags --max-count=1`) 9 | 10 | git checkout $latestTag > /dev/null 11 | echo "" 12 | echo "Successfully checked out latest tag." 13 | 14 | echo "" 15 | echo "Checking out latest tag of frontend application..." 16 | cd Refractor-Svelte 17 | git fetch --tags 18 | latestTag=$(git describe --tags `git rev-list --tags --max-count=1`) 19 | 20 | git checkout $latestTag > /dev/null 21 | cd .. 22 | echo "" 23 | echo "Successfully checked out latest tag." 24 | 25 | echo "" 26 | echo "" 27 | echo "Rebuilding services..." 28 | echo "Please let this script run uninterrupted until it's finished." 29 | 30 | docker-compose -f docker-compose.yml -f compose-frontend-svelte.yml up -d --force-recreate --build --no-deps refractor refractor-frontend 31 | 32 | echo "" 33 | echo "" 34 | echo "Services updated!" 35 | --------------------------------------------------------------------------------