Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

WIP: Feature/login history #340

Open
wants to merge 11 commits into
base: main
Choose a base branch
from
1 change: 1 addition & 0 deletions packages/nestjs-auth-apple/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@
"dependencies": {
"@concepta/nestjs-authentication": "^6.0.0-alpha.1",
"@concepta/nestjs-common": "^6.0.0-alpha.1",
"@concepta/nestjs-event": "^6.0.0-alpha.1",
"@concepta/nestjs-exception": "^6.0.0-alpha.1",
"@concepta/nestjs-federated": "^6.0.0-alpha.1",
"@concepta/nestjs-jwt": "^6.0.0-alpha.1",
Expand Down
2 changes: 2 additions & 0 deletions packages/nestjs-auth-apple/src/auth-apple.constants.ts
Original file line number Diff line number Diff line change
Expand Up @@ -18,3 +18,5 @@ export const AUTH_APPLE_VERIFY_ALGORITHM = 'RS256';
export const AUTH_APPLE_TOKEN_ISSUER = 'https://appleid.apple.com';

export const AUTH_APPLE_JWT_KEYS = 'https://appleid.apple.com/auth/keys';

export const AUTH_APPLE_AUTHENTICATION_TYPE = 'auth-apple';
35 changes: 33 additions & 2 deletions packages/nestjs-auth-apple/src/auth-apple.controller.ts
Original file line number Diff line number Diff line change
@@ -1,17 +1,24 @@
import { Controller, Inject, Get, UseGuards, Post } from '@nestjs/common';
import { ApiOkResponse, ApiTags } from '@nestjs/swagger';
import {
AuthenticatedEventInterface,
AuthenticatedUserInterface,
AuthenticationResponseInterface,
AuthenticatedUserInfoInterface,
AuthInfo,
} from '@concepta/nestjs-common';
import {
AuthUser,
IssueTokenServiceInterface,
AuthenticationJwtResponseDto,
AuthPublic,
} from '@concepta/nestjs-authentication';
import { AUTH_APPLE_ISSUE_TOKEN_SERVICE_TOKEN } from './auth-apple.constants';
import {
AUTH_APPLE_AUTHENTICATION_TYPE,
AUTH_APPLE_ISSUE_TOKEN_SERVICE_TOKEN,
} from './auth-apple.constants';
import { AuthAppleGuard } from './auth-apple.guard';
import { AuthAppleAuthenticatedEventAsync } from './events/auth-apple-authenticated.event';

/**
* Apple controller
Expand Down Expand Up @@ -57,7 +64,31 @@ export class AuthAppleController {
@Post('callback')
async post(
@AuthUser() user: AuthenticatedUserInterface,
@AuthInfo() authInfo: AuthenticatedUserInfoInterface,
): Promise<AuthenticationResponseInterface> {
return this.issueTokenService.responsePayload(user.id);
const response = this.issueTokenService.responsePayload(user.id);

await this.dispatchAuthenticatedEvent({
userInfo: {
userId: user.id,
ipAddress: authInfo?.ipAddress || '',
deviceInfo: authInfo?.deviceInfo || '',
authType: AUTH_APPLE_AUTHENTICATION_TYPE,
},
});

return response;
}

protected async dispatchAuthenticatedEvent(
payload?: AuthenticatedEventInterface,
): Promise<boolean> {
const authenticatedEventAsync = new AuthAppleAuthenticatedEventAsync(
payload,
);

const eventResult = await authenticatedEventAsync.emit();

return eventResult.every((it) => it === true);
}
}
2 changes: 2 additions & 0 deletions packages/nestjs-auth-apple/src/auth-apple.module.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@ import { AuthAppleModule } from './auth-apple.module';

import { FederatedEntityFixture } from './__fixtures__/federated-entity.fixture';
import { UserEntityFixture } from './__fixtures__/user.entity.fixture';
import { EventModule } from '@concepta/nestjs-event';

describe(AuthAppleModule, () => {
let authAppleModule: AuthAppleModule;
Expand All @@ -31,6 +32,7 @@ describe(AuthAppleModule, () => {
entities: [UserEntityFixture, FederatedEntityFixture],
}),
JwtModule.forRoot({}),
EventModule.forRoot({}),
AuthAppleModule.forRoot({}),
AuthenticationModule.forRoot({}),
AuthJwtModule.forRootAsync({
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
import { AuthenticatedEventInterface } from '@concepta/nestjs-common';
import { EventAsync } from '@concepta/nestjs-event';

export class AuthAppleAuthenticatedEventAsync extends EventAsync<
AuthenticatedEventInterface,
boolean
> {}
1 change: 1 addition & 0 deletions packages/nestjs-auth-github/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@
"dependencies": {
"@concepta/nestjs-authentication": "^6.0.0-alpha.1",
"@concepta/nestjs-common": "^6.0.0-alpha.1",
"@concepta/nestjs-event": "^6.0.0-alpha.1",
"@concepta/nestjs-exception": "^6.0.0-alpha.1",
"@concepta/nestjs-federated": "^6.0.0-alpha.1",
"@nestjs/common": "^10.4.1",
Expand Down
2 changes: 2 additions & 0 deletions packages/nestjs-auth-github/src/auth-github.constants.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8,3 +8,5 @@ export const AUTH_GITHUB_MODULE_DEFAULT_SETTINGS_TOKEN =
'AUTH_GITHUB_MODULE_DEFAULT_SETTINGS_TOKEN';

export const AUTH_GITHUB_STRATEGY_NAME = 'github';

export const AUTH_GITHUB_AUTHENTICATION_TYPE = 'auth-github';
35 changes: 33 additions & 2 deletions packages/nestjs-auth-github/src/auth-github.controller.ts
Original file line number Diff line number Diff line change
@@ -1,17 +1,24 @@
import { Controller, Inject, Get, UseGuards } from '@nestjs/common';
import { ApiOkResponse, ApiTags } from '@nestjs/swagger';
import {
AuthenticatedEventInterface,
AuthenticatedUserInfoInterface,
AuthenticatedUserInterface,
AuthenticationResponseInterface,
AuthInfo,
} from '@concepta/nestjs-common';
import {
AuthUser,
IssueTokenServiceInterface,
AuthenticationJwtResponseDto,
AuthPublic,
} from '@concepta/nestjs-authentication';
import { AUTH_GITHUB_ISSUE_TOKEN_SERVICE_TOKEN } from './auth-github.constants';
import {
AUTH_GITHUB_AUTHENTICATION_TYPE,
AUTH_GITHUB_ISSUE_TOKEN_SERVICE_TOKEN,
} from './auth-github.constants';
import { AuthGithubGuard } from './auth-github.guard';
import { AuthGithubAuthenticatedEventAsync } from './events/auth-github-authenticated.event';

// TODO: improve documentation
/**
Expand Down Expand Up @@ -59,7 +66,31 @@ export class AuthGithubController {
@Get('callback')
async get(
@AuthUser() user: AuthenticatedUserInterface,
@AuthInfo() authInfo: AuthenticatedUserInfoInterface,
): Promise<AuthenticationResponseInterface> {
return this.issueTokenService.responsePayload(user.id);
const response = this.issueTokenService.responsePayload(user.id);

await this.dispatchAuthenticatedEvent({
userInfo: {
userId: user.id,
ipAddress: authInfo?.ipAddress || '',
deviceInfo: authInfo?.deviceInfo || '',
authType: AUTH_GITHUB_AUTHENTICATION_TYPE,
},
});

return response;
}

protected async dispatchAuthenticatedEvent(
payload?: AuthenticatedEventInterface,
): Promise<boolean> {
const authenticatedEventAsync = new AuthGithubAuthenticatedEventAsync(
payload,
);

const eventResult = await authenticatedEventAsync.emit();

return eventResult.every((it) => it === true);
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
import { AuthenticatedEventInterface } from '@concepta/nestjs-common';
import { EventAsync } from '@concepta/nestjs-event';

export class AuthGithubAuthenticatedEventAsync extends EventAsync<
AuthenticatedEventInterface,
boolean
> {}
1 change: 1 addition & 0 deletions packages/nestjs-auth-google/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@
"dependencies": {
"@concepta/nestjs-authentication": "^6.0.0-alpha.1",
"@concepta/nestjs-common": "^6.0.0-alpha.1",
"@concepta/nestjs-event": "^6.0.0-alpha.1",
"@concepta/nestjs-exception": "^6.0.0-alpha.1",
"@concepta/nestjs-federated": "^6.0.0-alpha.1",
"@nestjs/common": "^10.4.1",
Expand Down
2 changes: 2 additions & 0 deletions packages/nestjs-auth-google/src/auth-google.constants.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8,3 +8,5 @@ export const AUTH_GOOGLE_MODULE_DEFAULT_SETTINGS_TOKEN =
'AUTH_GOOGLE_MODULE_DEFAULT_SETTINGS_TOKEN';

export const AUTH_GOOGLE_STRATEGY_NAME = 'google';

export const AUTH_GOOGLE_AUTHENTICATION_TYPE = 'auth-google';
35 changes: 33 additions & 2 deletions packages/nestjs-auth-google/src/auth-google.controller.ts
Original file line number Diff line number Diff line change
@@ -1,17 +1,24 @@
import { Controller, Inject, Get, UseGuards } from '@nestjs/common';
import { ApiOkResponse, ApiTags } from '@nestjs/swagger';
import {
AuthenticatedEventInterface,
AuthenticatedUserInfoInterface,
AuthenticatedUserInterface,
AuthenticationResponseInterface,
AuthInfo,
} from '@concepta/nestjs-common';
import {
AuthUser,
IssueTokenServiceInterface,
AuthenticationJwtResponseDto,
AuthPublic,
} from '@concepta/nestjs-authentication';
import { AUTH_GOOGLE_ISSUE_TOKEN_SERVICE_TOKEN } from './auth-google.constants';
import {
AUTH_GOOGLE_AUTHENTICATION_TYPE,
AUTH_GOOGLE_ISSUE_TOKEN_SERVICE_TOKEN,
} from './auth-google.constants';
import { AuthGoogleGuard } from './auth-google.guard';
import { AuthGoogleAuthenticatedEventAsync } from './events/auth-google-authenticated.event';

/**
* Google controller
Expand Down Expand Up @@ -57,7 +64,31 @@ export class AuthGoogleController {
@Get('callback')
async get(
@AuthUser() user: AuthenticatedUserInterface,
@AuthInfo() authInfo: AuthenticatedUserInfoInterface,
): Promise<AuthenticationResponseInterface> {
return this.issueTokenService.responsePayload(user.id);
const response = this.issueTokenService.responsePayload(user.id);

await this.dispatchAuthenticatedEvent({
userInfo: {
userId: user.id,
ipAddress: authInfo?.ipAddress || '',
deviceInfo: authInfo?.deviceInfo || '',
authType: AUTH_GOOGLE_AUTHENTICATION_TYPE,
},
});

return response;
}

protected async dispatchAuthenticatedEvent(
payload?: AuthenticatedEventInterface,
): Promise<boolean> {
const authenticatedEventAsync = new AuthGoogleAuthenticatedEventAsync(
payload,
);

const eventResult = await authenticatedEventAsync.emit();

return eventResult.every((it) => it === true);
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
import { AuthenticatedEventInterface } from '@concepta/nestjs-common';
import { EventAsync } from '@concepta/nestjs-event';

export class AuthGoogleAuthenticatedEventAsync extends EventAsync<
AuthenticatedEventInterface,
boolean
> {}
18 changes: 18 additions & 0 deletions packages/nestjs-auth-history/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
# Rockets NestJS Auth History

A module for tracking authentication history and events, providing services
for creating, reading, updating and deleting auth history records. Includes
event handling for authenticated requests, repository management, and access
control.

## Project

[![NPM Latest](https://img.shields.io/npm/v/@concepta/nestjs-auth-history)](https://www.npmjs.com/package/@concepta/nestjs-auth-history)
[![NPM Downloads](https://img.shields.io/npm/dw/@conceptadev/nestjs-auth-history)](https://www.npmjs.com/package/@concepta/nestjs-auth-history)
[![GH Last Commit](https://img.shields.io/github/last-commit/conceptadev/rockets?logo=github)](https://github.com/conceptadev/rockets)
[![GH Contrib](https://img.shields.io/github/contributors/conceptadev/rockets?logo=github)](https://github.com/conceptadev/rockets/graphs/contributors)
[![NestJS Dep](https://img.shields.io/github/package-json/dependency-version/conceptadev/rockets/@nestjs/common?label=NestJS&logo=nestjs&filename=packages%2Fnestjs-core%2Fpackage.json)](https://www.npmjs.com/package/@nestjs/common)

## Installation

`yarn add @concepta/nestjs-auth-history`
46 changes: 46 additions & 0 deletions packages/nestjs-auth-history/package.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,46 @@
{
"name": "@concepta/nestjs-auth-history",
"version": "6.0.0-alpha.1",
"description": "Rockets NestJS auth history",
"main": "dist/index.js",
"types": "dist/index.d.ts",
"license": "BSD-3-Clause",
"publishConfig": {
"access": "public"
},
"files": [
"dist/**/!(*.spec|*.e2e-spec|*.fixture).{js,d.ts}"
],
"dependencies": {
"@concepta/nestjs-access-control": "^6.0.0-alpha.1",
"@concepta/nestjs-common": "^6.0.0-alpha.1",
"@concepta/nestjs-crud": "^6.0.0-alpha.1",
"@concepta/nestjs-event": "^6.0.0-alpha.1",
"@concepta/nestjs-exception": "^6.0.0-alpha.1",
"@concepta/nestjs-password": "^6.0.0-alpha.1",
"@concepta/nestjs-typeorm-ext": "^6.0.0-alpha.1",
"@concepta/typeorm-common": "^6.0.0-alpha.1",
"@nestjs/common": "^10.4.1",
"@nestjs/config": "^3.2.3",
"@nestjs/core": "^10.4.1",
"@nestjs/swagger": "^7.4.0"
},
"devDependencies": {
"@concepta/nestjs-auth-jwt": "^6.0.0-alpha.1",
"@concepta/nestjs-authentication": "^6.0.0-alpha.1",
"@concepta/nestjs-jwt": "^6.0.0-alpha.1",
"@concepta/nestjs-user": "^6.0.0-alpha.1",
"@concepta/typeorm-seeding": "^4.0.0",
"@faker-js/faker": "^8.4.1",
"@nestjs/testing": "^10.4.1",
"@nestjs/typeorm": "^10.0.2",
"accesscontrol": "^2.2.1",
"supertest": "^6.3.4"
},
"peerDependencies": {
"@concepta/nestjs-auth-local": "^6.0.0-alpha.1",
"class-transformer": "*",
"class-validator": "*",
"typeorm": "^0.3.0"
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,61 @@
import { AccessControlModule } from '@concepta/nestjs-access-control';
import {
AuthLocalAuthenticatedEventAsync,
AuthLocalModule,
} from '@concepta/nestjs-auth-local';
import { CrudModule } from '@concepta/nestjs-crud';
import { EventModule } from '@concepta/nestjs-event';
import { TypeOrmExtModule } from '@concepta/nestjs-typeorm-ext';
import { Module } from '@nestjs/common';
import { AccessControl } from 'accesscontrol';

import { AuthHistoryModule } from '../auth-history.module';
import { AuthHistoryResource } from '../auth-history.types';

import { AuthenticationModule } from '@concepta/nestjs-authentication';
import { JwtModule } from '@concepta/nestjs-jwt';
import { AuthHistoryAccessQueryService } from '../services/auth-history-query.service';
import { AuthHistoryEntityFixture } from './entities/auth-history.entity.fixture';
import { ormConfig } from './ormconfig.fixture';
import { UserLookupServiceFixture } from './services/user-lookup.service.fixture';
import { ValidateUserServiceFixture } from './services/validate-user.service.fixture';

const rules = new AccessControl();
rules
.grant('auth-history')
.resource(AuthHistoryResource.One)
.createOwn()
.readOwn()
.updateOwn()
.deleteOwn();

@Module({
imports: [
TypeOrmExtModule.forRoot(ormConfig),
CrudModule.forRoot({}),
EventModule.forRoot({}),
JwtModule.forRoot({}),
AuthenticationModule.forRoot({}),
AccessControlModule.forRoot({
settings: { rules },
queryServices: [AuthHistoryAccessQueryService],
}),
AuthLocalModule.forRootAsync({
useFactory: () => ({
userLookupService: new UserLookupServiceFixture(),
validateUserService: new ValidateUserServiceFixture(),
}),
}),
AuthHistoryModule.forRoot({
settings: {
authenticatedEvents: [AuthLocalAuthenticatedEventAsync],
},
entities: {
authHistory: {
entity: AuthHistoryEntityFixture,
},
},
}),
],
})
export class AppModuleFixture {}
Loading
Loading