Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
16,762 changes: 11,056 additions & 5,706 deletions package-lock.json

Large diffs are not rendered by default.

11,081 changes: 0 additions & 11,081 deletions package-lock_BACKUP_772.json

This file was deleted.

11,242 changes: 0 additions & 11,242 deletions package-lock_BASE_772.json

This file was deleted.

11,101 changes: 0 additions & 11,101 deletions package-lock_LOCAL_772.json

This file was deleted.

11,216 changes: 0 additions & 11,216 deletions package-lock_REMOTE_772.json

This file was deleted.

111 changes: 52 additions & 59 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -30,99 +30,92 @@
},
"dependencies": {
"@chirpstack/chirpstack-api": "4.6.0",
"@grpc/grpc-js": "^1.9.13",
"@nestjs/axios": "^3.0.2",
"@nestjs/common": "^9.1.2",
"@nestjs/config": "^2.2.0",
"@nestjs/core": "^9.4.3",
"@nestjs/jwt": "^9.0.0",
"@nestjs/mapped-types": "^1.2.2",
"@nestjs/passport": "^9.0.0",
"@nestjs/platform-express": "^9.1.2",
"@nestjs/schedule": "^2.1.0",
"@nestjs/swagger": "^6.1.2",
"@nestjs/typeorm": "^9.0.1",
"@grpc/grpc-js": "^1.14.0",
"@nestjs/axios": "^4.0.1",
"@nestjs/cache-manager": "^3.0.1",
"@nestjs/common": "^11.1.6",
"@nestjs/config": "^4.0.2",
"@nestjs/core": "^11.1.6",
"@nestjs/jwt": "^11.0.0",
"@nestjs/mapped-types": "^2.1.0",
"@nestjs/passport": "^11.0.5",
"@nestjs/platform-express": "^11.1.6",
"@nestjs/schedule": "^6.0.1",
"@nestjs/swagger": "^11.2.0",
"@nestjs/typeorm": "^11.0.0",
"@node-saml/passport-saml": "^5.1.0",
"@types/bcryptjs": "^2.4.2",
"@types/geojson": "^7946.0.13",
"@types/kafkajs": "^1.9.0",
"@types/passport-saml": "^1.1.3",
"@types/pem": "^1.9.6",
"@types/uuid": "^8.3.0",
"@types/ws": "^8.5.3",
"@types/pem": "^1.14.4",
"@types/ws": "^8.18.1",
"@types/xml2js": "^0.4.14",
"ajv": "^6.12.6",
"axios": "^1.6.1",
"axios-cache-adapter": "^2.7.3",
"ajv": "^8.17.1",
"axios": "^1.12.2",
"axios-cache-interceptor": "^1.8.3",
"bcryptjs": "^2.4.3",
"bluebird": "^3.7.2",
"cache-manager": "^4.0.1",
"class-transformer": "^0.5.1",
"class-validator": "^0.14.0",
"compression": "^1.7.4",
"cookie-parser": "^1.4.5",
"class-validator": "^0.14.2",
"compression": "^1.8.1",
"cookie-parser": "^1.4.7",
"crypto-js": "^4.2.0",
"dayjs": "^1.11.13",
"dayjs": "^1.11.18",
"helmet": "^8.1.0",
"kafkajs": "^2.2.4",
"lodash": "^4.17.20",
"mqtt": "^4.3.7",
"lodash": "^4.17.21",
"mqtt": "^5.14.1",
"njwt": "^1.0.0",
"nodemailer": "^6.7.2",
"passport": "^0.6.0",
"nodemailer": "^7.0.9",
"passport": "^0.7.0",
"passport-headerapikey": "^1.2.2",
"passport-jwt": "^4.0.0",
"passport-jwt": "^4.0.1",
"passport-local": "^1.0.0",
"passport-saml": "^3.2.4",
"pem": "^1.14.7",
"pg": "^8.5.1",
"protobufjs": "^6.11.4",
"reflect-metadata": "^0.1.13",
"rimraf": "^3.0.2",
"rxjs": "^7.5.7",
"swagger-ui-express": "^4.1.5",
"typeorm": "^0.3.10",
"uuid": "^8.3.2",
"pem": "^1.14.8",
"pg": "^8.16.3",
"protobufjs": "^7.5.4",
"reflect-metadata": "^0.2.2",
"rimraf": "^6.0.1",
"rxjs": "^7.8.2",
"swagger-ui-express": "^5.0.1",
"typeorm": "^0.3.27",
"uuid": "^13.0.0",
"wait-for-expect": "^3.0.2"
},
"devDependencies": {
"@nestjs/cli": "^9.3.0",
"@nestjs/testing": "^9.1.2",
"@nestjs/cli": "^11.0.10",
"@nestjs/testing": "^11.1.6",
"@types/bcryptjs": "^2.4.2",
"@types/bluebird": "^3.5.33",
"@types/cache-manager": "^4.0.1",
"@types/compression": "^1.7.0",
"@types/cookie-parser": "^1.4.2",
"@types/cron": "^1.7.2",
"@types/crypto-js": "^4.1.1",
"@types/bluebird": "^3.5.42",
"@types/compression": "^1.8.1",
"@types/cookie-parser": "^1.4.9",
"@types/cron": "^2.4.3",
"@types/crypto-js": "^4.2.2",
"@types/express": "^4.17.9",
"@types/geojson": "^7946.0.13",
"@types/kafkajs": "^1.9.0",
"@types/lodash": "^4.14.165",
"@types/jest": "^30.0.0",
"@types/lodash": "^4.17.20",
"@types/node": "^14.14.14",
"@types/nodemailer": "^6.4.4",
"@types/passport-jwt": "^3.0.3",
"@types/passport-local": "^1.0.33",
"@types/passport-saml": "^1.1.2",
"@types/supertest": "^2.0.10",
"@types/uuid": "^8.3.0",
"@types/validator": "^13.7.1",
"@types/ws": "^8.5.3",
"@types/xml2js": "^0.4.14",
"@typescript-eslint/eslint-plugin": "^6.10.0",
"@typescript-eslint/parser": "^6.10.0",
"eslint": "^8.24.0",
"eslint-config-prettier": "^7.0.0",
"@typescript-eslint/eslint-plugin": "^8.46.0",
"@typescript-eslint/parser": "^8.46.0",
"eslint": "^9.37.0",
"eslint-config-prettier": "^10.1.8",
"jest": "^29.7.0",
"prettier": "^2.2.1",
"supertest": "^6.0.1",
"supertest": "^7.1.4",
"ts-jest": "^29.1.1",
"ts-node": "^10.9.1",
"typescript": "^4.8.3"
"typescript": "~5.4.5"
},
"overrides": {
"@babel/traverse": "^7.23.2",
"webpack": "^5.89.0",
"axios": "^1.6.1",
"xml2js": "^0.6.2",
"jsonwebtoken": "^9.0.0",
"debug": "^4.3.4",
Expand Down
47 changes: 26 additions & 21 deletions src/auth/kombit.strategy.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,32 +4,37 @@ import { ErrorCodes } from "@enum/error-codes.enum";
import { Injectable, Logger } from "@nestjs/common";
import { PassportStrategy } from "@nestjs/passport";
import { AuthService } from "@services/user-management/auth.service";
import { Profile, Strategy } from "passport-saml";
import { Strategy as SamlStrategy } from "@node-saml/passport-saml";
import { Profile } from "@node-saml/node-saml";

@Injectable()
export class KombitStrategy extends PassportStrategy(Strategy, "kombit") {
constructor(private readonly authService: AuthService) {
super({
issuer: `${configuration()["backend"]["baseurl"]}/api/v1/auth/kombit/metadata`,
audience: `${configuration()["backend"]["baseurl"]}/api/v1/auth/kombit/metadata`,
export class KombitStrategy extends PassportStrategy(SamlStrategy, "kombit") {
private readonly logger = new Logger(KombitStrategy.name);

callbackUrl: `${configuration()["backend"]["baseurl"]}/api/v1/auth/kombit/login/callback`,
logoutCallbackUrl: `${configuration()["backend"]["baseurl"]}/api/v1/auth/kombit/logout/callback`,
logoutUrl: configuration()["kombit"]["entryPoint"],
entryPoint: configuration()["kombit"]["entryPoint"],
identifierFormat: "",
cert: configuration()["kombit"]["certificatePublicKey"],
privateCert: configuration()["kombit"]["certificatePrivateKey"],
decryptionPvk: configuration()["kombit"]["certificatePrivateKey"],
signatureAlgorithm: "sha256",
disableRequestedAuthnContext: true,
authnRequestBinding: "HTTP-Redirect",
acceptedClockSkewMs: 1000, // Allow some slack in clock sync
});
constructor(private readonly authService: AuthService) {
super(
{
issuer: `${configuration()["backend"]["baseurl"]}/api/v1/auth/kombit/metadata`,
callbackUrl: `${configuration()["backend"]["baseurl"]}/api/v1/auth/kombit/login/callback`,
publicCert: configuration()["kombit"]["certificatePublicKey"],
idpCert: configuration()["kombit"]["certificatePublicKey"],
audience: `${configuration()["backend"]["baseurl"]}/api/v1/auth/kombit/metadata`,
logoutCallbackUrl: `${configuration()["backend"]["baseurl"]}/api/v1/auth/kombit/logout/callback`,
logoutUrl: configuration()["kombit"]["entryPoint"],
entryPoint: configuration()["kombit"]["entryPoint"],
identifierFormat: "",
decryptionPvk: configuration()["kombit"]["certificatePrivateKey"],
signatureAlgorithm: "sha256",
disableRequestedAuthnContext: true,
authnRequestBinding: "HTTP-Redirect",
acceptedClockSkewMs: 1000, // Allow some slack in clock sync
},
(req, profile, done) => {
return this.validate(profile, done);
}
);
}

private readonly logger = new Logger(KombitStrategy.name);

// eslint-disable-next-line @typescript-eslint/ban-types
async validate(profile: Profile, done: Function): Promise<UserResponseDto> {
try {
Expand Down
6 changes: 3 additions & 3 deletions src/config/configuration.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import { GetLogLevels, formatEmail } from "@helpers/env-variable-helper";
import { formatEmail, GetLogLevels } from "@helpers/env-variable-helper";

export default (): any => {
return {
Expand All @@ -9,7 +9,7 @@ export default (): any => {
username: process.env.DATABASE_USERNAME || "os2iot",
password: process.env.DATABASE_PASSWORD || "toi2so",
ssl: process.env.DATABASE_ENABLE_SSL === "true",
timezone: 'Z'
timezone: "Z",
},
jwt: {
secret: process.env.JWT_SECRET || "secretKey-os2iot-secretKey",
Expand All @@ -25,7 +25,7 @@ export default (): any => {
process.env.KOMBIT_ENTRYPOINT ||
"https://adgangsstyring.eksterntest-stoettesystemerne.dk/runtime/saml2/issue.idp",
certificatePublicKey: process.env.KOMBIT_CERTIFICATEPUBLICKEY || "INSERT_KOMBIT_CERT", // Public certificate from Kombit Test server
certificatePrivateKey: process.env.KOMBIT_CERTIFICATEPRIVATEKEY || null,
certificatePrivateKey: process.env.KOMBIT_CERTIFICATEPRIVATEKEY || "",
roleUri: process.env.KOMBIT_ROLE_NAME || "http://os2iot.dk/roles/usersystemrole/adgang/",
},
chirpstack: {
Expand Down
6 changes: 3 additions & 3 deletions src/controllers/user-management/auth.controller.ts
Original file line number Diff line number Diff line change
Expand Up @@ -36,23 +36,23 @@ import { KombitStrategy } from "@auth/kombit.strategy";
import { ErrorCodes } from "@enum/error-codes.enum";
import { CustomExceptionFilter } from "@auth/custom-exception-filter";
import { isOrganizationPermission } from "@helpers/security-helper";
import { RequestWithUser } from "passport-saml/lib/passport-saml/types";
import Configuration from "@config/configuration";
import { ApiAuth } from "@auth/swagger-auth-decorator";
import { RequestWithUser } from "@node-saml/passport-saml/lib/types";

@UseFilters(new CustomExceptionFilter())
@ApiTags("Auth")
@Controller("auth")
export class AuthController {
private readonly logger = new Logger(AuthController.name);

constructor(
private authService: AuthService,
private userService: UserService,
private organisationService: OrganizationService,
private strategy: KombitStrategy
) {}

private readonly logger = new Logger(AuthController.name);

@Get("kombit/login")
@ApiOperation({ summary: "Initiate login with Kombit adgangsstyring" })
@UseGuards(KombitAuthGuard)
Expand Down
8 changes: 4 additions & 4 deletions src/helpers/fiware-token.helper.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
import { HttpService } from "@nestjs/axios";
import { CACHE_MANAGER, Inject, Injectable, Logger } from "@nestjs/common";
import { Cache } from "cache-manager";
import { Inject, Injectable, Logger } from "@nestjs/common";
import { FiwareDataTargetConfiguration } from "../entities/interfaces/fiware-data-target-configuration.interface";
import { Cache, CACHE_MANAGER } from "@nestjs/cache-manager";

type TokenEndpointResponse = {
data: {
Expand Down Expand Up @@ -38,7 +38,7 @@ export class AuthenticationTokenProvider {
@Inject(CACHE_MANAGER) private cacheManager: Cache
) {}

async clearConfig(config: FiwareDataTargetConfiguration): Promise<void> {
async clearConfig(config: FiwareDataTargetConfiguration): Promise<boolean> {
if (config.clientId) {
this.logger.debug(`AuthenticationTokenProvider clearing token for ${config.clientId}`);
const key = config.clientId + config.updatedAt.getTime();
Expand Down Expand Up @@ -74,7 +74,7 @@ export class AuthenticationTokenProvider {
this.logger.debug(
`AuthenticationTokenProvider caching token for ${config.clientId} (expires in ${ttl} seconds)`
);
await this.cacheManager.set(key, data.access_token, { ttl });
await this.cacheManager.set(key, data.access_token, ttl);
return data.access_token;
} catch (err) {
this.logger.error(`AuthenticationTokenProvider got error ${err}`);
Expand Down
2 changes: 1 addition & 1 deletion src/main.ts
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ import helmet from "helmet";

async function bootstrap() {
// Load .env file as environment before startup.
dotenv.config({ path: "../.env", debug: true });
dotenv.config({ path: "./.env", debug: true });

const config = {
NEST_PORT: 3000,
Expand Down
5 changes: 3 additions & 2 deletions src/modules/data-target/data-target-fiware-sender.module.ts
Original file line number Diff line number Diff line change
@@ -1,11 +1,12 @@
import { HttpModule } from "@nestjs/axios";
import { CacheModule, Module } from "@nestjs/common";
import { Module } from "@nestjs/common";
import { FiwareDataTargetService } from "@services/data-targets/fiware-data-target.service";
import {
AuthenticationTokenProvider,
CLIENT_SECRET_PROVIDER,
PlainTextClientSecretProvider,
} from "../../helpers/fiware-token.helper";
} from "@helpers/fiware-token.helper";
import { CacheModule } from "@nestjs/cache-manager";

@Module({
imports: [HttpModule, CacheModule.register()],
Expand Down
27 changes: 12 additions & 15 deletions src/services/data-management/chirpstack-mqtt-listener.service.ts
Original file line number Diff line number Diff line change
Expand Up @@ -13,27 +13,15 @@ import { ChirpstackStateTemplatePath } from "@resources/resource-paths";
import { ReceiveDataService } from "@services/data-management/receive-data.service";
import { IoTDeviceDownlinkService } from "@services/device-management/iot-device-downlink.service";
import { IoTDeviceService } from "@services/device-management/iot-device.service";
import * as mqtt from "mqtt";
import { Client } from "mqtt";
import mqtt, { MqttClient } from "mqtt";
import * as Protobuf from "protobufjs";

@Injectable()
export class ChirpstackMQTTListenerService implements OnApplicationBootstrap {
constructor(
private receiveDataService: ReceiveDataService,
private iotDeviceService: IoTDeviceService,
private downlinkService: IoTDeviceDownlinkService
) {
const connStateFullTemplate = Protobuf.loadSync(ChirpstackStateTemplatePath);
this.connStateType = connStateFullTemplate.lookupType("ConnState");
}

MQTT_URL = `mqtt://${process.env.CS_MQTT_HOSTNAME || "localhost"}:${process.env.CS_MQTT_PORT || "1883"}`;
client: MqttClient;
private readonly logger = new Logger(ChirpstackMQTTListenerService.name);
private readonly connStateType: Protobuf.Type;

MQTT_URL = `mqtt://${process.env.CS_MQTT_HOSTNAME || "localhost"}:${process.env.CS_MQTT_PORT || "1883"}`;
client: Client;

private readonly CHIRPSTACK_MQTT_DEVICE_DATA_PREFIX = "application/";
private readonly CHIRPSTACK_MQTT_DEVICE_DATA_TOPIC = this.CHIRPSTACK_MQTT_DEVICE_DATA_PREFIX + "+/device/+/event/up";
private readonly CHIRPSTACK_MQTT_DEVICE_DATA_TXACK_TOPIC =
Expand All @@ -45,6 +33,15 @@ export class ChirpstackMQTTListenerService implements OnApplicationBootstrap {
private readonly CHIRPSTACK_MQTT_GATEWAY_PREFIX = "gateway/";
private readonly CHIRPSTACK_MQTT_GATEWAY_TOPIC = this.CHIRPSTACK_MQTT_GATEWAY_PREFIX + "+/state/conn";

constructor(
private receiveDataService: ReceiveDataService,
private iotDeviceService: IoTDeviceService,
private downlinkService: IoTDeviceDownlinkService
) {
const connStateFullTemplate = Protobuf.loadSync(ChirpstackStateTemplatePath);
this.connStateType = connStateFullTemplate.lookupType("ConnState");
}

public async onApplicationBootstrap(): Promise<void> {
this.logger.debug("Pre-init");

Expand Down
Loading
Loading