1749 lines
52 KiB
Markdown
1749 lines
52 KiB
Markdown
# 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<String> 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<LicenseActivation> 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<License> licenses;
|
|
|
|
// Standard getters, setters
|
|
}
|
|
```
|
|
|
|
#### 7.5 REST API Endpoints
|
|
|
|
**LicenseController.java**
|
|
|
|
**POST /api/v1/licenses/activate**
|
|
```java
|
|
@PostMapping("/activate")
|
|
public ResponseEntity<LicenseActivationResponse> 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<LicenseValidationResponse> 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<Void> 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<LicenseStatusResponse> 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<LoginResponse> 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<UserProfileResponse> 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<TokenResponse> 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<UserProfileResponse> getProfile(
|
|
@AuthenticationPrincipal UserDetails userDetails
|
|
) {
|
|
// Return user profile + licenses
|
|
}
|
|
```
|
|
|
|
**PUT /api/v1/users/profile**
|
|
```java
|
|
@PutMapping("/profile")
|
|
@PreAuthorize("hasRole('USER')")
|
|
public ResponseEntity<UserProfileResponse> 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<Map<String, Object>> getGlobalSettings() {
|
|
// Return public global settings
|
|
// e.g., allowed domains, feature flags, client update URLs
|
|
}
|
|
```
|
|
|
|
**GET /api/v1/settings/{key}**
|
|
```java
|
|
@GetMapping("/{key}")
|
|
public ResponseEntity<GlobalSettingResponse> getSetting(
|
|
@PathVariable String key
|
|
) {
|
|
// Return specific setting value
|
|
}
|
|
```
|
|
|
|
**PUT /api/v1/settings/{key}** (Admin only)
|
|
```java
|
|
@PutMapping("/{key}")
|
|
@PreAuthorize("hasRole('ADMIN')")
|
|
public ResponseEntity<GlobalSettingResponse> 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
|
|
<dependencies>
|
|
<!-- Spring Boot Starters -->
|
|
<dependency>
|
|
<groupId>org.springframework.boot</groupId>
|
|
<artifactId>spring-boot-starter-web</artifactId>
|
|
</dependency>
|
|
<dependency>
|
|
<groupId>org.springframework.boot</groupId>
|
|
<artifactId>spring-boot-starter-data-jpa</artifactId>
|
|
</dependency>
|
|
<dependency>
|
|
<groupId>org.springframework.boot</groupId>
|
|
<artifactId>spring-boot-starter-security</artifactId>
|
|
</dependency>
|
|
<dependency>
|
|
<groupId>org.springframework.boot</groupId>
|
|
<artifactId>spring-boot-starter-validation</artifactId>
|
|
</dependency>
|
|
|
|
<!-- Database -->
|
|
<dependency>
|
|
<groupId>org.postgresql</groupId>
|
|
<artifactId>postgresql</artifactId>
|
|
<scope>runtime</scope>
|
|
</dependency>
|
|
<dependency>
|
|
<groupId>org.flywaydb</groupId>
|
|
<artifactId>flyway-core</artifactId>
|
|
</dependency>
|
|
|
|
<!-- JWT -->
|
|
<dependency>
|
|
<groupId>io.jsonwebtoken</groupId>
|
|
<artifactId>jjwt-api</artifactId>
|
|
<version>0.11.5</version>
|
|
</dependency>
|
|
<dependency>
|
|
<groupId>io.jsonwebtoken</groupId>
|
|
<artifactId>jjwt-impl</artifactId>
|
|
<version>0.11.5</version>
|
|
<scope>runtime</scope>
|
|
</dependency>
|
|
<dependency>
|
|
<groupId>io.jsonwebtoken</groupId>
|
|
<artifactId>jjwt-jackson</artifactId>
|
|
<version>0.11.5</version>
|
|
<scope>runtime</scope>
|
|
</dependency>
|
|
|
|
<!-- JSON support -->
|
|
<dependency>
|
|
<groupId>com.vladmihalcea</groupId>
|
|
<artifactId>hibernate-types-60</artifactId>
|
|
<version>2.21.1</version>
|
|
</dependency>
|
|
|
|
<!-- API Documentation -->
|
|
<dependency>
|
|
<groupId>org.springdoc</groupId>
|
|
<artifactId>springdoc-openapi-starter-webmvc-ui</artifactId>
|
|
<version>2.2.0</version>
|
|
</dependency>
|
|
|
|
<!-- Utilities -->
|
|
<dependency>
|
|
<groupId>org.projectlombok</groupId>
|
|
<artifactId>lombok</artifactId>
|
|
<optional>true</optional>
|
|
</dependency>
|
|
<dependency>
|
|
<groupId>org.apache.commons</groupId>
|
|
<artifactId>commons-lang3</artifactId>
|
|
</dependency>
|
|
<dependency>
|
|
<groupId>commons-codec</groupId>
|
|
<artifactId>commons-codec</artifactId>
|
|
</dependency>
|
|
|
|
<!-- Testing -->
|
|
<dependency>
|
|
<groupId>org.springframework.boot</groupId>
|
|
<artifactId>spring-boot-starter-test</artifactId>
|
|
<scope>test</scope>
|
|
</dependency>
|
|
<dependency>
|
|
<groupId>org.springframework.security</groupId>
|
|
<artifactId>spring-security-test</artifactId>
|
|
<scope>test</scope>
|
|
</dependency>
|
|
</dependencies>
|
|
```
|
|
|
|
### 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=<secure-password>
|
|
JWT_SECRET=<generate-secure-secret>
|
|
LICENSE_SECRET=<generate-secure-secret>
|
|
SSL_ENABLED=true
|
|
SSL_KEYSTORE_PATH=/etc/ssl/hiveops.jks
|
|
SSL_KEYSTORE_PASSWORD=<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
|