fase(9): auth module with casl rbac and session management
This commit is contained in:
35
dist/modules/auth/domain/entities/ApiKey.js
vendored
Normal file
35
dist/modules/auth/domain/entities/ApiKey.js
vendored
Normal file
@@ -0,0 +1,35 @@
|
||||
"use strict";
|
||||
Object.defineProperty(exports, "__esModule", { value: true });
|
||||
exports.ApiKey = void 0;
|
||||
const AggregateRoot_1 = require("../../../../shared/domain/AggregateRoot");
|
||||
const UniqueId_1 = require("../../../../shared/domain/UniqueId");
|
||||
class ApiKey extends AggregateRoot_1.AggregateRoot {
|
||||
static create(props, id) {
|
||||
const keyId = id ?? UniqueId_1.UniqueId.create();
|
||||
return new ApiKey({
|
||||
...props,
|
||||
createdAt: new Date(),
|
||||
}, keyId);
|
||||
}
|
||||
static reconstitute(props, id) {
|
||||
return new ApiKey(props, id);
|
||||
}
|
||||
get userId() { return this.props.userId; }
|
||||
get orgId() { return this.props.orgId; }
|
||||
get name() { return this.props.name; }
|
||||
get keyHash() { return this.props.keyHash; }
|
||||
get keyPrefix() { return this.props.keyPrefix; }
|
||||
get permissions() { return this.props.permissions; }
|
||||
get expiresAt() { return this.props.expiresAt; }
|
||||
get lastUsedAt() { return this.props.lastUsedAt; }
|
||||
get createdAt() { return this.props.createdAt; }
|
||||
isExpired() {
|
||||
if (!this.props.expiresAt)
|
||||
return false;
|
||||
return new Date() > this.props.expiresAt;
|
||||
}
|
||||
markUsed() {
|
||||
this.props.lastUsedAt = new Date();
|
||||
}
|
||||
}
|
||||
exports.ApiKey = ApiKey;
|
||||
33
dist/modules/auth/domain/entities/Organization.js
vendored
Normal file
33
dist/modules/auth/domain/entities/Organization.js
vendored
Normal file
@@ -0,0 +1,33 @@
|
||||
"use strict";
|
||||
Object.defineProperty(exports, "__esModule", { value: true });
|
||||
exports.Organization = void 0;
|
||||
const AggregateRoot_1 = require("../../../../shared/domain/AggregateRoot");
|
||||
const UniqueId_1 = require("../../../../shared/domain/UniqueId");
|
||||
const OrgCreated_1 = require("../events/OrgCreated");
|
||||
class Organization extends AggregateRoot_1.AggregateRoot {
|
||||
static create(props, id) {
|
||||
const orgId = id ?? UniqueId_1.UniqueId.create();
|
||||
const org = new Organization({
|
||||
...props,
|
||||
createdAt: new Date(),
|
||||
}, orgId);
|
||||
org.addDomainEvent(new OrgCreated_1.OrgCreated(orgId.toString(), {
|
||||
name: props.name,
|
||||
slug: props.slug,
|
||||
}));
|
||||
return org;
|
||||
}
|
||||
static reconstitute(props, id) {
|
||||
return new Organization(props, id);
|
||||
}
|
||||
static slugify(name) {
|
||||
return name
|
||||
.toLowerCase()
|
||||
.replace(/[^a-z0-9]+/g, '-')
|
||||
.replace(/^-|-$/g, '');
|
||||
}
|
||||
get name() { return this.props.name; }
|
||||
get slug() { return this.props.slug; }
|
||||
get createdAt() { return this.props.createdAt; }
|
||||
}
|
||||
exports.Organization = Organization;
|
||||
42
dist/modules/auth/domain/entities/User.js
vendored
Normal file
42
dist/modules/auth/domain/entities/User.js
vendored
Normal file
@@ -0,0 +1,42 @@
|
||||
"use strict";
|
||||
Object.defineProperty(exports, "__esModule", { value: true });
|
||||
exports.User = void 0;
|
||||
const AggregateRoot_1 = require("../../../../shared/domain/AggregateRoot");
|
||||
const UniqueId_1 = require("../../../../shared/domain/UniqueId");
|
||||
const UserCreated_1 = require("../events/UserCreated");
|
||||
class User extends AggregateRoot_1.AggregateRoot {
|
||||
static create(props, id) {
|
||||
const userId = id ?? UniqueId_1.UniqueId.create();
|
||||
const now = new Date();
|
||||
const user = new User({
|
||||
...props,
|
||||
createdAt: now,
|
||||
updatedAt: now,
|
||||
}, userId);
|
||||
user.addDomainEvent(new UserCreated_1.UserCreated(userId.toString(), {
|
||||
email: props.email.value,
|
||||
name: props.name,
|
||||
role: props.role.value,
|
||||
}));
|
||||
return user;
|
||||
}
|
||||
static reconstitute(props, id) {
|
||||
return new User(props, id);
|
||||
}
|
||||
get email() { return this.props.email; }
|
||||
get name() { return this.props.name; }
|
||||
get passwordHash() { return this.props.passwordHash; }
|
||||
get role() { return this.props.role; }
|
||||
get orgId() { return this.props.orgId; }
|
||||
get createdAt() { return this.props.createdAt; }
|
||||
get updatedAt() { return this.props.updatedAt; }
|
||||
assignToOrg(orgId) {
|
||||
this.props.orgId = orgId;
|
||||
this.props.updatedAt = new Date();
|
||||
}
|
||||
changeRole(role) {
|
||||
this.props.role = role;
|
||||
this.props.updatedAt = new Date();
|
||||
}
|
||||
}
|
||||
exports.User = User;
|
||||
14
dist/modules/auth/domain/events/MemberInvited.js
vendored
Normal file
14
dist/modules/auth/domain/events/MemberInvited.js
vendored
Normal file
@@ -0,0 +1,14 @@
|
||||
"use strict";
|
||||
Object.defineProperty(exports, "__esModule", { value: true });
|
||||
exports.MemberInvited = void 0;
|
||||
const crypto_1 = require("crypto");
|
||||
class MemberInvited {
|
||||
constructor(aggregateId, payload) {
|
||||
this.aggregateId = aggregateId;
|
||||
this.payload = payload;
|
||||
this.eventId = (0, crypto_1.randomUUID)();
|
||||
this.eventName = 'auth.member.invited';
|
||||
this.occurredOn = new Date();
|
||||
}
|
||||
}
|
||||
exports.MemberInvited = MemberInvited;
|
||||
14
dist/modules/auth/domain/events/OrgCreated.js
vendored
Normal file
14
dist/modules/auth/domain/events/OrgCreated.js
vendored
Normal file
@@ -0,0 +1,14 @@
|
||||
"use strict";
|
||||
Object.defineProperty(exports, "__esModule", { value: true });
|
||||
exports.OrgCreated = void 0;
|
||||
const crypto_1 = require("crypto");
|
||||
class OrgCreated {
|
||||
constructor(aggregateId, payload) {
|
||||
this.aggregateId = aggregateId;
|
||||
this.payload = payload;
|
||||
this.eventId = (0, crypto_1.randomUUID)();
|
||||
this.eventName = 'auth.org.created';
|
||||
this.occurredOn = new Date();
|
||||
}
|
||||
}
|
||||
exports.OrgCreated = OrgCreated;
|
||||
14
dist/modules/auth/domain/events/UserCreated.js
vendored
Normal file
14
dist/modules/auth/domain/events/UserCreated.js
vendored
Normal file
@@ -0,0 +1,14 @@
|
||||
"use strict";
|
||||
Object.defineProperty(exports, "__esModule", { value: true });
|
||||
exports.UserCreated = void 0;
|
||||
const crypto_1 = require("crypto");
|
||||
class UserCreated {
|
||||
constructor(aggregateId, payload) {
|
||||
this.aggregateId = aggregateId;
|
||||
this.payload = payload;
|
||||
this.eventId = (0, crypto_1.randomUUID)();
|
||||
this.eventName = 'auth.user.created';
|
||||
this.occurredOn = new Date();
|
||||
}
|
||||
}
|
||||
exports.UserCreated = UserCreated;
|
||||
14
dist/modules/auth/domain/events/UserLoggedIn.js
vendored
Normal file
14
dist/modules/auth/domain/events/UserLoggedIn.js
vendored
Normal file
@@ -0,0 +1,14 @@
|
||||
"use strict";
|
||||
Object.defineProperty(exports, "__esModule", { value: true });
|
||||
exports.UserLoggedIn = void 0;
|
||||
const crypto_1 = require("crypto");
|
||||
class UserLoggedIn {
|
||||
constructor(aggregateId, payload) {
|
||||
this.aggregateId = aggregateId;
|
||||
this.payload = payload;
|
||||
this.eventId = (0, crypto_1.randomUUID)();
|
||||
this.eventName = 'auth.user.logged_in';
|
||||
this.occurredOn = new Date();
|
||||
}
|
||||
}
|
||||
exports.UserLoggedIn = UserLoggedIn;
|
||||
2
dist/modules/auth/domain/ports/IApiKeyRepository.js
vendored
Normal file
2
dist/modules/auth/domain/ports/IApiKeyRepository.js
vendored
Normal file
@@ -0,0 +1,2 @@
|
||||
"use strict";
|
||||
Object.defineProperty(exports, "__esModule", { value: true });
|
||||
2
dist/modules/auth/domain/ports/IOrganizationRepository.js
vendored
Normal file
2
dist/modules/auth/domain/ports/IOrganizationRepository.js
vendored
Normal file
@@ -0,0 +1,2 @@
|
||||
"use strict";
|
||||
Object.defineProperty(exports, "__esModule", { value: true });
|
||||
2
dist/modules/auth/domain/ports/ISessionRepository.js
vendored
Normal file
2
dist/modules/auth/domain/ports/ISessionRepository.js
vendored
Normal file
@@ -0,0 +1,2 @@
|
||||
"use strict";
|
||||
Object.defineProperty(exports, "__esModule", { value: true });
|
||||
2
dist/modules/auth/domain/ports/IUserRepository.js
vendored
Normal file
2
dist/modules/auth/domain/ports/IUserRepository.js
vendored
Normal file
@@ -0,0 +1,2 @@
|
||||
"use strict";
|
||||
Object.defineProperty(exports, "__esModule", { value: true });
|
||||
18
dist/modules/auth/domain/value-objects/Email.js
vendored
Normal file
18
dist/modules/auth/domain/value-objects/Email.js
vendored
Normal file
@@ -0,0 +1,18 @@
|
||||
"use strict";
|
||||
Object.defineProperty(exports, "__esModule", { value: true });
|
||||
exports.Email = void 0;
|
||||
const ValueObject_1 = require("../../../../shared/domain/ValueObject");
|
||||
class Email extends ValueObject_1.ValueObject {
|
||||
static create(value) {
|
||||
const normalized = value.trim().toLowerCase();
|
||||
if (!Email.EMAIL_REGEX.test(normalized)) {
|
||||
throw new Error(`Invalid email address: ${value}`);
|
||||
}
|
||||
return new Email({ value: normalized });
|
||||
}
|
||||
get value() {
|
||||
return this.props.value;
|
||||
}
|
||||
}
|
||||
exports.Email = Email;
|
||||
Email.EMAIL_REGEX = /^[^\s@]+@[^\s@]+\.[^\s@]+$/;
|
||||
12
dist/modules/auth/domain/value-objects/Permission.js
vendored
Normal file
12
dist/modules/auth/domain/value-objects/Permission.js
vendored
Normal file
@@ -0,0 +1,12 @@
|
||||
"use strict";
|
||||
Object.defineProperty(exports, "__esModule", { value: true });
|
||||
exports.Permission = void 0;
|
||||
const ValueObject_1 = require("../../../../shared/domain/ValueObject");
|
||||
class Permission extends ValueObject_1.ValueObject {
|
||||
static create(action, subject) {
|
||||
return new Permission({ action, subject });
|
||||
}
|
||||
get action() { return this.props.action; }
|
||||
get subject() { return this.props.subject; }
|
||||
}
|
||||
exports.Permission = Permission;
|
||||
29
dist/modules/auth/domain/value-objects/Role.js
vendored
Normal file
29
dist/modules/auth/domain/value-objects/Role.js
vendored
Normal file
@@ -0,0 +1,29 @@
|
||||
"use strict";
|
||||
Object.defineProperty(exports, "__esModule", { value: true });
|
||||
exports.Role = void 0;
|
||||
const ValueObject_1 = require("../../../../shared/domain/ValueObject");
|
||||
class Role extends ValueObject_1.ValueObject {
|
||||
static create(value) {
|
||||
if (!Role.VALID_ROLES.includes(value)) {
|
||||
throw new Error(`Invalid role: ${value}. Must be one of: ${Role.VALID_ROLES.join(', ')}`);
|
||||
}
|
||||
return new Role({ value: value });
|
||||
}
|
||||
static owner() { return new Role({ value: 'owner' }); }
|
||||
static admin() { return new Role({ value: 'admin' }); }
|
||||
static member() { return new Role({ value: 'member' }); }
|
||||
static viewer() { return new Role({ value: 'viewer' }); }
|
||||
get value() {
|
||||
return this.props.value;
|
||||
}
|
||||
isOwner() { return this.props.value === 'owner'; }
|
||||
isAdmin() { return this.props.value === 'admin'; }
|
||||
isMember() { return this.props.value === 'member'; }
|
||||
isViewer() { return this.props.value === 'viewer'; }
|
||||
}
|
||||
exports.Role = Role;
|
||||
Role.OWNER = 'owner';
|
||||
Role.ADMIN = 'admin';
|
||||
Role.MEMBER = 'member';
|
||||
Role.VIEWER = 'viewer';
|
||||
Role.VALID_ROLES = ['owner', 'admin', 'member', 'viewer'];
|
||||
Reference in New Issue
Block a user