feat: implement account settings and API tokens management
- Added SettingsComponent for user profile management, including display name and password change functionality. - Introduced TokensComponent for managing API tokens, including creation and revocation. - Created LayoutComponent for consistent application layout with navigation and user information. - Established main application structure in index.html and main.ts. - Integrated Tailwind CSS for styling and responsive design. - Configured TypeScript settings for strict type checking and module resolution.
This commit is contained in:
152
ts/interfaces/audit.interfaces.ts
Normal file
152
ts/interfaces/audit.interfaces.ts
Normal file
@@ -0,0 +1,152 @@
|
||||
/**
|
||||
* Audit logging interfaces
|
||||
*/
|
||||
|
||||
// =============================================================================
|
||||
// Audit Action Types
|
||||
// =============================================================================
|
||||
|
||||
export type TAuditAction =
|
||||
// Authentication
|
||||
| 'AUTH_LOGIN'
|
||||
| 'AUTH_LOGOUT'
|
||||
| 'AUTH_FAILED'
|
||||
| 'AUTH_MFA_ENABLED'
|
||||
| 'AUTH_MFA_DISABLED'
|
||||
| 'AUTH_PASSWORD_CHANGED'
|
||||
| 'AUTH_PASSWORD_RESET'
|
||||
// API Tokens
|
||||
| 'TOKEN_CREATED'
|
||||
| 'TOKEN_USED'
|
||||
| 'TOKEN_REVOKED'
|
||||
| 'TOKEN_EXPIRED'
|
||||
// User Management
|
||||
| 'USER_CREATED'
|
||||
| 'USER_UPDATED'
|
||||
| 'USER_DELETED'
|
||||
| 'USER_SUSPENDED'
|
||||
| 'USER_ACTIVATED'
|
||||
// Organization Management
|
||||
| 'ORG_CREATED'
|
||||
| 'ORG_UPDATED'
|
||||
| 'ORG_DELETED'
|
||||
| 'ORG_MEMBER_ADDED'
|
||||
| 'ORG_MEMBER_REMOVED'
|
||||
| 'ORG_MEMBER_ROLE_CHANGED'
|
||||
// Team Management
|
||||
| 'TEAM_CREATED'
|
||||
| 'TEAM_UPDATED'
|
||||
| 'TEAM_DELETED'
|
||||
| 'TEAM_MEMBER_ADDED'
|
||||
| 'TEAM_MEMBER_REMOVED'
|
||||
// Repository Management
|
||||
| 'REPO_CREATED'
|
||||
| 'REPO_UPDATED'
|
||||
| 'REPO_DELETED'
|
||||
| 'REPO_VISIBILITY_CHANGED'
|
||||
| 'REPO_PERMISSION_GRANTED'
|
||||
| 'REPO_PERMISSION_REVOKED'
|
||||
// Package Operations
|
||||
| 'PACKAGE_PUSHED'
|
||||
| 'PACKAGE_PULLED'
|
||||
| 'PACKAGE_DELETED'
|
||||
| 'PACKAGE_DEPRECATED'
|
||||
// Security Events
|
||||
| 'SECURITY_SCAN_COMPLETED'
|
||||
| 'SECURITY_VULNERABILITY_FOUND'
|
||||
| 'SECURITY_IP_BLOCKED'
|
||||
| 'SECURITY_RATE_LIMITED';
|
||||
|
||||
export type TAuditResourceType =
|
||||
| 'user'
|
||||
| 'organization'
|
||||
| 'team'
|
||||
| 'repository'
|
||||
| 'package'
|
||||
| 'api_token'
|
||||
| 'session'
|
||||
| 'system';
|
||||
|
||||
// =============================================================================
|
||||
// Audit Log Entry
|
||||
// =============================================================================
|
||||
|
||||
export interface IAuditLog {
|
||||
id: string;
|
||||
actorId?: string;
|
||||
actorType: 'user' | 'api_token' | 'system' | 'anonymous';
|
||||
actorTokenId?: string;
|
||||
actorIp?: string;
|
||||
actorUserAgent?: string;
|
||||
action: TAuditAction;
|
||||
resourceType: TAuditResourceType;
|
||||
resourceId?: string;
|
||||
resourceName?: string;
|
||||
organizationId?: string;
|
||||
repositoryId?: string;
|
||||
metadata: Record<string, unknown>;
|
||||
success: boolean;
|
||||
errorCode?: string;
|
||||
errorMessage?: string;
|
||||
durationMs?: number;
|
||||
timestamp: Date;
|
||||
}
|
||||
|
||||
// =============================================================================
|
||||
// Audit Query Types
|
||||
// =============================================================================
|
||||
|
||||
export interface IAuditQuery {
|
||||
actorId?: string;
|
||||
organizationId?: string;
|
||||
repositoryId?: string;
|
||||
resourceType?: TAuditResourceType;
|
||||
action?: TAuditAction[];
|
||||
success?: boolean;
|
||||
startDate?: Date;
|
||||
endDate?: Date;
|
||||
offset?: number;
|
||||
limit?: number;
|
||||
}
|
||||
|
||||
export interface IAuditQueryResult {
|
||||
logs: IAuditLog[];
|
||||
total: number;
|
||||
offset: number;
|
||||
limit: number;
|
||||
}
|
||||
|
||||
// =============================================================================
|
||||
// Audit Event (for logging)
|
||||
// =============================================================================
|
||||
|
||||
export interface IAuditEvent {
|
||||
actorId?: string;
|
||||
actorType?: 'user' | 'api_token' | 'system' | 'anonymous';
|
||||
actorTokenId?: string;
|
||||
actorIp?: string;
|
||||
actorUserAgent?: string;
|
||||
action: TAuditAction;
|
||||
resourceType: TAuditResourceType;
|
||||
resourceId?: string;
|
||||
resourceName?: string;
|
||||
organizationId?: string;
|
||||
repositoryId?: string;
|
||||
metadata?: Record<string, unknown>;
|
||||
success?: boolean;
|
||||
errorCode?: string;
|
||||
errorMessage?: string;
|
||||
durationMs?: number;
|
||||
}
|
||||
|
||||
// =============================================================================
|
||||
// Token Activity
|
||||
// =============================================================================
|
||||
|
||||
export interface ITokenActivitySummary {
|
||||
tokenId: string;
|
||||
totalActions: number;
|
||||
lastUsed?: Date;
|
||||
actionBreakdown: Record<string, number>;
|
||||
ipAddresses: string[];
|
||||
}
|
||||
282
ts/interfaces/auth.interfaces.ts
Normal file
282
ts/interfaces/auth.interfaces.ts
Normal file
@@ -0,0 +1,282 @@
|
||||
/**
|
||||
* Authentication and authorization interfaces
|
||||
*/
|
||||
|
||||
// =============================================================================
|
||||
// User Types
|
||||
// =============================================================================
|
||||
|
||||
export type TUserStatus = 'active' | 'suspended' | 'pending_verification';
|
||||
|
||||
export interface IUser {
|
||||
id: string;
|
||||
email: string;
|
||||
username: string;
|
||||
passwordHash: string;
|
||||
displayName: string;
|
||||
avatarUrl?: string;
|
||||
status: TUserStatus;
|
||||
emailVerified: boolean;
|
||||
mfaEnabled: boolean;
|
||||
mfaSecret?: string;
|
||||
lastLoginAt?: Date;
|
||||
lastLoginIp?: string;
|
||||
failedLoginAttempts: number;
|
||||
lockedUntil?: Date;
|
||||
isPlatformAdmin: boolean;
|
||||
createdAt: Date;
|
||||
updatedAt: Date;
|
||||
}
|
||||
|
||||
// =============================================================================
|
||||
// Organization Types
|
||||
// =============================================================================
|
||||
|
||||
export type TOrganizationPlan = 'free' | 'team' | 'enterprise';
|
||||
export type TOrganizationRole = 'owner' | 'admin' | 'member';
|
||||
|
||||
export interface IOrganizationSettings {
|
||||
requireMfa: boolean;
|
||||
allowPublicRepositories: boolean;
|
||||
defaultRepositoryVisibility: TRepositoryVisibility;
|
||||
allowedProtocols: TRegistryProtocol[];
|
||||
}
|
||||
|
||||
export interface IOrganization {
|
||||
id: string;
|
||||
name: string; // URL-safe slug
|
||||
displayName: string;
|
||||
description?: string;
|
||||
avatarUrl?: string;
|
||||
plan: TOrganizationPlan;
|
||||
settings: IOrganizationSettings;
|
||||
billingEmail?: string;
|
||||
isVerified: boolean;
|
||||
verifiedDomains: string[];
|
||||
storageQuotaBytes: number;
|
||||
usedStorageBytes: number;
|
||||
createdAt: Date;
|
||||
updatedAt: Date;
|
||||
createdById: string;
|
||||
}
|
||||
|
||||
export interface IOrganizationMember {
|
||||
id: string;
|
||||
organizationId: string;
|
||||
userId: string;
|
||||
role: TOrganizationRole;
|
||||
invitedBy?: string;
|
||||
joinedAt: Date;
|
||||
createdAt: Date;
|
||||
}
|
||||
|
||||
// =============================================================================
|
||||
// Team Types
|
||||
// =============================================================================
|
||||
|
||||
export type TTeamRole = 'maintainer' | 'member';
|
||||
|
||||
export interface ITeam {
|
||||
id: string;
|
||||
organizationId: string;
|
||||
name: string;
|
||||
description?: string;
|
||||
isDefaultTeam: boolean;
|
||||
createdAt: Date;
|
||||
updatedAt: Date;
|
||||
}
|
||||
|
||||
export interface ITeamMember {
|
||||
id: string;
|
||||
teamId: string;
|
||||
userId: string;
|
||||
role: TTeamRole;
|
||||
createdAt: Date;
|
||||
}
|
||||
|
||||
// =============================================================================
|
||||
// Repository Types
|
||||
// =============================================================================
|
||||
|
||||
export type TRepositoryVisibility = 'public' | 'private' | 'internal';
|
||||
export type TRepositoryRole = 'admin' | 'maintainer' | 'developer' | 'reader';
|
||||
export type TRegistryProtocol = 'oci' | 'npm' | 'maven' | 'cargo' | 'composer' | 'pypi' | 'rubygems';
|
||||
|
||||
export interface IRepository {
|
||||
id: string;
|
||||
organizationId: string;
|
||||
name: string;
|
||||
description?: string;
|
||||
protocol: TRegistryProtocol;
|
||||
visibility: TRepositoryVisibility;
|
||||
storageNamespace: string;
|
||||
downloadCount: number;
|
||||
starCount: number;
|
||||
createdAt: Date;
|
||||
updatedAt: Date;
|
||||
createdById: string;
|
||||
}
|
||||
|
||||
export interface IRepositoryPermission {
|
||||
id: string;
|
||||
repositoryId: string;
|
||||
teamId?: string;
|
||||
userId?: string;
|
||||
role: TRepositoryRole;
|
||||
createdAt: Date;
|
||||
grantedById: string;
|
||||
}
|
||||
|
||||
// =============================================================================
|
||||
// Token Types
|
||||
// =============================================================================
|
||||
|
||||
export interface ITokenScope {
|
||||
protocol: TRegistryProtocol | '*';
|
||||
organizationId?: string;
|
||||
repositoryId?: string;
|
||||
actions: TTokenAction[];
|
||||
}
|
||||
|
||||
export type TTokenAction = 'read' | 'write' | 'delete' | '*';
|
||||
|
||||
export interface IApiToken {
|
||||
id: string;
|
||||
userId: string;
|
||||
name: string;
|
||||
tokenHash: string;
|
||||
tokenPrefix: string;
|
||||
protocols: TRegistryProtocol[];
|
||||
scopes: ITokenScope[];
|
||||
expiresAt?: Date;
|
||||
lastUsedAt?: Date;
|
||||
lastUsedIp?: string;
|
||||
usageCount: number;
|
||||
isRevoked: boolean;
|
||||
revokedAt?: Date;
|
||||
revokedReason?: string;
|
||||
createdAt: Date;
|
||||
createdIp?: string;
|
||||
}
|
||||
|
||||
// =============================================================================
|
||||
// Session Types
|
||||
// =============================================================================
|
||||
|
||||
export interface ISession {
|
||||
id: string;
|
||||
userId: string;
|
||||
userAgent: string;
|
||||
ipAddress: string;
|
||||
isValid: boolean;
|
||||
invalidatedAt?: Date;
|
||||
invalidatedReason?: string;
|
||||
lastActivityAt: Date;
|
||||
createdAt: Date;
|
||||
}
|
||||
|
||||
// =============================================================================
|
||||
// JWT Types
|
||||
// =============================================================================
|
||||
|
||||
export interface IJwtPayload {
|
||||
sub: string; // User ID
|
||||
iss: string; // Issuer
|
||||
aud: string; // Audience
|
||||
exp: number; // Expiration
|
||||
iat: number; // Issued at
|
||||
nbf: number; // Not before
|
||||
type: 'access' | 'refresh';
|
||||
email: string;
|
||||
username: string;
|
||||
orgs: Array<{
|
||||
id: string;
|
||||
name: string;
|
||||
role: TOrganizationRole;
|
||||
}>;
|
||||
sessionId: string;
|
||||
}
|
||||
|
||||
// =============================================================================
|
||||
// Auth Results
|
||||
// =============================================================================
|
||||
|
||||
export interface IAuthResult {
|
||||
accessToken: string;
|
||||
refreshToken: string;
|
||||
expiresIn: number;
|
||||
user: IUser;
|
||||
}
|
||||
|
||||
export interface IValidatedToken {
|
||||
tokenId: string;
|
||||
userId: string;
|
||||
username: string;
|
||||
protocols: TRegistryProtocol[];
|
||||
scopes: ITokenScope[];
|
||||
}
|
||||
|
||||
export interface IAuthorizationResult {
|
||||
authorized: boolean;
|
||||
reason?: string;
|
||||
userId?: string;
|
||||
}
|
||||
|
||||
// =============================================================================
|
||||
// Permission Types
|
||||
// =============================================================================
|
||||
|
||||
export type TPermissionAction =
|
||||
| 'repo:read'
|
||||
| 'repo:write'
|
||||
| 'repo:delete'
|
||||
| 'repo:admin'
|
||||
| 'team:read'
|
||||
| 'team:write'
|
||||
| 'team:admin'
|
||||
| 'org:read'
|
||||
| 'org:write'
|
||||
| 'org:admin'
|
||||
| 'token:create'
|
||||
| 'token:revoke';
|
||||
|
||||
export interface IResource {
|
||||
type: 'repository' | 'organization' | 'team' | 'user';
|
||||
id: string;
|
||||
}
|
||||
|
||||
// =============================================================================
|
||||
// Create/Update DTOs
|
||||
// =============================================================================
|
||||
|
||||
export interface ICreateUserDto {
|
||||
email: string;
|
||||
username: string;
|
||||
password: string;
|
||||
displayName?: string;
|
||||
}
|
||||
|
||||
export interface ICreateOrganizationDto {
|
||||
name: string;
|
||||
displayName: string;
|
||||
description?: string;
|
||||
}
|
||||
|
||||
export interface ICreateTeamDto {
|
||||
name: string;
|
||||
description?: string;
|
||||
}
|
||||
|
||||
export interface ICreateRepositoryDto {
|
||||
name: string;
|
||||
description?: string;
|
||||
protocol: TRegistryProtocol;
|
||||
visibility?: TRepositoryVisibility;
|
||||
}
|
||||
|
||||
export interface ICreateTokenDto {
|
||||
name: string;
|
||||
protocols: TRegistryProtocol[];
|
||||
scopes: ITokenScope[];
|
||||
expiresAt?: Date;
|
||||
}
|
||||
7
ts/interfaces/index.ts
Normal file
7
ts/interfaces/index.ts
Normal file
@@ -0,0 +1,7 @@
|
||||
/**
|
||||
* Type definitions for Stack.Gallery Registry
|
||||
*/
|
||||
|
||||
export * from './auth.interfaces.ts';
|
||||
export * from './package.interfaces.ts';
|
||||
export * from './audit.interfaces.ts';
|
||||
202
ts/interfaces/package.interfaces.ts
Normal file
202
ts/interfaces/package.interfaces.ts
Normal file
@@ -0,0 +1,202 @@
|
||||
/**
|
||||
* Package and artifact interfaces
|
||||
*/
|
||||
|
||||
import type { TRegistryProtocol } from './auth.interfaces.ts';
|
||||
|
||||
// =============================================================================
|
||||
// Package Types
|
||||
// =============================================================================
|
||||
|
||||
export interface IPackage {
|
||||
id: string; // {protocol}:{org}:{name}
|
||||
organizationId: string;
|
||||
repositoryId: string;
|
||||
protocol: TRegistryProtocol;
|
||||
name: string;
|
||||
description?: string;
|
||||
versions: Record<string, IPackageVersion>;
|
||||
distTags: Record<string, string>; // npm dist-tags, e.g., { latest: "1.0.0" }
|
||||
metadata: IProtocolMetadata;
|
||||
isPrivate: boolean;
|
||||
storageBytes: number;
|
||||
downloadCount: number;
|
||||
starCount: number;
|
||||
cacheExpiresAt?: Date;
|
||||
createdAt: Date;
|
||||
updatedAt: Date;
|
||||
createdById: string;
|
||||
}
|
||||
|
||||
export interface IPackageVersion {
|
||||
version: string;
|
||||
digest?: string; // Content-addressable digest (sha256:...)
|
||||
size: number;
|
||||
publishedAt: Date;
|
||||
publishedById: string;
|
||||
deprecated?: boolean;
|
||||
deprecationMessage?: string;
|
||||
downloads: number;
|
||||
metadata: IVersionMetadata;
|
||||
}
|
||||
|
||||
// =============================================================================
|
||||
// Protocol-Specific Metadata
|
||||
// =============================================================================
|
||||
|
||||
export type IProtocolMetadata =
|
||||
| INpmMetadata
|
||||
| IOciMetadata
|
||||
| IMavenMetadata
|
||||
| ICargoMetadata
|
||||
| IComposerMetadata
|
||||
| IPypiMetadata
|
||||
| IRubygemsMetadata;
|
||||
|
||||
export interface INpmMetadata {
|
||||
type: 'npm';
|
||||
scope?: string;
|
||||
keywords?: string[];
|
||||
license?: string;
|
||||
repository?: {
|
||||
type: string;
|
||||
url: string;
|
||||
};
|
||||
homepage?: string;
|
||||
bugs?: string;
|
||||
author?: string | { name: string; email?: string; url?: string };
|
||||
maintainers?: Array<{ name: string; email?: string }>;
|
||||
}
|
||||
|
||||
export interface IOciMetadata {
|
||||
type: 'oci';
|
||||
mediaType: string;
|
||||
tags: string[];
|
||||
architecture?: string;
|
||||
os?: string;
|
||||
annotations?: Record<string, string>;
|
||||
}
|
||||
|
||||
export interface IMavenMetadata {
|
||||
type: 'maven';
|
||||
groupId: string;
|
||||
artifactId: string;
|
||||
packaging: string;
|
||||
classifier?: string;
|
||||
parent?: {
|
||||
groupId: string;
|
||||
artifactId: string;
|
||||
version: string;
|
||||
};
|
||||
}
|
||||
|
||||
export interface ICargoMetadata {
|
||||
type: 'cargo';
|
||||
features: Record<string, string[]>;
|
||||
dependencies: Array<{
|
||||
name: string;
|
||||
req: string;
|
||||
features: string[];
|
||||
optional: boolean;
|
||||
defaultFeatures: boolean;
|
||||
target?: string;
|
||||
kind: 'normal' | 'dev' | 'build';
|
||||
}>;
|
||||
keywords?: string[];
|
||||
categories?: string[];
|
||||
license?: string;
|
||||
links?: string;
|
||||
}
|
||||
|
||||
export interface IComposerMetadata {
|
||||
type: 'composer';
|
||||
vendor: string;
|
||||
packageType?: string;
|
||||
license?: string | string[];
|
||||
require?: Record<string, string>;
|
||||
requireDev?: Record<string, string>;
|
||||
autoload?: Record<string, unknown>;
|
||||
}
|
||||
|
||||
export interface IPypiMetadata {
|
||||
type: 'pypi';
|
||||
classifiers?: string[];
|
||||
requiresPython?: string;
|
||||
requiresDist?: string[];
|
||||
providesExtra?: string[];
|
||||
projectUrls?: Record<string, string>;
|
||||
}
|
||||
|
||||
export interface IRubygemsMetadata {
|
||||
type: 'rubygems';
|
||||
platform?: string;
|
||||
requiredRubyVersion?: string;
|
||||
requiredRubygemsVersion?: string;
|
||||
dependencies?: Array<{
|
||||
name: string;
|
||||
requirements: string;
|
||||
type: 'runtime' | 'development';
|
||||
}>;
|
||||
}
|
||||
|
||||
// =============================================================================
|
||||
// Version Metadata
|
||||
// =============================================================================
|
||||
|
||||
export interface IVersionMetadata {
|
||||
readme?: string;
|
||||
changelog?: string;
|
||||
dependencies?: Record<string, string>;
|
||||
devDependencies?: Record<string, string>;
|
||||
peerDependencies?: Record<string, string>;
|
||||
engines?: Record<string, string>;
|
||||
files?: string[];
|
||||
checksum?: {
|
||||
sha256?: string;
|
||||
sha512?: string;
|
||||
md5?: string;
|
||||
};
|
||||
}
|
||||
|
||||
// =============================================================================
|
||||
// Search Types
|
||||
// =============================================================================
|
||||
|
||||
export interface IPackageSearchParams {
|
||||
query?: string;
|
||||
protocol?: TRegistryProtocol;
|
||||
organizationId?: string;
|
||||
visibility?: 'public' | 'private' | 'internal';
|
||||
sort?: 'downloads' | 'stars' | 'updated' | 'name';
|
||||
order?: 'asc' | 'desc';
|
||||
offset?: number;
|
||||
limit?: number;
|
||||
}
|
||||
|
||||
export interface IPackageSearchResult {
|
||||
packages: IPackage[];
|
||||
total: number;
|
||||
offset: number;
|
||||
limit: number;
|
||||
}
|
||||
|
||||
// =============================================================================
|
||||
// Stats Types
|
||||
// =============================================================================
|
||||
|
||||
export interface IPackageStats {
|
||||
packageId: string;
|
||||
totalDownloads: number;
|
||||
downloadsByVersion: Record<string, number>;
|
||||
downloadsByDay: Array<{ date: string; count: number }>;
|
||||
downloadsByCountry?: Record<string, number>;
|
||||
}
|
||||
|
||||
export interface IOrganizationStats {
|
||||
organizationId: string;
|
||||
totalPackages: number;
|
||||
totalDownloads: number;
|
||||
storageUsedBytes: number;
|
||||
storageQuotaBytes: number;
|
||||
packagesByProtocol: Record<TRegistryProtocol, number>;
|
||||
}
|
||||
Reference in New Issue
Block a user