# HiveOps Browser: Protocol Handling, Licensing & User Management ## Overview Add domain-based protocol handling (*.hiveops.com), external API-based licensing system with full feature controls (activation, tiers, expiration), and user authentication (license key + user profile). **Architecture**: Two-component system: 1. **hiveops-browser** (Electron app) - Desktop client with protocol handling and licensing enforcement 2. **hiveops-mgmt** (Spring Boot 4 microservice) - Central management service for licensing, user profiles, and global settings ## Requirements Summary - **Protocol Handling**: Domain-based (*.hiveops.com) and custom protocol (hiveops://) - **Licensing**: External API service with full controls (activation, feature-based tiers, time-based expiration) - **Authentication**: License key + User profile system - **License Tiers**: Basic, Pro, Enterprise (each with different feature sets) - **Backend**: Spring Boot 4 microservice with PostgreSQL database - **Repository**: Separate repository for hiveops-mgmt microservice ## Implementation Plan ### 1. Core License Management Infrastructure #### 1.1 Create License Manager Module **File**: `src/main/license-manager.js` (NEW) Core responsibilities: - Validate license key format (XXXXX-XXXXX-XXXXX-XXXXX-XXXXX) - Store/retrieve license data using encrypted electron-store - Verify license signatures (anti-tamper using HMAC-SHA256) - Check license validity (expiration, signature) - Feature gate checks (tier-based feature access) - User profile management Key methods: - `validateLicenseKeyFormat(key)` - Format validation - `storeLicense(licenseData)` - Encrypted storage - `isLicenseValid()` - Validity check (expiration + signature) - `hasFeature(featureName)` - Feature gate check - `getTier()` - Get license tier (basic/pro/enterprise) - `getDaysUntilExpiration()` - Expiration countdown #### 1.2 Create API Client Module **File**: `src/main/api-client.js` (NEW) External API communication: - Base URL: `https://api.hiveops.com/v1` (configurable) - 30-second timeout for all requests - HTTPS-only with proper error handling Key endpoints: - `POST /licenses/activate` - Activate license key - `POST /licenses/validate` - Online validation - `POST /auth/login` - User login - `GET /users/profile` - Get user profile - `GET /licenses/{key}/status` - Check license status - `POST /licenses/deactivate` - Deactivate license Key methods: - `activateLicense(licenseKey, machineId)` - Activate license - `validateLicense(licenseKey, machineId)` - Validate online - `login(email, password)` - User authentication - `getUserProfile(authToken)` - Fetch profile - `getMachineId()` - Generate unique device ID #### 1.3 Create Authentication Manager **File**: `src/main/auth-manager.js` (NEW) User authentication and session management: - Store auth tokens securely - Manage user profiles - Handle login/logout - Token refresh logic Key methods: - `login(email, password)` - User login - `logout()` - Clear session - `isAuthenticated()` - Check auth status - `getUser()` - Get current user - `getToken()` - Get auth token - `refreshProfile()` - Update user data ### 2. Application Lifecycle Integration #### 2.1 Modify Main Process **File**: `src/main/main.js` (MODIFY) Changes at app startup (app.whenReady): ```javascript // Add license check before main window if (!licenseManager.isLicenseValid()) { createLicenseActivationWindow(); // Block app until activated } else { createMainWindow(); // Show expiration warning if < 7 days remaining const daysRemaining = licenseManager.getDaysUntilExpiration(); if (daysRemaining <= 7) showExpirationWarning(daysRemaining); } ``` Add new window functions: - `createLicenseActivationWindow()` - 600x500 modal for activation - `openLicenseManagement()` - 600x500 modal for license info - `showExpirationWarning(days)` - Dialog for expiration alerts Add background license validation: - Every 24 hours, validate license online - Update local cache with server data - Handle offline gracefully (use local validation) - Force quit if license revoked or expired Add IPC handlers: - `activate-license` - Activate via API - `get-license-info` - Return license data - `deactivate-license` - Deactivate and quit - `validate-license` - Online validation - `has-feature` - Check feature access - `login` - User authentication - `logout` - Clear session - `get-user-profile` - Get user data - `is-authenticated` - Check auth status #### 2.2 Update Configuration Module **File**: `src/main/config.js` (MODIFY) Add feature tier definitions: ```javascript const FEATURE_TIERS = { basic: ['single-url', 'basic-navigation'], pro: ['single-url', 'basic-navigation', 'subdomain-access', 'zoom-controls'], enterprise: ['single-url', 'basic-navigation', 'subdomain-access', 'zoom-controls', 'custom-protocols', 'advanced-settings', 'api-access'] }; ``` Add methods: - `isFeatureEnabled(featureName)` - Check if feature is in current tier - Modify `isUrlAllowed()` to check license validity first Update default-config.json: ```json { "apiBaseUrl": "https://api.hiveops.com/v1" } ``` #### 2.3 Update IPC Bridge **File**: `src/main/preload.js` (MODIFY) Expose new APIs to renderer: ```javascript electronAPI: { // License APIs activateLicense: (licenseKey) => ipcRenderer.invoke('activate-license', licenseKey), getLicenseInfo: () => ipcRenderer.invoke('get-license-info'), deactivateLicense: () => ipcRenderer.invoke('deactivate-license'), validateLicense: () => ipcRenderer.invoke('validate-license'), hasFeature: (featureName) => ipcRenderer.invoke('has-feature', featureName), // Auth APIs login: (email, password) => ipcRenderer.invoke('login', email, password), logout: () => ipcRenderer.invoke('logout'), getUserProfile: () => ipcRenderer.invoke('get-user-profile'), isAuthenticated: () => ipcRenderer.invoke('is-authenticated'), // Window control closeLicenseWindow: () => ipcRenderer.send('close-license-window'), openLicenseManagement: () => ipcRenderer.send('open-license-management') } ``` ### 3. User Interface Components #### 3.1 License Activation Screen **Files**: - `src/renderer/license-activation.html` (NEW) - `src/renderer/license-activation.js` (NEW) - `src/renderer/license.css` (NEW) Features: - Tabbed interface: "License Key" and "User Login" - License key input with auto-formatting (dashes added automatically) - Email/password login form - Error/success message display - Loading states for async operations - Links to trial/purchase pages Workflow: 1. User enters license key OR logs in with credentials 2. Validate format client-side 3. Call API via IPC 4. Show success/error 5. Close window on success (main window opens) 6. Quit app on cancel if no valid license #### 3.2 License Management Screen **Files**: - `src/renderer/license-management.html` (NEW) - `src/renderer/license-management.js` (NEW) Features: - Display license status (active/expired/trial) - Show license tier (basic/pro/enterprise) - Show expiration date and days remaining - Display masked license key - Show user profile (name, email) if logged in - List enabled features for current tier - Refresh button (online validation) - Deactivate button (clear license and quit) #### 3.3 Update Settings Page **File**: `src/renderer/settings.html` (MODIFY) Add license information section: - Display current tier - Display expiration date - "Manage License" button → opens license management window Add to settings.js: - Load license info on page load - Display tier and expiration - Handle "Manage License" button click ### 4. Protocol Handler Registration #### 4.1 Update Build Configuration **File**: `electron-builder.yml` (MODIFY) Add protocol registration: ```yaml protocols: - name: HiveOps Browser schemes: - hiveops role: Viewer win: fileAssociations: - ext: hiveops name: HiveOps Link description: HiveOps Browser Link role: Viewer nsis: include: installer-script.nsh # Custom registry script linux: mimeTypes: - x-scheme-handler/hiveops desktop: MimeType: x-scheme-handler/hiveops ``` #### 4.2 Windows Protocol Registration **File**: `installer-script.nsh` (NEW) NSIS script for Windows registry: ```nsis !macro customInstall WriteRegStr HKCR "hiveops" "" "URL:HiveOps Protocol" WriteRegStr HKCR "hiveops" "URL Protocol" "" WriteRegStr HKCR "hiveops\DefaultIcon" "" "$INSTDIR\${APP_EXECUTABLE_FILENAME},0" WriteRegStr HKCR "hiveops\shell\open\command" "" '"$INSTDIR\${APP_EXECUTABLE_FILENAME}" "%1"' !macroend !macro customUnInstall DeleteRegKey HKCR "hiveops" !macroend ``` #### 4.3 Protocol Handling in Main Process **File**: `src/main/main.js` (MODIFY) Add protocol handler setup: ```javascript // Register protocol app.setAsDefaultProtocolClient('hiveops'); // Handle macOS protocol URLs app.on('open-url', (event, url) => { event.preventDefault(); handleProtocolUrl(url); }); // Handle Windows/Linux (single instance) const gotTheLock = app.requestSingleInstanceLock(); if (!gotTheLock) { app.quit(); } else { app.on('second-instance', (event, commandLine) => { const url = commandLine.find(arg => arg.startsWith('hiveops://')); if (url) handleProtocolUrl(url); if (mainWindow) { mainWindow.restore(); mainWindow.focus(); } }); } function handleProtocolUrl(protocolUrl) { // Parse: hiveops://open?url=https://example.hiveops.com/path const url = new URL(protocolUrl); const targetUrl = url.searchParams.get('url'); if (targetUrl && config.isUrlAllowed(targetUrl)) { mainWindow.loadURL(targetUrl); } } ``` ### 5. Feature Gates Implementation #### 5.1 Feature-Gated Menu Items **File**: `src/main/main.js` (MODIFY) Wrap menu items with feature checks: ```javascript { label: 'Zoom In', click: () => { if (!config.isFeatureEnabled('zoom-controls')) { dialog.showMessageBoxSync({ type: 'info', title: 'Feature Not Available', message: 'Zoom controls require Pro or Enterprise license.' }); return; } // Zoom logic } } ``` Apply to: - Zoom controls (Pro+) - Settings (if advanced settings are Enterprise-only) - Multiple windows (Pro+) - Custom protocol handling (Enterprise) #### 5.2 Feature-Gated URL Access **File**: `src/main/config.js` (MODIFY) Already implemented in `isUrlAllowed()`: - Basic: Single URL only - Pro: Single URL + subdomains - Enterprise: Single URL + subdomains + custom protocols ### 6. Security Implementation #### 6.1 Encrypted License Storage - Use electron-store with encryption key derived from machine ID - Store license data in: `~/.config/HiveOps/hiveops-license` (Linux) - Encryption prevents tampering with local data #### 6.2 License Signature Verification - Server generates HMAC-SHA256 signature: `HMAC(key + tier + expiry, secret)` - Client verifies signature on every validation - Prevents local tampering with tier/expiration #### 6.3 Machine ID Fingerprinting - Use `app.getSystemId()` or fallback to deterministic ID - Hash with SHA256 for consistent device identification - Used to enforce activation limits (e.g., 3 devices per license) #### 6.4 Online/Offline Validation - Primary: Local signature + expiration check (works offline) - Secondary: Background API validation every 24 hours (when online) - Grace period: Allow offline operation for up to 7 days - Forced validation: On app startup if last check > 7 days ago ### 7. HiveOps Management Microservice (hiveops-mgmt) **Separate Repository**: Create new Spring Boot 4 microservice in separate repository #### 7.1 Technology Stack - **Framework**: Spring Boot 4.0.x - **Language**: Java 21 (LTS) - **Database**: PostgreSQL 16+ - **Security**: Spring Security 6 with JWT - **ORM**: Spring Data JPA (Hibernate) - **API Docs**: SpringDoc OpenAPI 3 - **Build**: Maven or Gradle - **Deployment**: Docker containerized #### 7.2 Project Structure ``` hiveops-mgmt/ ├── src/ │ ├── main/ │ │ ├── java/com/hiveops/mgmt/ │ │ │ ├── HiveOpsMgmtApplication.java │ │ │ ├── config/ │ │ │ │ ├── SecurityConfig.java │ │ │ │ ├── JwtConfig.java │ │ │ │ └── CorsConfig.java │ │ │ ├── controller/ │ │ │ │ ├── LicenseController.java │ │ │ │ ├── AuthController.java │ │ │ │ ├── UserController.java │ │ │ │ └── GlobalSettingsController.java │ │ │ ├── service/ │ │ │ │ ├── LicenseService.java │ │ │ │ ├── AuthService.java │ │ │ │ ├── UserService.java │ │ │ │ ├── LicenseKeyGenerator.java │ │ │ │ └── GlobalSettingsService.java │ │ │ ├── repository/ │ │ │ │ ├── LicenseRepository.java │ │ │ │ ├── UserRepository.java │ │ │ │ ├── LicenseActivationRepository.java │ │ │ │ └── GlobalSettingsRepository.java │ │ │ ├── model/ │ │ │ │ ├── entity/ │ │ │ │ │ ├── License.java │ │ │ │ │ ├── User.java │ │ │ │ │ ├── LicenseActivation.java │ │ │ │ │ └── GlobalSetting.java │ │ │ │ ├── dto/ │ │ │ │ │ ├── LicenseActivationRequest.java │ │ │ │ │ ├── LicenseActivationResponse.java │ │ │ │ │ ├── LoginRequest.java │ │ │ │ │ ├── LoginResponse.java │ │ │ │ │ └── UserProfileResponse.java │ │ │ │ └── enums/ │ │ │ │ ├── LicenseTier.java │ │ │ │ ├── LicenseStatus.java │ │ │ │ └── UserRole.java │ │ │ ├── security/ │ │ │ │ ├── JwtTokenProvider.java │ │ │ │ ├── JwtAuthenticationFilter.java │ │ │ │ └── UserDetailsServiceImpl.java │ │ │ ├── exception/ │ │ │ │ ├── GlobalExceptionHandler.java │ │ │ │ ├── LicenseException.java │ │ │ │ └── AuthenticationException.java │ │ │ └── util/ │ │ │ ├── SignatureUtils.java │ │ │ └── DateUtils.java │ │ └── resources/ │ │ ├── application.yml │ │ ├── application-dev.yml │ │ ├── application-prod.yml │ │ └── db/migration/ # Flyway migrations │ │ ├── V1__init_schema.sql │ │ └── V2__seed_data.sql │ └── test/ │ └── java/com/hiveops/mgmt/ │ ├── service/ │ ├── controller/ │ └── integration/ ├── Dockerfile ├── docker-compose.yml ├── pom.xml (or build.gradle) └── README.md ``` #### 7.3 Database Schema (PostgreSQL) **Table: users** ```sql CREATE TABLE users ( id BIGSERIAL PRIMARY KEY, uuid UUID UNIQUE NOT NULL DEFAULT gen_random_uuid(), email VARCHAR(255) UNIQUE NOT NULL, password_hash VARCHAR(255) NOT NULL, name VARCHAR(255), role VARCHAR(50) NOT NULL DEFAULT 'USER', enabled BOOLEAN DEFAULT TRUE, created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP, updated_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP, last_login_at TIMESTAMP ); CREATE INDEX idx_users_email ON users(email); CREATE INDEX idx_users_uuid ON users(uuid); ``` **Table: licenses** ```sql CREATE TABLE licenses ( id BIGSERIAL PRIMARY KEY, license_key VARCHAR(29) UNIQUE NOT NULL, -- XXXXX-XXXXX-XXXXX-XXXXX-XXXXX user_id BIGINT REFERENCES users(id) ON DELETE CASCADE, tier VARCHAR(50) NOT NULL, -- BASIC, PRO, ENTERPRISE status VARCHAR(50) NOT NULL DEFAULT 'ACTIVE', -- ACTIVE, EXPIRED, REVOKED, TRIAL max_activations INTEGER DEFAULT 3, features JSONB, -- Array of feature names issued_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP, expires_at TIMESTAMP, trial_ends_at TIMESTAMP, created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP, updated_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP, metadata JSONB -- Additional data (company, notes, etc.) ); CREATE INDEX idx_licenses_key ON licenses(license_key); CREATE INDEX idx_licenses_user ON licenses(user_id); CREATE INDEX idx_licenses_status ON licenses(status); ``` **Table: license_activations** ```sql CREATE TABLE license_activations ( id BIGSERIAL PRIMARY KEY, license_id BIGINT NOT NULL REFERENCES licenses(id) ON DELETE CASCADE, machine_id VARCHAR(255) NOT NULL, platform VARCHAR(50), -- linux, windows, darwin app_version VARCHAR(50), activated_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP, last_validated_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP, ip_address INET, hostname VARCHAR(255), metadata JSONB, UNIQUE(license_id, machine_id) ); CREATE INDEX idx_activations_license ON license_activations(license_id); CREATE INDEX idx_activations_machine ON license_activations(machine_id); ``` **Table: global_settings** ```sql CREATE TABLE global_settings ( id BIGSERIAL PRIMARY KEY, setting_key VARCHAR(255) UNIQUE NOT NULL, setting_value TEXT NOT NULL, setting_type VARCHAR(50) DEFAULT 'STRING', -- STRING, INTEGER, BOOLEAN, JSON description TEXT, editable BOOLEAN DEFAULT TRUE, created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP, updated_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP ); CREATE INDEX idx_settings_key ON global_settings(setting_key); ``` **Table: audit_logs** ```sql CREATE TABLE audit_logs ( id BIGSERIAL PRIMARY KEY, user_id BIGINT REFERENCES users(id) ON DELETE SET NULL, action VARCHAR(100) NOT NULL, -- LICENSE_ACTIVATED, LOGIN, LICENSE_REVOKED, etc. entity_type VARCHAR(50), -- LICENSE, USER, SETTING entity_id BIGINT, details JSONB, ip_address INET, created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP ); CREATE INDEX idx_audit_user ON audit_logs(user_id); CREATE INDEX idx_audit_action ON audit_logs(action); CREATE INDEX idx_audit_created ON audit_logs(created_at); ``` #### 7.4 Core Entities (JPA) **License.java** ```java @Entity @Table(name = "licenses") public class License { @Id @GeneratedValue(strategy = GenerationType.IDENTITY) private Long id; @Column(name = "license_key", unique = true, nullable = false, length = 29) private String licenseKey; @ManyToOne @JoinColumn(name = "user_id") private User user; @Enumerated(EnumType.STRING) private LicenseTier tier; @Enumerated(EnumType.STRING) private LicenseStatus status; @Column(name = "max_activations") private Integer maxActivations = 3; @Type(JsonBinaryType.class) @Column(columnDefinition = "jsonb") private List features; @Column(name = "issued_at") private LocalDateTime issuedAt; @Column(name = "expires_at") private LocalDateTime expiresAt; @Column(name = "trial_ends_at") private LocalDateTime trialEndsAt; @OneToMany(mappedBy = "license", cascade = CascadeType.ALL) private List activations; // Standard getters, setters, constructors } ``` **LicenseActivation.java** ```java @Entity @Table(name = "license_activations") public class LicenseActivation { @Id @GeneratedValue(strategy = GenerationType.IDENTITY) private Long id; @ManyToOne @JoinColumn(name = "license_id", nullable = false) private License license; @Column(name = "machine_id", nullable = false) private String machineId; private String platform; @Column(name = "app_version") private String appVersion; @Column(name = "activated_at") private LocalDateTime activatedAt; @Column(name = "last_validated_at") private LocalDateTime lastValidatedAt; @Column(name = "ip_address") private String ipAddress; private String hostname; // Standard getters, setters } ``` **User.java** ```java @Entity @Table(name = "users") public class User { @Id @GeneratedValue(strategy = GenerationType.IDENTITY) private Long id; private UUID uuid; @Column(unique = true, nullable = false) private String email; @Column(name = "password_hash", nullable = false) private String passwordHash; private String name; @Enumerated(EnumType.STRING) private UserRole role = UserRole.USER; private Boolean enabled = true; @Column(name = "created_at") private LocalDateTime createdAt; @Column(name = "last_login_at") private LocalDateTime lastLoginAt; @OneToMany(mappedBy = "user", cascade = CascadeType.ALL) private List licenses; // Standard getters, setters } ``` #### 7.5 REST API Endpoints **LicenseController.java** **POST /api/v1/licenses/activate** ```java @PostMapping("/activate") public ResponseEntity activateLicense( @RequestBody LicenseActivationRequest request ) { // Validate license key format // Check license exists and is active // Check activation limit // Create activation record // Generate signature // Return license data with features and signature } ``` **POST /api/v1/licenses/validate** ```java @PostMapping("/validate") public ResponseEntity validateLicense( @RequestBody LicenseValidationRequest request ) { // Find activation by license key + machine ID // Update last_validated_at // Check expiration // Return updated license data } ``` **POST /api/v1/licenses/deactivate** ```java @PostMapping("/deactivate") public ResponseEntity deactivateLicense( @RequestBody LicenseDeactivationRequest request, @AuthenticationPrincipal UserDetails userDetails ) { // Find activation // Verify ownership or admin // Delete activation record // Audit log } ``` **GET /api/v1/licenses/{licenseKey}/status** ```java @GetMapping("/{licenseKey}/status") @PreAuthorize("hasRole('USER')") public ResponseEntity getLicenseStatus( @PathVariable String licenseKey, @AuthenticationPrincipal UserDetails userDetails ) { // Verify ownership // Return license status, tier, expiration, activation count } ``` **AuthController.java** **POST /api/v1/auth/login** ```java @PostMapping("/login") public ResponseEntity login( @RequestBody LoginRequest request ) { // Authenticate credentials // Generate JWT token // Update last_login_at // Return token + user profile + associated licenses } ``` **POST /api/v1/auth/register** ```java @PostMapping("/register") public ResponseEntity register( @RequestBody UserRegistrationRequest request ) { // Validate email uniqueness // Hash password (BCrypt) // Create user // Return user profile } ``` **POST /api/v1/auth/refresh** ```java @PostMapping("/refresh") public ResponseEntity refreshToken( @RequestHeader("Authorization") String refreshToken ) { // Validate refresh token // Generate new access token // Return new token } ``` **UserController.java** **GET /api/v1/users/profile** ```java @GetMapping("/profile") @PreAuthorize("hasRole('USER')") public ResponseEntity getProfile( @AuthenticationPrincipal UserDetails userDetails ) { // Return user profile + licenses } ``` **PUT /api/v1/users/profile** ```java @PutMapping("/profile") @PreAuthorize("hasRole('USER')") public ResponseEntity updateProfile( @RequestBody UserUpdateRequest request, @AuthenticationPrincipal UserDetails userDetails ) { // Update user name, email, etc. // Return updated profile } ``` **GlobalSettingsController.java** **GET /api/v1/settings** ```java @GetMapping public ResponseEntity> getGlobalSettings() { // Return public global settings // e.g., allowed domains, feature flags, client update URLs } ``` **GET /api/v1/settings/{key}** ```java @GetMapping("/{key}") public ResponseEntity getSetting( @PathVariable String key ) { // Return specific setting value } ``` **PUT /api/v1/settings/{key}** (Admin only) ```java @PutMapping("/{key}") @PreAuthorize("hasRole('ADMIN')") public ResponseEntity updateSetting( @PathVariable String key, @RequestBody GlobalSettingUpdateRequest request ) { // Update setting value // Audit log } ``` #### 7.6 Service Layer **LicenseService.java** ```java @Service public class LicenseService { public LicenseActivationResponse activateLicense( String licenseKey, String machineId, String platform, String appVersion, String ipAddress ) { // 1. Find license by key // 2. Validate status (ACTIVE, not EXPIRED/REVOKED) // 3. Check expiration date // 4. Count current activations // 5. Enforce max_activations limit // 6. Create or update activation record // 7. Generate HMAC signature // 8. Return LicenseActivationResponse with: // - license key, tier, features, expiresAt // - signature (HMAC-SHA256) // 9. Audit log } public LicenseValidationResponse validateLicense( String licenseKey, String machineId ) { // 1. Find activation // 2. Check license status // 3. Check expiration // 4. Update last_validated_at // 5. Return updated license data } public void deactivateLicense(String licenseKey, String machineId, User user) { // 1. Find activation // 2. Verify ownership (user owns license OR user is admin) // 3. Delete activation // 4. Audit log } public String generateSignature(License license) { // HMAC-SHA256(licenseKey + tier + expiresAt, SECRET_KEY) String payload = license.getLicenseKey() + "|" + license.getTier() + "|" + license.getExpiresAt(); return HmacUtils.hmacSha256Hex(secretKey, payload); } public boolean verifySignature(License license, String signature) { return generateSignature(license).equals(signature); } } ``` **LicenseKeyGenerator.java** ```java @Service public class LicenseKeyGenerator { public String generateLicenseKey(LicenseTier tier) { // Format: TTTPP-RRRRR-RRRRR-CCCCC-RRRRR // TTT: Tier code (BAS, PRO, ENT) // PP: Product code (HB = HiveOps Browser) // R: Random alphanumeric // C: Checksum String tierCode = tier == LicenseTier.BASIC ? "BAS" : tier == LicenseTier.PRO ? "PRO" : "ENT"; String productCode = "HB"; String random1 = RandomStringUtils.randomAlphanumeric(5).toUpperCase(); String random2 = RandomStringUtils.randomAlphanumeric(5).toUpperCase(); String random3 = RandomStringUtils.randomAlphanumeric(5).toUpperCase(); String partialKey = tierCode + productCode + random1 + random2; String checksum = calculateChecksum(partialKey); return format(tierCode + productCode, random1, random2, checksum, random3); } private String calculateChecksum(String data) { // Simple checksum using CRC or custom algorithm int sum = 0; for (char c : data.toCharArray()) { sum += c; } return String.format("%05d", sum % 100000).substring(0, 5); } private String format(String p1, String p2, String p3, String p4, String p5) { return p1 + "-" + p2 + "-" + p3 + "-" + p4 + "-" + p5; } } ``` #### 7.7 Security Configuration **SecurityConfig.java** ```java @Configuration @EnableWebSecurity @EnableMethodSecurity public class SecurityConfig { @Bean public SecurityFilterChain filterChain(HttpSecurity http) throws Exception { http .csrf().disable() .cors().and() .authorizeHttpRequests(auth -> auth .requestMatchers("/api/v1/auth/**").permitAll() .requestMatchers("/api/v1/licenses/activate").permitAll() .requestMatchers("/api/v1/licenses/validate").permitAll() .requestMatchers("/api/v1/settings").permitAll() .requestMatchers("/api/v1/admin/**").hasRole("ADMIN") .anyRequest().authenticated() ) .sessionManagement() .sessionCreationPolicy(SessionCreationPolicy.STATELESS) .and() .addFilterBefore(jwtAuthenticationFilter(), UsernamePasswordAuthenticationFilter.class); return http.build(); } @Bean public PasswordEncoder passwordEncoder() { return new BCryptPasswordEncoder(12); } @Bean public JwtAuthenticationFilter jwtAuthenticationFilter() { return new JwtAuthenticationFilter(); } } ``` **JwtTokenProvider.java** ```java @Component public class JwtTokenProvider { @Value("${jwt.secret}") private String jwtSecret; @Value("${jwt.expiration}") private long jwtExpiration = 86400000; // 24 hours public String generateToken(User user) { Date now = new Date(); Date expiryDate = new Date(now.getTime() + jwtExpiration); return Jwts.builder() .setSubject(user.getEmail()) .claim("userId", user.getId()) .claim("role", user.getRole()) .setIssuedAt(now) .setExpiration(expiryDate) .signWith(SignatureAlgorithm.HS512, jwtSecret) .compact(); } public String getUserEmailFromToken(String token) { Claims claims = Jwts.parser() .setSigningKey(jwtSecret) .parseClaimsJws(token) .getBody(); return claims.getSubject(); } public boolean validateToken(String token) { try { Jwts.parser().setSigningKey(jwtSecret).parseClaimsJws(token); return true; } catch (Exception e) { return false; } } } ``` #### 7.8 Configuration Files **application.yml** ```yaml spring: application: name: hiveops-mgmt datasource: url: jdbc:postgresql://localhost:5432/hiveops_mgmt username: ${DB_USERNAME:hiveops} password: ${DB_PASSWORD:changeme} driver-class-name: org.postgresql.Driver jpa: hibernate: ddl-auto: validate # Use Flyway for migrations show-sql: false properties: hibernate: dialect: org.hibernate.dialect.PostgreSQLDialect format_sql: true flyway: enabled: true locations: classpath:db/migration baseline-on-migrate: true server: port: 8080 servlet: context-path: /api jwt: secret: ${JWT_SECRET:your-secret-key-change-in-production} expiration: 86400000 # 24 hours license: signature-secret: ${LICENSE_SECRET:your-license-secret-key} max-activations-default: 3 offline-grace-period-days: 7 logging: level: com.hiveops.mgmt: DEBUG org.springframework.security: DEBUG ``` **application-prod.yml** ```yaml spring: datasource: url: jdbc:postgresql://${DB_HOST:localhost}:${DB_PORT:5432}/${DB_NAME:hiveops_mgmt} jpa: show-sql: false logging: level: com.hiveops.mgmt: INFO org.springframework.security: WARN server: port: ${PORT:8080} ssl: enabled: ${SSL_ENABLED:false} key-store: ${SSL_KEYSTORE_PATH} key-store-password: ${SSL_KEYSTORE_PASSWORD} ``` #### 7.9 Docker Configuration **Dockerfile** ```dockerfile FROM eclipse-temurin:21-jre-alpine WORKDIR /app COPY target/hiveops-mgmt-*.jar app.jar EXPOSE 8080 ENV JAVA_OPTS="-Xmx512m -Xms256m" ENTRYPOINT ["sh", "-c", "java $JAVA_OPTS -jar app.jar"] ``` **docker-compose.yml** ```yaml version: '3.8' services: postgres: image: postgres:16-alpine environment: POSTGRES_DB: hiveops_mgmt POSTGRES_USER: hiveops POSTGRES_PASSWORD: changeme ports: - "5432:5432" volumes: - postgres_data:/var/lib/postgresql/data networks: - hiveops-network hiveops-mgmt: build: . ports: - "8080:8080" environment: DB_HOST: postgres DB_PORT: 5432 DB_NAME: hiveops_mgmt DB_USERNAME: hiveops DB_PASSWORD: changeme JWT_SECRET: your-production-jwt-secret LICENSE_SECRET: your-production-license-secret depends_on: - postgres networks: - hiveops-network volumes: postgres_data: networks: hiveops-network: driver: bridge ``` #### 7.10 Maven Dependencies (pom.xml) ```xml org.springframework.boot spring-boot-starter-web org.springframework.boot spring-boot-starter-data-jpa org.springframework.boot spring-boot-starter-security org.springframework.boot spring-boot-starter-validation org.postgresql postgresql runtime org.flywaydb flyway-core io.jsonwebtoken jjwt-api 0.11.5 io.jsonwebtoken jjwt-impl 0.11.5 runtime io.jsonwebtoken jjwt-jackson 0.11.5 runtime com.vladmihalcea hibernate-types-60 2.21.1 org.springdoc springdoc-openapi-starter-webmvc-ui 2.2.0 org.projectlombok lombok true org.apache.commons commons-lang3 commons-codec commons-codec org.springframework.boot spring-boot-starter-test test org.springframework.security spring-security-test test ``` ### 8. Browser Client Updates (Connects to hiveops-mgmt) The browser client API implementation from earlier sections remains mostly the same, but with these key changes: **api-client.js modifications:** - Base URL points to hiveops-mgmt: `https://api.hiveops.com/api/v1` (adjust based on deployment) - All endpoints match the Spring Boot REST API paths - Error handling matches Spring Boot error response format ### 9. API Server Requirements (Now hiveops-mgmt Implementation) The external API must implement these endpoints (implemented in Spring Boot microservice above): **POST /v1/licenses/activate** - Validate license key - Check activation limit (e.g., max 3 devices) - Store machine ID - Return license data with signature - Status: 200 (success), 400 (invalid), 409 (max activations), 410 (expired) **POST /v1/licenses/validate** - Verify license still valid - Check revocation status - Return updated license data - Status: 200 (valid), 403 (invalid/expired) **POST /v1/auth/login** - Authenticate user credentials - Return JWT token + user profile + associated license - Status: 200 (success), 401 (invalid credentials) **GET /v1/users/profile** (Bearer token required) - Return user profile and license list - Status: 200 (success), 401 (unauthorized) **GET /v1/licenses/{key}/status** (Bearer token required) - Return license status, expiration, tier, features - Return activation count (current/max) - Status: 200 (success), 404 (not found) **POST /v1/licenses/deactivate** - Remove machine ID from activation list - Free up activation slot - Status: 200 (success), 404 (not found) ### 8. Testing Strategy #### 8.1 License Validation Testing - [ ] Valid license key format accepted - [ ] Invalid format rejected - [ ] Expired license blocks app startup - [ ] Valid license allows app to run - [ ] Signature tampering detected and rejected - [ ] Feature gates work correctly per tier #### 8.2 API Integration Testing - [ ] Successful license activation - [ ] Invalid key returns error - [ ] Network error handled gracefully - [ ] Timeout handled (30s) - [ ] Offline mode uses local validation - [ ] Online validation updates local cache #### 8.3 Authentication Testing - [ ] Successful login stores token and profile - [ ] Invalid credentials show error - [ ] Logout clears session data - [ ] Token expiration triggers re-login #### 8.4 Protocol Handler Testing - [ ] `hiveops://open?url=https://test.hiveops.com` opens URL - [ ] Invalid URLs blocked - [ ] Single instance enforcement works - [ ] Windows registry entries created on install - [ ] Linux .desktop file includes MIME type #### 8.5 Feature Gate Testing - [ ] Basic tier: Only basic features available - [ ] Pro tier: Advanced features unlocked - [ ] Enterprise tier: All features available - [ ] Feature upgrade prompt shows correctly #### 8.6 Security Testing - [ ] License data encryption verified - [ ] Signature tampering detected - [ ] Machine ID consistent across runs - [ ] API authentication required - [ ] Offline grace period enforced ### 9. Implementation Timeline #### Phase 1: Microservice Backend (hiveops-mgmt) - Weeks 1-3 **Week 1: Project Setup & Core Entities** 1. Create new Spring Boot 4 project (Maven/Gradle) 2. Set up PostgreSQL database and docker-compose 3. Configure Spring Security, JPA, Flyway 4. Create database schema (migrations) 5. Implement entity classes (User, License, LicenseActivation, GlobalSetting) 6. Create repositories (Spring Data JPA) 7. Write unit tests for entities **Week 2: Service Layer & Business Logic** 8. Implement LicenseService (activate, validate, deactivate) 9. Implement AuthService (login, register, token management) 10. Implement UserService (profile, CRUD) 11. Implement GlobalSettingsService 12. Create LicenseKeyGenerator with checksum validation 13. Implement signature generation/verification (HMAC-SHA256) 14. Write service layer unit tests **Week 3: REST API & Security** 15. Implement LicenseController with all endpoints 16. Implement AuthController (login, register, refresh) 17. Implement UserController (profile management) 18. Implement GlobalSettingsController 19. Configure JWT authentication filter 20. Add global exception handling 21. Set up API documentation (SpringDoc/Swagger) 22. Integration tests for all endpoints 23. Security testing (authentication, authorization) #### Phase 2: Browser Client (hiveops-browser) - Weeks 4-6 **Week 4: Client Infrastructure** 24. Create `license-manager.js` with client-side validation 25. Create `api-client.js` connecting to hiveops-mgmt 26. Create `auth-manager.js` with token management 27. Update `preload.js` with new IPC APIs 28. Add IPC handlers to `main.js` 29. Test API communication with backend 30. Test license storage and validation **Week 5: UI Development** 31. Create `license-activation.html/js` with dual-tab interface 32. Create `license-management.html/js` with status display 33. Create `license.css` for styling 34. Update `settings.html` with license info section 35. Update `about.html` to show tier 36. Test all UI flows with mock data 37. Integration with real backend API **Week 6: Features & Integration** 38. Modify `main.js` startup to check license 39. Add background validation (24-hour interval) 40. Update `config.js` with feature gates 41. Implement feature-gated menu items 42. Add expiration warnings 43. Test end-to-end flows (client + backend) #### Phase 3: Protocol Handler & Distribution - Week 7 **Week 7: Protocol & Build** 44. Update `electron-builder.yml` with protocol config 45. Create `installer-script.nsh` for Windows 46. Add protocol handling to `main.js` 47. Test protocol handler on all platforms 48. Full integration testing (client + backend + protocol) 49. Security testing and penetration tests #### Phase 4: Deployment & Documentation - Week 8 **Week 8: Deploy & Polish** 50. Deploy hiveops-mgmt to production (Docker/K8s) 51. Configure production database (PostgreSQL) 52. Set up SSL/TLS certificates 53. Build and test installers (Windows/Linux) 54. Write user documentation 55. Write API documentation 56. Create admin panel for license management (optional) 57. Final QA and release ### 10. Critical Files Summary #### hiveops-mgmt (Spring Boot Microservice - NEW REPOSITORY) **New Java Files** (~30 files): - `HiveOpsMgmtApplication.java` - Main Spring Boot application - `SecurityConfig.java` - Spring Security configuration - `JwtConfig.java` - JWT configuration - `LicenseController.java` - License REST endpoints - `AuthController.java` - Authentication endpoints - `UserController.java` - User management endpoints - `GlobalSettingsController.java` - Settings endpoints - `LicenseService.java` - License business logic - `AuthService.java` - Authentication service - `UserService.java` - User service - `LicenseKeyGenerator.java` - Key generation logic - `GlobalSettingsService.java` - Settings service - `License.java` - License entity (JPA) - `User.java` - User entity - `LicenseActivation.java` - Activation entity - `GlobalSetting.java` - Setting entity - `JwtTokenProvider.java` - JWT token handling - `JwtAuthenticationFilter.java` - JWT filter - `GlobalExceptionHandler.java` - Exception handling - DTO classes (requests/responses) - Repository interfaces - Utility classes **Configuration Files**: - `application.yml` - Main configuration - `application-prod.yml` - Production config - `pom.xml` - Maven dependencies - `Dockerfile` - Container config - `docker-compose.yml` - Local development - `V1__init_schema.sql` - Flyway migration - `installer-script.nsh` - Windows protocol registration #### hiveops-browser (Electron Client - EXISTING REPOSITORY) **New Files** (9 total): - `src/main/license-manager.js` - License validation core - `src/main/api-client.js` - External API communication - `src/main/auth-manager.js` - User authentication - `src/renderer/license-activation.html` - Activation UI - `src/renderer/license-activation.js` - Activation logic - `src/renderer/license-management.html` - Management UI - `src/renderer/license-management.js` - Management logic - `src/renderer/license.css` - License UI styles - `installer-script.nsh` - Windows protocol registration **Modified Files** (6 total): - `src/main/main.js` - Add license checks, protocol handler, IPC handlers - `src/main/config.js` - Add feature gates, license-aware URL validation - `src/main/preload.js` - Expose license/auth APIs - `src/renderer/settings.html` - Add license info section - `config/default-config.json` - Add apiBaseUrl - `electron-builder.yml` - Add protocol registration - `package.json` - Update version to 2.0.0 ### 11. Verification Checklist #### Backend (hiveops-mgmt) Verification - [ ] Spring Boot application starts without errors - [ ] Database schema created via Flyway - [ ] PostgreSQL connection established - [ ] Swagger UI accessible at `/swagger-ui.html` - [ ] License activation endpoint works - [ ] License validation endpoint works - [ ] User login returns JWT token - [ ] JWT authentication filter validates tokens - [ ] License signature verification works - [ ] Activation limit enforcement works (max 3 devices) - [ ] License expiration checked correctly - [ ] Global settings CRUD operations work - [ ] Audit logs created for actions - [ ] API error handling returns proper status codes - [ ] Docker container builds and runs - [ ] docker-compose brings up full stack #### Client (hiveops-browser) Verification - [ ] Fresh install shows license activation screen - [ ] Valid license key activates successfully via API - [ ] Invalid license key shows error from backend - [ ] User login works and stores profile + token - [ ] Main window opens after successful activation - [ ] License expiration is enforced - [ ] Feature gates work per tier (Basic/Pro/Enterprise) - [ ] Protocol handler opens app with URL (hiveops://) - [ ] Settings page shows license info - [ ] License management shows all data from backend - [ ] Deactivation calls backend API and quits - [ ] Offline operation works (local validation) - [ ] Background validation (24hr) calls backend - [ ] Network errors handled gracefully - [ ] Build creates installers with protocol registration - [ ] Windows installer registers protocol in registry - [ ] Linux .deb includes MIME type associations #### Integration Testing - [ ] End-to-end: Activate license from fresh install - [ ] End-to-end: Login with user account - [ ] End-to-end: Validate license online - [ ] End-to-end: Deactivate license - [ ] Backend handles concurrent activations - [ ] Backend enforces activation limits - [ ] Client handles backend downtime gracefully - [ ] Offline mode works for 7 days - [ ] Expired license blocks app startup - [ ] Revoked license detected on validation ### 12. Deployment Guide #### Backend Deployment (hiveops-mgmt) **Infrastructure Requirements**: - **Server**: 2 vCPU, 4GB RAM minimum - **Database**: PostgreSQL 16+ (separate instance recommended) - **Storage**: 20GB minimum - **Network**: SSL/TLS certificate for HTTPS **Deployment Options**: **Option 1: Docker (Recommended)** ```bash # Build and run with docker-compose docker-compose up -d # Or deploy to container orchestration docker build -t hiveops-mgmt:latest . docker push registry.hiveops.com/hiveops-mgmt:latest ``` **Option 2: Kubernetes** ```yaml # Create deployment, service, ingress kubectl apply -f k8s/deployment.yaml kubectl apply -f k8s/service.yaml kubectl apply -f k8s/ingress.yaml ``` **Option 3: Traditional Server (JAR)** ```bash # Build JAR mvn clean package -DskipTests # Run with production profile java -jar target/hiveops-mgmt-1.0.0.jar \ --spring.profiles.active=prod \ --server.port=8080 ``` **Environment Variables (Production)**: ```bash DB_HOST=postgres.hiveops.com DB_PORT=5432 DB_NAME=hiveops_mgmt DB_USERNAME=hiveops_user DB_PASSWORD= JWT_SECRET= LICENSE_SECRET= SSL_ENABLED=true SSL_KEYSTORE_PATH=/etc/ssl/hiveops.jks SSL_KEYSTORE_PASSWORD= ``` **Database Setup**: ```sql -- Create database and user CREATE DATABASE hiveops_mgmt; CREATE USER hiveops_user WITH ENCRYPTED PASSWORD 'secure-password'; GRANT ALL PRIVILEGES ON DATABASE hiveops_mgmt TO hiveops_user; -- Flyway will handle schema migrations automatically ``` **SSL/TLS Certificate**: ```bash # Generate Let's Encrypt certificate certbot certonly --standalone -d api.hiveops.com # Or use existing certificate # Configure in application-prod.yml ``` **Post-Deployment Checks**: - [ ] Health check: `curl https://api.hiveops.com/api/actuator/health` - [ ] Swagger UI: `https://api.hiveops.com/api/swagger-ui.html` - [ ] Test license activation endpoint - [ ] Test user login endpoint - [ ] Verify database connectivity - [ ] Check logs for errors #### Client Deployment (hiveops-browser) **Build Configuration**: 1. Update `config/default-config.json`: ```json { "apiBaseUrl": "https://api.hiveops.com/api/v1" } ``` 2. Update version in `package.json`: ```json { "version": "2.0.0" } ``` 3. Build installers: ```bash # Build all platforms ./build-all.sh # Or individually npm run build:linux npm run build:win ``` **Distribution**: - Windows: `dist/customer-packages/windows/HiveOps Browser Setup 2.0.0.exe` - Linux: `dist/customer-packages/linux/hiveops-browser_2.0.0_amd64.deb` - AppImage: `dist/customer-packages/linux/HiveOps Browser-2.0.0.AppImage` **Deployment Prerequisites**: 1. ✅ Backend API deployed and accessible 2. ✅ Database populated with initial data 3. ✅ SSL certificates configured 4. ✅ DNS records set (api.hiveops.com) 5. ✅ Monitoring and logging configured 6. ✅ Admin user created for license management 7. ✅ Initial license keys generated for testing 8. ✅ Documentation prepared 9. ✅ Support channel established ### 13. Post-Launch Monitoring **Backend Monitoring (hiveops-mgmt)**: - API response times and latency - Database query performance - License activation/validation success rate - Failed authentication attempts (security) - API error rates (4xx, 5xx) - Active license count by tier - Server resource usage (CPU, memory, disk) - Database connection pool utilization **Client Monitoring**: - License activation success rate - Offline validation failures - Feature gate usage by tier - Protocol handler usage - Crash reports and errors - User feedback on licensing UX - Update installation rates **Recommended Tools**: - **Backend**: Spring Boot Actuator + Prometheus + Grafana - **Database**: PostgreSQL pg_stat_statements - **Logging**: ELK Stack (Elasticsearch, Logstash, Kibana) - **Alerts**: PagerDuty or similar - **Client**: Sentry for error tracking --- ## Implementation Summary ### Two-Component Architecture ``` ┌─────────────────────────────────────┐ │ HiveOps Browser (Electron) │ │ - License validation UI │ │ - Protocol handler (hiveops://) │ │ - Feature gates (Basic/Pro/Ent) │ │ - Offline validation (7-day grace)│ │ - Background sync (24hr) │ └─────────────┬───────────────────────┘ │ HTTPS/REST API │ (JWT Authentication) ▼ ┌─────────────────────────────────────┐ │ hiveops-mgmt (Spring Boot 4) │ │ - License activation/validation │ │ - User authentication (JWT) │ │ - License key generation │ │ - Feature management │ │ - Global settings │ │ - Audit logging │ └─────────────┬───────────────────────┘ │ ▼ ┌─────────────────────────────────────┐ │ PostgreSQL Database │ │ - users │ │ - licenses │ │ - license_activations │ │ - global_settings │ │ - audit_logs │ └─────────────────────────────────────┘ ``` ### Key Features **Licensing System**: - Three-tier license model (Basic, Pro, Enterprise) - Machine-based activation (max 3 devices per license) - Online validation with offline grace period (7 days) - License expiration and trial support - Anti-tamper signature verification (HMAC-SHA256) - Revocation support **User Management**: - User authentication with JWT - User profile with associated licenses - Role-based access control (USER, ADMIN) - Password hashing (BCrypt) **Protocol Handling**: - Custom protocol: `hiveops://` - Domain-based: `*.hiveops.com` - Platform-specific registration (Windows registry, Linux MIME types) - Deep linking support **Security**: - Encrypted license storage (electron-store) - JWT authentication (Spring Security) - HTTPS-only API communication - SQL injection prevention (parameterized queries) - XSS protection (CSP headers) - Audit logging for all actions ### Total Effort Estimate - **Backend Development**: 3 weeks - **Client Development**: 3 weeks - **Integration & Testing**: 1 week - **Deployment & Documentation**: 1 week - **Total**: 8 weeks (2 months) ### Success Metrics - ✅ License activation success rate > 95% - ✅ API response time < 200ms (p95) - ✅ Zero license bypass incidents - ✅ Offline operation works seamlessly - ✅ Protocol handler registration success > 90% - ✅ User satisfaction score > 4/5