Compare commits

..

19 Commits
1.2.1 ... 1.3.5

Author SHA1 Message Date
bb213f001e chore(release): 1.3.5
All checks were successful
Build release images / build-container (push) Successful in 1m16s
2025-04-08 20:01:13 +02:00
5415cd38a7 feat(runners): Generate selfservice urls on runner if requested or create/update/get single 2025-04-08 20:00:27 +02:00
175ba52ffa chore(release): 1.3.4
All checks were successful
Build release images / build-container (push) Successful in 1m10s
2025-03-28 21:49:42 +01:00
5c5000a218 feat: add runnersViaSelfservice to statsControllerGet 2025-03-28 21:49:19 +01:00
d559d04031 chore(release): 1.3.3
All checks were successful
Build release images / build-container (push) Successful in 1m11s
2025-03-28 21:20:39 +01:00
2af682d1dd ci: remove "v" prefix from tags 2025-03-28 21:20:30 +01:00
30905e481c chore(release): v1.3.2
All checks were successful
Build release images / build-container (push) Successful in 1m17s
2025-03-28 21:16:41 +01:00
752d405bda ci: pnpm@10.7 2025-03-28 21:16:28 +01:00
8fa4ed7c33 chore(release): v1.3.1
Some checks failed
Build release images / build-container (push) Failing after 6s
2025-03-28 21:15:27 +01:00
c4201e9a68 fix: TypeError: Cannot read properties of undefined (reading 'filter') - when trying to delete a org/team with runners
close #210
2025-03-28 21:14:14 +01:00
78dcad0857 pnpm@10.7, node@23, argon->@node-rs/argon2 2025-03-28 21:04:50 +01:00
93e0cdf577 chore(release): v1.3.0
Some checks failed
Build release images / build-container (push) Failing after 6s
2025-03-28 18:56:01 +01:00
6efcd94726 ci: change release commit message 2025-03-28 18:55:25 +01:00
2e271bcd52 fix: add .created_via to ResponseParticipant constructor 2025-03-28 18:24:53 +01:00
ebde8c6ffd ci: move to gitea workflows 2025-03-28 18:07:10 +01:00
a3639dd89b feat: created_via for tracking how runners got into the system (#212)
close #211

squash merge please:)

Reviewed-on: #212
2025-03-28 17:05:10 +00:00
0a43f1bb5b build: docker "AS" casing 2025-03-28 17:41:20 +01:00
8c6fdb2239 refactor(RunnerController.remove): only load necessary relations 2025-03-28 12:01:15 +01:00
c0d5af5d7a refactor(RunnerTeamController.remove): only load necessary relations 2025-03-28 12:00:55 +01:00
30 changed files with 6076 additions and 4589 deletions

View File

@@ -0,0 +1,33 @@
name: Build release images
on:
push:
tags:
- "*.*.*"
jobs:
build-container:
runs-on: ubuntu-latest
steps:
- name: Checkout
uses: actions/checkout@v4
- name: Set up Node.js
uses: actions/setup-node@v4
with:
node-version: 19
- run: npm i -g pnpm@10.7 && pnpm i
- run: pnpm licenses:export
- name: Login to registry
uses: docker/login-action@v3
with:
registry: registry.odit.services
username: ${{ vars.REGISTRY_USERNAME }}
password: ${{ secrets.REGISTRY_PASSWORD }}
- name: Set up Docker Buildx
uses: docker/setup-buildx-action@v3
- name: Build and push
uses: docker/build-push-action@v6
with:
push: true
tags: |
${{ vars.REGISTRY }}/lfk/backend:${{ github.ref_name }}
platforms: linux/amd64,linux/arm64

View File

@@ -9,8 +9,7 @@
"[typescript]": {
"editor.defaultFormatter": "vscode.typescript-language-features",
"editor.codeActionsOnSave": {
"source.organizeImports": true,
// "source.fixAll": true
"source.organizeImports": "explicit"
}
},
"javascript.preferences.quoteStyle": "single",

View File

@@ -1,33 +0,0 @@
steps:
- name: build latest
image: woodpeckerci/plugin-docker-buildx
settings:
repo: registry.odit.services/lfk/backend
tags:
- latest
registry: registry.odit.services
platforms: linux/amd64,linux/arm64
cache_from: registry.odit.services/lfk/backend:dev
username:
from_secret: odit-registry-builder-username
password:
from_secret: odit-registry-builder-password
when:
branch: main
- name: build dev
image: woodpeckerci/plugin-docker-buildx
settings:
repo: registry.odit.services/lfk/backend
tags:
- dev
registry: registry.odit.services
platforms: linux/amd64,linux/arm64
cache_from: registry.odit.services/lfk/backend:dev
username:
from_secret: odit-registry-builder-username
password:
from_secret: odit-registry-builder-password
when:
branch: dev
when:
event: push

View File

@@ -1,17 +0,0 @@
steps:
- name: build tag
image: woodpeckerci/plugin-docker-buildx
settings:
repo: registry.odit.services/lfk/backend
tags:
- "${CI_COMMIT_TAG}"
registry: registry.odit.services
platforms: linux/amd64,linux/arm64
cache_from: registry.odit.services/lfk/backend:dev
username:
from_secret: odit-registry-builder-username
password:
from_secret: odit-registry-builder-password
when:
event:
- tag

View File

@@ -2,13 +2,83 @@
All notable changes to this project will be documented in this file. Dates are displayed in UTC.
#### [1.3.5](https://git.odit.services/lfk/backend/compare/1.3.4...1.3.5)
- feat(runners): Generate selfservice urls on runner if requested or create/update/get single [`5415cd3`](https://git.odit.services/lfk/backend/commit/5415cd38a727e76632a01a4d2634a1777df5542c)
#### [1.3.4](https://git.odit.services/lfk/backend/compare/1.3.3...1.3.4)
> 28 March 2025
- feat: add runnersViaSelfservice to statsControllerGet [`5c5000a`](https://git.odit.services/lfk/backend/commit/5c5000a218b47815e6846ac8b857dcd1995bfa6f)
- chore(release): 1.3.4 [`175ba52`](https://git.odit.services/lfk/backend/commit/175ba52ffae8e6ba1fdc1603ac2f5eba15602046)
#### [1.3.3](https://git.odit.services/lfk/backend/compare/v1.3.2...1.3.3)
> 28 March 2025
- chore(release): 1.3.3 [`d559d04`](https://git.odit.services/lfk/backend/commit/d559d0403191c703fd6da0e3f3dab53eec9258c0)
- ci: remove "v" prefix from tags [`2af682d`](https://git.odit.services/lfk/backend/commit/2af682d1dd09df496eb9f3a9111c50c0c4117356)
#### [v1.3.2](https://git.odit.services/lfk/backend/compare/v1.3.1...v1.3.2)
> 28 March 2025
- chore(release): v1.3.2 [`30905e4`](https://git.odit.services/lfk/backend/commit/30905e481c69cfe62b4261544b4277de3a1a43c2)
- ci: pnpm@10.7 [`752d405`](https://git.odit.services/lfk/backend/commit/752d405bda9129f3cd288a956d5444cab316c2af)
#### [v1.3.1](https://git.odit.services/lfk/backend/compare/1.3.0...v1.3.1)
> 28 March 2025
- fix: TypeError: Cannot read properties of undefined (reading 'filter') - when trying to delete a org/team with runners [`#210`](https://git.odit.services/lfk/backend/issues/210)
- pnpm@10.7, node@23, argon->@node-rs/argon2 [`78dcad0`](https://git.odit.services/lfk/backend/commit/78dcad085794c93829499dd550a786c38d6186f5)
- chore(release): v1.3.1 [`8fa4ed7`](https://git.odit.services/lfk/backend/commit/8fa4ed7c3319c3e56a71701ba266ceda64d2ef69)
#### [1.3.0](https://git.odit.services/lfk/backend/compare/1.2.1...1.3.0)
> 28 March 2025
- feat: created_via for tracking how runners got into the system [`#212`](https://git.odit.services/lfk/backend/pull/212)
- feat: created_via for tracking how runners got into the system (#212) [`#211`](https://git.odit.services/lfk/backend/issues/211)
- ci: move to gitea workflows [`ebde8c6`](https://git.odit.services/lfk/backend/commit/ebde8c6ffd8b17c6752da8c4d8eb3095105f6132)
- chore(release): v1.3.0 [`93e0cdf`](https://git.odit.services/lfk/backend/commit/93e0cdf577654898b2d63790d91598c458a2db59)
- build: docker "AS" casing [`0a43f1b`](https://git.odit.services/lfk/backend/commit/0a43f1bb5b26d3acb0d4d91648473f0dc55e8637)
- ci: change release commit message [`6efcd94`](https://git.odit.services/lfk/backend/commit/6efcd94726957b8c527820f1a9b0130151ce22f1)
- refactor(RunnerController.remove): only load necessary relations [`8c6fdb2`](https://git.odit.services/lfk/backend/commit/8c6fdb22390218e385780fadb3bdaf32148ac054)
- refactor(RunnerTeamController.remove): only load necessary relations [`c0d5af5`](https://git.odit.services/lfk/backend/commit/c0d5af5d7ab44cfdf19014e0d774fb560d08f6d7)
- fix: add .created_via to ResponseParticipant constructor [`2e271bc`](https://git.odit.services/lfk/backend/commit/2e271bcd52f02ab7449cd15916b0afc86e8b0a90)
#### [1.2.1](https://git.odit.services/lfk/backend/compare/1.2.0...1.2.1)
> 11 December 2024
- refactor: allow selfservice link every 30s [`07bf28b`](https://git.odit.services/lfk/backend/commit/07bf28b14458849930748ce041fb65e572759482)
- chore(release): 1.2.1 [`4008a5e`](https://git.odit.services/lfk/backend/commit/4008a5ee720b212bac9cba64417058bf4526060b)
#### [1.2.0](https://git.odit.services/lfk/backend/compare/v1.1.4...1.2.0)
> 11 December 2024
- refactor: move to new mailer [`0f4c8b2`](https://git.odit.services/lfk/backend/commit/0f4c8b2051cae17fbdd7e02017ad5b41c61e210c)
- refactor(ci): Switch to new woodpecker [`b3a73b2`](https://git.odit.services/lfk/backend/commit/b3a73b25e80a0466ff83e43481271fc0cd499a0d)
- feat: middlename [`6eff243`](https://git.odit.services/lfk/backend/commit/6eff2438035b368eb45931fad9402a6cb942b350)
- SELFSERVICE_URL [`765ef84`](https://git.odit.services/lfk/backend/commit/765ef849035ca4f8b2253bb76d15be8e9a3e6763)
- FRONTEND_URL env [`296ba8d`](https://git.odit.services/lfk/backend/commit/296ba8ddab1dba46f8201829d9a7e5fc1c88c0f8)
- chore: update readme [`d842c14`](https://git.odit.services/lfk/backend/commit/d842c14240fb4a7f70c66143bbe877f8168ef6d4)
- chore(release): 1.2.0 [`6764bf8`](https://git.odit.services/lfk/backend/commit/6764bf80eac832d186e688319d8a959543a1495f)
- Merge pull request 'refactor: move to new mailer' (#209) from refactor/new-mailer into dev [`bda1f97`](https://git.odit.services/lfk/backend/commit/bda1f971d1a14ea403439533c7ae31280c7df167)
#### [v1.1.4](https://git.odit.services/lfk/backend/compare/v1.1.3...v1.1.4)
> 20 November 2024
- build: package lock [`50dd703`](https://git.odit.services/lfk/backend/commit/50dd703a1bd276a607cc10a087c7e90fd880847a)
- fix(deps): Bump sqlite3 [`cd3cd81`](https://git.odit.services/lfk/backend/commit/cd3cd81360777e8bc4d78e861354e58c8da79cc7)
- feat(ci)!: Switch to woodpecker [`3192365`](https://git.odit.services/lfk/backend/commit/3192365793fae59f2b89e3231db298654f0a28e9)
- fix(deps): Bumped argon2 to latest version for arm support [`cf48c00`](https://git.odit.services/lfk/backend/commit/cf48c00ddb2ac33263549876928db50ae152c12d)
- fix: updated README for pnpm, typos [`5082b1b`](https://git.odit.services/lfk/backend/commit/5082b1b8b1c0ae9e8ffa9c71c4d7923fd9223c87)
- 🚀Bumped version to v1.1.4 [`a54cb28`](https://git.odit.services/lfk/backend/commit/a54cb287a4323ac8de77f51711cc6c52ec290859)
- ci: drop lfk-client-node [`075d484`](https://git.odit.services/lfk/backend/commit/075d484f1169bfc5c5b68cb9712116b0e270b471)
- fix(dependencies): Switch back to previous class-validator version to produce a working build [`74d334f`](https://git.odit.services/lfk/backend/commit/74d334f9b747a77115bd9b97729ef1120822e128)

View File

@@ -1,10 +1,12 @@
# Typescript Build
FROM registry.odit.services/hub/library/node:21.1.0-alpine3.18 as build
FROM registry.odit.services/hub/library/node:23.10.0-alpine3.21 AS build
ARG NPM_REGISTRY_URL=https://registry.npmjs.org
WORKDIR /app
COPY package.json ./
RUN npm config set registry $NPM_REGISTRY_URL && npm i -g pnpm@8
COPY pnpm-workspace.yaml ./
COPY pnpm-lock.yaml ./
RUN npm config set registry $NPM_REGISTRY_URL && npm i -g pnpm@10.7
RUN mkdir /pnpm && pnpm config set store-dir /pnpm && pnpm i
COPY tsconfig.json ormconfig.js ./
@@ -14,9 +16,11 @@ RUN pnpm run build \
&& pnpm i --production --prefer-offline
# final image
FROM registry.odit.services/hub/library/node:21.1.0-alpine3.18 as final
FROM registry.odit.services/hub/library/node:23.10.0-alpine3.21 AS final
WORKDIR /app
COPY --from=build /app/package.json /app/package.json
COPY --from=build /app/pnpm-lock.yaml /app/pnpm-lock.yaml
COPY --from=build /app/pnpm-workspace.yaml /app/pnpm-workspace.yaml
COPY --from=build /app/ormconfig.js /app/ormconfig.js
COPY --from=build /app/dist /app/dist
COPY --from=build /app/node_modules /app/node_modules

View File

@@ -1,4 +1,3 @@
version: "3"
services:
backend_server:
build: .
@@ -14,7 +13,7 @@ services:
DB_NAME: ./db.sqlite
NODE_ENV: production
POSTALCODE_COUNTRYCODE: DE
SEED_TEST_DATA: "false"
SEED_TEST_DATA: "true"
MAILER_URL: https://dev.lauf-fuer-kaya.de/mailer
MAILER_KEY: asdasd
# APP_PORT: 4010

View File

@@ -1,3 +1,32 @@
# @node-rs/argon2
**Author**: undefined
**Repo**: [object Object]
**License**: MIT
**Description**: RustCrypto: Argon2 binding for Node.js
## License Text
MIT License
Copyright (c) 2020-present LongYinan
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.
# @odit/class-validator-jsonschema
**Author**: Aleksi Pekkala <aleksipekkala@gmail.com>
**Repo**: git@github.com:epiphone/class-validator-jsonschema.git
@@ -27,36 +56,6 @@ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.
# argon2
**Author**: Ranieri Althoff <ranisalt+argon2@gmail.com>
**Repo**: [object Object]
**License**: MIT
**Description**: An Argon2 library for Node
## License Text
The MIT License (MIT)
Copyright (c) 2015 Ranieri Althoff
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.
# axios
**Author**: Matt Zabriskie
**Repo**: [object Object]

View File

@@ -1,11 +1,8 @@
{
"name": "@odit/lfk-backend",
"version": "1.2.1",
"version": "1.3.5",
"main": "src/app.ts",
"repository": "https://git.odit.services/lfk/backend",
"engines": {
"pnpm": "8"
},
"author": {
"name": "ODIT.Services",
"email": "info@odit.services",
@@ -25,8 +22,8 @@
],
"license": "CC-BY-NC-SA-4.0",
"dependencies": {
"@node-rs/argon2": "^2.0.2",
"@odit/class-validator-jsonschema": "2.1.1",
"argon2": "0.31.2",
"axios": "0.21.1",
"body-parser": "1.19.0",
"check-password-strength": "2.0.2",
@@ -46,7 +43,7 @@
"reflect-metadata": "0.1.13",
"routing-controllers": "0.9.0-alpha.6",
"routing-controllers-openapi": "2.2.0",
"sqlite3": "5.1.6",
"sqlite3": "5.1.7",
"typeorm": "0.2.30",
"typeorm-routing-controllers-extensions": "0.2.0",
"typeorm-seeding": "1.6.1",
@@ -94,12 +91,12 @@
"git": {
"commit": true,
"requireCleanWorkingDir": false,
"commitMessage": "🚀Bumped version to v${version}",
"commitMessage": "chore(release): ${version}",
"requireBranch": "dev",
"push": true,
"tag": true,
"tagName": "v${version}",
"tagAnnotation": "v${version}"
"tagName": "${version}",
"tagAnnotation": "${version}"
},
"npm": {
"publish": false
@@ -114,4 +111,4 @@
"docs/*"
]
}
}
}

10304
pnpm-lock.yaml generated

File diff suppressed because it is too large Load Diff

2
pnpm-workspace.yaml Normal file
View File

@@ -0,0 +1,2 @@
onlyBuiltDependencies:
- sqlite3

View File

@@ -30,7 +30,7 @@ export class RunnerController {
@Authorized("RUNNER:GET")
@ResponseSchema(ResponseRunner, { isArray: true })
@OpenAPI({ description: 'Lists all runners from all teams/orgs. <br> This includes the runner\'s group and distance ran.' })
async getAll(@QueryParam("page", { required: false }) page: number, @QueryParam("page_size", { required: false }) page_size: number = 100) {
async getAll(@QueryParam("page", { required: false }) page: number, @QueryParam("page_size", { required: false }) page_size: number = 100, @QueryParam("selfservice_links", { required: false }) selfservice_links: boolean = false) {
let responseRunners: ResponseRunner[] = new Array<ResponseRunner>();
let runners: Array<Runner>;
@@ -41,7 +41,7 @@ export class RunnerController {
}
runners.forEach(runner => {
responseRunners.push(new ResponseRunner(runner));
responseRunners.push(new ResponseRunner(runner, selfservice_links));
});
return responseRunners;
}
@@ -55,7 +55,7 @@ export class RunnerController {
async getOne(@Param('id') id: number) {
let runner = await this.runnerRepository.findOne({ id: id }, { relations: ['scans', 'group', 'group.parentGroup', 'scans.track', 'cards'] })
if (!runner) { throw new RunnerNotFoundError(); }
return new ResponseRunner(runner);
return new ResponseRunner(runner, true);
}
@Get('/:id/scans')
@@ -98,7 +98,7 @@ export class RunnerController {
}
runner = await this.runnerRepository.save(runner)
return new ResponseRunner(await this.runnerRepository.findOne(runner, { relations: ['scans', 'group', 'group.parentGroup', 'scans.track', 'cards'] }));
return new ResponseRunner(await this.runnerRepository.findOne(runner, { relations: ['scans', 'group', 'group.parentGroup', 'scans.track', 'cards'] }), true);
}
@Put('/:id')
@@ -119,7 +119,7 @@ export class RunnerController {
}
await this.runnerRepository.save(await runner.update(oldRunner));
return new ResponseRunner(await this.runnerRepository.findOne({ id: id }, { relations: ['scans', 'group', 'group.parentGroup', 'scans.track', 'cards'] }));
return new ResponseRunner(await this.runnerRepository.findOne({ id: id }, { relations: ['scans', 'group', 'group.parentGroup', 'scans.track', 'cards'] }), true);
}
@Delete('/:id')
@@ -132,7 +132,7 @@ export class RunnerController {
async remove(@Param("id") id: number, @QueryParam("force") force: boolean) {
let runner = await this.runnerRepository.findOne({ id: id });
if (!runner) { return null; }
const responseRunner = await this.runnerRepository.findOne(runner, { relations: ['scans', 'group', 'group.parentGroup', 'scans.track', 'cards'] });
const responseRunner = await this.runnerRepository.findOne(runner);
if (!runner) {
throw new RunnerNotFoundError();

View File

@@ -119,7 +119,7 @@ export class RunnerTeamController {
async remove(@Param("id") id: number, @QueryParam("force") force: boolean) {
let team = await this.runnerTeamRepository.findOne({ id: id });
if (!team) { return null; }
let runnerTeam = await this.runnerTeamRepository.findOne(team, { relations: ['parentGroup', 'contact', 'runners'] });
let runnerTeam = await this.runnerTeamRepository.findOne(team, { relations: ['runners'] });
if (!force) {
if (runnerTeam.runners.length != 0) {

View File

@@ -23,6 +23,7 @@ export class StatsController {
@OpenAPI({ description: "A very basic stats endpoint providing basic counters for a dashboard or simmilar" })
async get() {
const connection = getConnection();
const runnersViaSelfservice = await connection.getRepository(Runner).count({ where: { created_via: "selfservice" } });
const runners = await connection.getRepository(Runner).count();
const teams = await connection.getRepository(RunnerTeam).count();
const orgs = await connection.getRepository(RunnerOrganization).count();
@@ -41,7 +42,7 @@ export class StatsController {
let donations = await connection.getRepository(Donation).find({ relations: ['runner', 'runner.scans', 'runner.scans.track'] });
const donors = await connection.getRepository(Donor).count();
return new ResponseStats(runners, teams, orgs, users, scans, donations, distace, donors)
return new ResponseStats(runnersViaSelfservice, runners, teams, orgs, users, scans, donations, distace, donors)
}
@Get("/runners/distance")

View File

@@ -1,4 +1,4 @@
import * as argon2 from "argon2";
import { verify } from '@node-rs/argon2';
import { Request, Response } from 'express';
import { getConnectionManager } from 'typeorm';
import { ScanStation } from '../models/entities/ScanStation';
@@ -58,7 +58,7 @@ const ScanAuth = async (req: Request, res: Response, next: () => void) => {
if (station.enabled == false) {
res.status(401).send({ http_code: 401, short: "station_disabled", message: "Station is disabled." });
}
if (!(await argon2.verify(station.key, provided_token))) {
if (!(await verify(station.key, provided_token))) {
res.status(401).send({ http_code: 401, short: "invalid_token", message: "Api token non-existent or invalid syntax." });
return;
}

View File

@@ -1,4 +1,4 @@
import * as argon2 from "argon2";
import { verify } from '@node-rs/argon2';
import { Request, Response } from 'express';
import { getConnectionManager } from 'typeorm';
import { StatsClient } from '../models/entities/StatsClient';
@@ -55,7 +55,7 @@ const StatsAuth = async (req: Request, res: Response, next: () => void) => {
}
}
else {
if (!(await argon2.verify(client.key, provided_token))) {
if (!(await verify(client.key, provided_token))) {
res.status(401).send("Api token invalid.");
return;
}

View File

@@ -1,4 +1,4 @@
import * as argon2 from "argon2";
import { hash } from '@node-rs/argon2';
import { IsNotEmpty, IsOptional, IsString } from 'class-validator';
import * as jsonwebtoken from 'jsonwebtoken';
import { getConnectionManager } from 'typeorm';
@@ -49,7 +49,7 @@ export class ResetPassword {
if (found_user.refreshTokenCount !== decoded["refreshTokenCount"]) { throw new RefreshTokenCountInvalidError(); }
found_user.refreshTokenCount = found_user.refreshTokenCount + 1;
found_user.password = await argon2.hash(this.password + found_user.uuid);
found_user.password = await hash(this.password + found_user.uuid);
await getConnectionManager().get().getRepository(User).save(found_user);
return "password reset successfull";

View File

@@ -1,4 +1,4 @@
import * as argon2 from "argon2";
import { verify } from '@node-rs/argon2';
import { IsEmail, IsNotEmpty, IsOptional, IsString } from 'class-validator';
import { getConnectionManager } from 'typeorm';
import { InvalidCredentialsError, PasswordNeededError, UserDisabledError, UserNotFoundError } from '../../../errors/AuthError';
@@ -56,7 +56,7 @@ export class CreateAuth {
throw new UserNotFoundError();
}
if (found_user.enabled == false) { throw new UserDisabledError(); }
if (!(await argon2.verify(found_user.password, this.password + found_user.uuid))) {
if (!(await verify(found_user.password, this.password + found_user.uuid))) {
throw new InvalidCredentialsError();
}

View File

@@ -1,4 +1,4 @@
import * as argon2 from "argon2";
import { hash } from '@node-rs/argon2';
import { IsBoolean, IsInt, IsOptional, IsPositive, IsString } from 'class-validator';
import crypto from 'crypto';
import { getConnection } from 'typeorm';
@@ -44,7 +44,7 @@ export class CreateScanStation {
let newUUID = uuid.v4().toUpperCase();
newStation.prefix = crypto.createHash("sha3-512").update(newUUID).digest('hex').substring(0, 7).toUpperCase();
newStation.key = await argon2.hash(newStation.prefix + "." + newUUID);
newStation.key = await hash(newStation.prefix + "." + newUUID);
newStation.cleartextkey = newStation.prefix + "." + newUUID;
return newStation;

View File

@@ -26,6 +26,7 @@ export class CreateSelfServiceCitizenRunner extends CreateParticipant {
public async toEntity(): Promise<Runner> {
let newRunner: Runner = new Runner();
newRunner.created_via = "selfservice";
newRunner.firstname = this.firstname;
newRunner.middlename = this.middlename;
newRunner.lastname = this.lastname;

View File

@@ -28,6 +28,7 @@ export class CreateSelfServiceRunner extends CreateParticipant {
public async toEntity(group: RunnerGroup): Promise<Runner> {
let newRunner: Runner = new Runner();
newRunner.created_via = "selfservice";
newRunner.firstname = this.firstname;
newRunner.middlename = this.middlename;
newRunner.lastname = this.lastname;

View File

@@ -1,4 +1,4 @@
import * as argon2 from "argon2";
import { hash } from '@node-rs/argon2';
import { IsOptional, IsString } from 'class-validator';
import crypto from 'crypto';
import * as uuid from 'uuid';
@@ -25,7 +25,7 @@ export class CreateStatsClient {
let newUUID = uuid.v4().toUpperCase();
newClient.prefix = crypto.createHash("sha3-512").update(newUUID).digest('hex').substring(0, 7).toUpperCase();
newClient.key = await argon2.hash(newClient.prefix + "." + newUUID);
newClient.key = await hash(newClient.prefix + "." + newUUID);
newClient.cleartextkey = newClient.prefix + "." + newUUID;
return newClient;

View File

@@ -1,4 +1,4 @@
import * as argon2 from "argon2";
import { hash } from "@node-rs/argon2";
import { passwordStrength } from "check-password-strength";
import { IsBoolean, IsEmail, IsNotEmpty, IsOptional, IsPhoneNumber, IsString, IsUrl } from 'class-validator';
import { getConnectionManager } from 'typeorm';
@@ -110,7 +110,7 @@ export class CreateUser {
newUser.lastname = this.lastname
newUser.uuid = uuid.v4()
newUser.phone = this.phone
newUser.password = await argon2.hash(this.password + newUser.uuid);
newUser.password = await hash(this.password + newUser.uuid);
newUser.groups = await this.getGroups();
newUser.enabled = this.enabled;

View File

@@ -1,4 +1,4 @@
import * as argon2 from "argon2";
import { hash } from '@node-rs/argon2';
import { passwordStrength } from "check-password-strength";
import { IsBoolean, IsEmail, IsInt, IsNotEmpty, IsOptional, IsPhoneNumber, IsString, IsUrl } from 'class-validator';
import { getConnectionManager } from 'typeorm';
@@ -111,7 +111,7 @@ export class UpdateUser {
if (!password_strength.contains.includes("lowercase")) { throw new PasswordMustContainLowercaseLetterError(); }
if (!password_strength.contains.includes("number")) { throw new PasswordMustContainNumberError(); }
if (!(password_strength.length > 9)) { throw new PasswordTooShortError(); }
user.password = await argon2.hash(this.password + user.uuid);
user.password = await hash(this.password + user.uuid);
user.refreshTokenCount = user.refreshTokenCount + 1;
}

View File

@@ -75,6 +75,14 @@ export abstract class Participant {
@IsEmail()
email?: string;
/**
* how the participant got into the system
*/
@Column({ nullable: true, default: "backend" })
@IsOptional()
@IsEmail()
created_via?: string;
/**
* Turns this entity into it's response class.
*/

View File

@@ -57,7 +57,10 @@ export class Runner extends Participant {
* This is implemented here to avoid duplicate code in other files.
*/
public get validScans(): Scan[] {
return this.scans.filter(scan => scan.valid == true);
if (this.scans) {
return this.scans.filter(scan => scan.valid == true);
}
return []
}
/**

View File

@@ -50,6 +50,12 @@ export abstract class ResponseParticipant implements IResponse {
@IsString()
email?: string;
/**
* how the participant got into the system
*/
@IsString()
created_via?: string;
/**
* The participant's address.
*/
@@ -64,6 +70,7 @@ export abstract class ResponseParticipant implements IResponse {
public constructor(participant: Participant) {
this.id = participant.id;
this.firstname = participant.firstname;
this.created_via = participant.created_via;
this.middlename = participant.middlename;
this.lastname = participant.lastname;
this.phone = participant.phone;

View File

@@ -1,7 +1,10 @@
import {
IsInt,
IsObject
IsObject,
IsOptional,
IsString
} from "class-validator";
import { JwtCreator } from '../../jwtcreator';
import { Runner } from '../entities/Runner';
import { ResponseObjectType } from '../enums/ResponseObjectType';
import { IResponse } from './IResponse';
@@ -30,14 +33,26 @@ export class ResponseRunner extends ResponseParticipant implements IResponse {
@IsObject()
group: ResponseRunnerGroup;
/**
* A selfservice link for our new runner.
*/
@IsOptional()
@IsString()
selfserviceLink: string;
/**
* Creates a ResponseRunner object from a runner.
* @param runner The user the response shall be build for.
*/
public constructor(runner: Runner) {
public constructor(runner: Runner, generateSelfServiceLink: boolean = false) {
super(runner);
if (!runner.scans) { this.distance = 0 }
else { this.distance = runner.validScans.reduce((sum, current) => sum + current.distance, 0); }
if (runner.group) { this.group = runner.group.toResponse(); }
if (generateSelfServiceLink) {
const token = JwtCreator.createSelfService(runner);
this.selfserviceLink = `${process.env.SELFSERVICE_URL}/profile/${token}`;
}
}
}

View File

@@ -16,6 +16,12 @@ export class ResponseStats implements IResponse {
*/
responseType: ResponseObjectType = ResponseObjectType.STATS;
/**
* The amount of runners registered via selfservice.
*/
@IsInt()
runnersViaSelfservice: number;
/**
* The amount of runners registered in the system.
*/
@@ -84,14 +90,16 @@ export class ResponseStats implements IResponse {
/**
* Creates a new stats response containing some basic statistics for a dashboard or public display.
* @param runners Array containing all runners - the following relations have to be resolved: scans, scans.track
* @param teams Array containing all teams - no relations have to be resolved.
* @param orgs Array containing all orgs - no relations have to be resolved.
* @param users Array containing all users - no relations have to be resolved.
* @param scans Array containing all scans - no relations have to be resolved.
* @param runnersViaSelfservice number of runners registered via selfservice
* @param runners number of runners
* @param teams number of teams - no relations have to be resolved.
* @param orgs number of orgs - no relations have to be resolved.
* @param users number of users - no relations have to be resolved.
* @param scans number of scans - no relations have to be resolved.
* @param donations Array containing all donations - the following relations have to be resolved: runner, runner.scans, runner.scans.track
*/
public constructor(runners: number, teams: number, orgs: number, users: number, scans: number, donations: Donation[], distance: number, donors: number) {
public constructor(runnersViaSelfservice: number, runners: number, teams: number, orgs: number, users: number, scans: number, donations: Donation[], distance: number, donors: number) {
this.runnersViaSelfservice = runnersViaSelfservice;
this.total_runners = runners;
this.total_teams = teams;
this.total_orgs = orgs;

View File

@@ -1,4 +1,4 @@
import * as argon2 from "argon2";
import { hash } from '@node-rs/argon2';
import { Connection } from 'typeorm';
import { Factory, Seeder } from 'typeorm-seeding';
import * as uuid from 'uuid';
@@ -33,7 +33,7 @@ export default class SeedUsers implements Seeder {
initialUser.lastname = "demo";
initialUser.username = "demo";
initialUser.uuid = uuid.v4();
initialUser.password = await argon2.hash("demo" + initialUser.uuid);
initialUser.password = await hash("demo" + initialUser.uuid);
initialUser.email = "demo@dev.lauf-fuer-kaya.de"
initialUser.groups = [group];
return await connection.getRepository(User).save(initialUser);