nostr-auth-middleware 0.2.7
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE +21 -0
- package/README.md +216 -0
- package/dist/__tests__/nostr-auth.middleware.test.d.ts +1 -0
- package/dist/__tests__/nostr-auth.middleware.test.js +104 -0
- package/dist/config/index.d.ts +7 -0
- package/dist/config/index.js +148 -0
- package/dist/config/index.js.map +1 -0
- package/dist/config.d.ts +3 -0
- package/dist/config.js +68 -0
- package/dist/config.js.map +1 -0
- package/dist/index.d.ts +33 -0
- package/dist/index.js +39 -0
- package/dist/index.js.map +1 -0
- package/dist/interfaces/nostr.interface.d.ts +29 -0
- package/dist/interfaces/nostr.interface.js +1 -0
- package/dist/middleware/nostr-auth.middleware.d.ts +14 -0
- package/dist/middleware/nostr-auth.middleware.js +102 -0
- package/dist/middleware/nostr-auth.middleware.js.map +1 -0
- package/dist/middleware/security.middleware.d.ts +5 -0
- package/dist/middleware/security.middleware.js +55 -0
- package/dist/middleware/security.middleware.js.map +1 -0
- package/dist/models/nostr-profile.d.ts +9 -0
- package/dist/models/nostr-profile.js +1 -0
- package/dist/scripts/generate-keypair.js +15 -0
- package/dist/scripts/tests/create-test-user.js +19 -0
- package/dist/scripts/tests/test-auth-live.js +156 -0
- package/dist/server.d.ts +1 -0
- package/dist/server.js +67 -0
- package/dist/server.js.map +1 -0
- package/dist/services/nostr.service.d.ts +11 -0
- package/dist/services/nostr.service.js +110 -0
- package/dist/services/nostr.service.js.map +1 -0
- package/dist/src/config/index.js +148 -0
- package/dist/src/config.js +60 -0
- package/dist/src/index.js +39 -0
- package/dist/src/middleware/nostr-auth.middleware.js +120 -0
- package/dist/src/middleware/security.middleware.js +55 -0
- package/dist/src/server.js +67 -0
- package/dist/src/services/nostr.service.js +287 -0
- package/dist/src/types/index.js +1 -0
- package/dist/src/utils/api-key.utils.js +72 -0
- package/dist/src/utils/crypto.utils.js +81 -0
- package/dist/src/utils/domain.utils.js +67 -0
- package/dist/src/utils/logger.js +25 -0
- package/dist/src/utils/types.js +1 -0
- package/dist/src/validators/event.validator.js +144 -0
- package/dist/types/index.d.ts +58 -0
- package/dist/types/index.js +1 -0
- package/dist/types/index.js.map +1 -0
- package/dist/types.d.ts +57 -0
- package/dist/types.js +1 -0
- package/dist/utils/api-key.utils.d.ts +10 -0
- package/dist/utils/api-key.utils.js +65 -0
- package/dist/utils/api-key.utils.js.map +1 -0
- package/dist/utils/crypto.utils.d.ts +9 -0
- package/dist/utils/crypto.utils.js +80 -0
- package/dist/utils/crypto.utils.js.map +1 -0
- package/dist/utils/domain.utils.d.ts +31 -0
- package/dist/utils/domain.utils.js +67 -0
- package/dist/utils/domain.utils.js.map +1 -0
- package/dist/utils/jwt.utils.d.ts +4 -0
- package/dist/utils/jwt.utils.js +22 -0
- package/dist/utils/logger.d.ts +2 -0
- package/dist/utils/logger.js +25 -0
- package/dist/utils/logger.js.map +1 -0
- package/dist/utils/types.d.ts +14 -0
- package/dist/utils/types.js +1 -0
- package/dist/utils/types.js.map +1 -0
- package/dist/validators/event.validator.d.ts +14 -0
- package/dist/validators/event.validator.js +137 -0
- package/dist/validators/event.validator.js.map +1 -0
- package/dist/validators/nostr-event.validator.d.ts +4 -0
- package/dist/validators/nostr-event.validator.js +14 -0
- package/package.json +120 -0
package/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2024 MaiQR.app
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
package/README.md
ADDED
|
@@ -0,0 +1,216 @@
|
|
|
1
|
+
# Nostr Auth Middleware
|
|
2
|
+
|
|
3
|
+
A focused, security-first authentication middleware for Nostr applications.
|
|
4
|
+
|
|
5
|
+
⚠️ **Important Security Notice**
|
|
6
|
+
|
|
7
|
+
This library handles cryptographic keys and authentication tokens that are critical for securing your Nostr application and user data. Any private keys (`nsec`) or authentication tokens must be stored and managed with the utmost security and care.
|
|
8
|
+
|
|
9
|
+
Developers using this middleware must inform their users about the critical nature of managing private keys and tokens. It is the user's responsibility to securely store and manage these credentials. The library and its authors disclaim any responsibility or liability for lost keys, compromised tokens, or data resulting from mismanagement.
|
|
10
|
+
|
|
11
|
+
## Project Philosophy
|
|
12
|
+
|
|
13
|
+
This middleware follows key principles that promote security, auditability, and simplicity:
|
|
14
|
+
|
|
15
|
+
### 1. Single Responsibility
|
|
16
|
+
- **Authentication Only**: Handles only Nostr key-based authentication
|
|
17
|
+
- **No Business Logic**: Business rules, user tiers, and application logic belong in your API layer
|
|
18
|
+
- **Simple JWT**: Issues basic JWTs with minimal claims (npub, timestamp)
|
|
19
|
+
|
|
20
|
+
### 2. Security First
|
|
21
|
+
- **Open Source**: Fully auditable security-critical code
|
|
22
|
+
- **Transparent**: Clear, readable implementation
|
|
23
|
+
- **Focused Scope**: Does one thing well - Nostr authentication
|
|
24
|
+
|
|
25
|
+
### 3. Integration Ready
|
|
26
|
+
```plaintext
|
|
27
|
+
┌─────────────────┐
|
|
28
|
+
│ Client App │
|
|
29
|
+
└────────┬────────┘
|
|
30
|
+
│
|
|
31
|
+
▼
|
|
32
|
+
┌─────────────────┐
|
|
33
|
+
│ Nostr Auth │ ◄── This Service
|
|
34
|
+
│ Service │ Simple Auth Only
|
|
35
|
+
└────────┬────────┘
|
|
36
|
+
│
|
|
37
|
+
▼
|
|
38
|
+
┌─────────────────┐
|
|
39
|
+
│ App Platform │ ◄── Your Business Logic
|
|
40
|
+
│ API │ User Tiers
|
|
41
|
+
└─────────────────┘ Rate Limits
|
|
42
|
+
```
|
|
43
|
+
|
|
44
|
+
## Core Features
|
|
45
|
+
|
|
46
|
+
- 🔑 NIP-07 Compatible Authentication
|
|
47
|
+
- 📝 Secure User Enrollment with Nostr
|
|
48
|
+
- ⚡ Comprehensive Event Validation
|
|
49
|
+
- 🔒 Advanced Cryptographic Operations
|
|
50
|
+
- 🗄️ Supabase Integration for Data Persistence
|
|
51
|
+
- 🎫 JWT-based Session Management
|
|
52
|
+
- 🔄 Profile Management & Synchronization
|
|
53
|
+
- 📊 Detailed Logging and Monitoring
|
|
54
|
+
- 🔐 Automatic Key Management
|
|
55
|
+
- 🚀 Environment-Aware Deployment
|
|
56
|
+
- 🛠️ Development & Production Modes
|
|
57
|
+
- 📁 Automated Directory Management
|
|
58
|
+
|
|
59
|
+
## Documentation
|
|
60
|
+
|
|
61
|
+
- [Architecture Guide](docs/architecture-guide.md) - Understanding the service architecture
|
|
62
|
+
- [Key Management Guide](docs/key-management.md) - Comprehensive key management documentation
|
|
63
|
+
- [Deployment Guide](docs/deployment-guide.md) - Environment-specific deployment instructions
|
|
64
|
+
- [Getting Started](docs/getting-started.md) - Quick start guide
|
|
65
|
+
- [Authentication Flow](docs/authentication-flow.md) - Detailed authentication process
|
|
66
|
+
- [Troubleshooting Guide](docs/troubleshooting.md) - Common issues and solutions
|
|
67
|
+
- [API Documentation](docs/api.md) - API endpoints and usage
|
|
68
|
+
- [Security Guide](docs/security.md) - Security best practices and considerations
|
|
69
|
+
- [Automated Tests](docs/automated-tests.md) - Comprehensive test suite documentation
|
|
70
|
+
|
|
71
|
+
## Testing
|
|
72
|
+
|
|
73
|
+
The middleware includes comprehensive test coverage for all core functionality:
|
|
74
|
+
|
|
75
|
+
- ✅ Challenge Generation & Verification
|
|
76
|
+
- ✅ Profile Fetching
|
|
77
|
+
- ✅ Enrollment & Verification
|
|
78
|
+
- ✅ Error Handling
|
|
79
|
+
- ✅ Router Integration
|
|
80
|
+
|
|
81
|
+
Current test coverage: 94.8%
|
|
82
|
+
|
|
83
|
+
For detailed information about the test suite, please see our [Automated Tests Documentation](docs/automated-tests.md).
|
|
84
|
+
|
|
85
|
+
To run the tests:
|
|
86
|
+
|
|
87
|
+
```bash
|
|
88
|
+
npm test
|
|
89
|
+
```
|
|
90
|
+
|
|
91
|
+
For live testing with actual Nostr relays:
|
|
92
|
+
|
|
93
|
+
```bash
|
|
94
|
+
npm run test:live
|
|
95
|
+
```
|
|
96
|
+
|
|
97
|
+
For testing authentication flow:
|
|
98
|
+
|
|
99
|
+
```bash
|
|
100
|
+
npm run test:auth
|
|
101
|
+
```
|
|
102
|
+
|
|
103
|
+
## Quick Start
|
|
104
|
+
|
|
105
|
+
1. Clone the repository
|
|
106
|
+
2. Copy `.env.example` to `.env`
|
|
107
|
+
3. Run `./scripts/startup.sh`
|
|
108
|
+
|
|
109
|
+
The server will automatically:
|
|
110
|
+
- Configure itself based on the environment (development/production)
|
|
111
|
+
- Generate server keys if none exist
|
|
112
|
+
- Create necessary directories with proper permissions
|
|
113
|
+
- Start the service with appropriate settings
|
|
114
|
+
|
|
115
|
+
## Development Mode
|
|
116
|
+
|
|
117
|
+
```bash
|
|
118
|
+
# Start the service in development mode
|
|
119
|
+
NODE_ENV=development ./scripts/startup.sh
|
|
120
|
+
|
|
121
|
+
# Stop the service
|
|
122
|
+
./scripts/shutdown.sh
|
|
123
|
+
```
|
|
124
|
+
|
|
125
|
+
Development mode features:
|
|
126
|
+
- Local directory structure
|
|
127
|
+
- Auto-generated test keys
|
|
128
|
+
- In-memory data storage option
|
|
129
|
+
- Hot-reloading enabled
|
|
130
|
+
- Detailed logging
|
|
131
|
+
- No root permissions required
|
|
132
|
+
|
|
133
|
+
## Production Mode
|
|
134
|
+
|
|
135
|
+
```bash
|
|
136
|
+
# Start the service in production mode
|
|
137
|
+
sudo NODE_ENV=production ./scripts/startup.sh
|
|
138
|
+
|
|
139
|
+
# Stop the service
|
|
140
|
+
sudo ./scripts/shutdown.sh
|
|
141
|
+
```
|
|
142
|
+
|
|
143
|
+
Production mode features:
|
|
144
|
+
- System-level directory structure
|
|
145
|
+
- Secure key management via Supabase
|
|
146
|
+
- Proper file permissions
|
|
147
|
+
- Log rotation and compression
|
|
148
|
+
- Automatic backups
|
|
149
|
+
- Rate limiting
|
|
150
|
+
- IP whitelisting
|
|
151
|
+
|
|
152
|
+
## Configuration
|
|
153
|
+
|
|
154
|
+
### Environment Variables
|
|
155
|
+
|
|
156
|
+
```bash
|
|
157
|
+
# Core Configuration
|
|
158
|
+
NODE_ENV=development # development or production
|
|
159
|
+
DOMAIN=nostr-platform.app # your domain
|
|
160
|
+
SERVICE_NAME=auth # service identifier
|
|
161
|
+
|
|
162
|
+
# Service URLs (auto-configured in production)
|
|
163
|
+
AUTH_SERVICE_URL=http://localhost:3002 # becomes https://auth.your-domain.app
|
|
164
|
+
IPFS_SERVICE_URL=http://localhost:3001 # becomes https://ipfs.your-domain.app
|
|
165
|
+
RELAY_SERVICE_URL=http://localhost:3000 # becomes https://relay.your-domain.app
|
|
166
|
+
|
|
167
|
+
# Security Configuration
|
|
168
|
+
SERVER_PRIVATE_KEY= # auto-generated if not provided
|
|
169
|
+
SERVER_PUBLIC_KEY= # auto-generated if not provided
|
|
170
|
+
JWT_SECRET=your_jwt_secret # required in production
|
|
171
|
+
|
|
172
|
+
# Supabase Configuration
|
|
173
|
+
SUPABASE_PROJECT=your-project # project identifier
|
|
174
|
+
SUPABASE_URL=your_supabase_url # required in production
|
|
175
|
+
SUPABASE_KEY=your_supabase_key # required in production
|
|
176
|
+
|
|
177
|
+
# Service Configuration
|
|
178
|
+
SERVICE_USER=nostr # service user (production)
|
|
179
|
+
SERVICE_GROUP=nostr # service group (production)
|
|
180
|
+
DEPLOY_DIR=/opt/nostr-platform/auth # deployment directory (production)
|
|
181
|
+
BACKUP_DIR=/opt/backups/nostr # backup directory (production)
|
|
182
|
+
LOG_DIR=/var/log/nostr-platform # log directory (production)
|
|
183
|
+
```
|
|
184
|
+
|
|
185
|
+
## Scripts
|
|
186
|
+
|
|
187
|
+
The `scripts` directory contains utilities for managing the service:
|
|
188
|
+
|
|
189
|
+
- `startup.sh`: Service initialization and startup
|
|
190
|
+
- Environment detection
|
|
191
|
+
- Directory creation
|
|
192
|
+
- Permission setting
|
|
193
|
+
- Service startup
|
|
194
|
+
|
|
195
|
+
- `shutdown.sh`: Clean service shutdown
|
|
196
|
+
- Process termination
|
|
197
|
+
- Log rotation
|
|
198
|
+
- Cleanup operations
|
|
199
|
+
|
|
200
|
+
- `config.sh`: Configuration management
|
|
201
|
+
- Environment detection
|
|
202
|
+
- Directory structure
|
|
203
|
+
- Permissions handling
|
|
204
|
+
- Logging utilities
|
|
205
|
+
|
|
206
|
+
## Contributing
|
|
207
|
+
|
|
208
|
+
We welcome contributions! Please see our [Contributing Guide](CONTRIBUTING.md) for details.
|
|
209
|
+
|
|
210
|
+
## Security
|
|
211
|
+
|
|
212
|
+
Security is our top priority. For details about our security practices and how to report security issues, see our [Security Guide](docs/security.md).
|
|
213
|
+
|
|
214
|
+
## License
|
|
215
|
+
|
|
216
|
+
This project is licensed under the MIT License - see the [LICENSE](LICENSE) file for details.
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
|
@@ -0,0 +1,104 @@
|
|
|
1
|
+
import { NostrAuthMiddleware } from '../middleware/nostr-auth.middleware';
|
|
2
|
+
import { jest } from '@jest/globals';
|
|
3
|
+
jest.mock('../services/nostr.service');
|
|
4
|
+
describe('NostrAuthMiddleware', () => {
|
|
5
|
+
let middleware;
|
|
6
|
+
let mockNostrService;
|
|
7
|
+
let mockReq;
|
|
8
|
+
let mockRes;
|
|
9
|
+
let mockNext;
|
|
10
|
+
let mockConfig;
|
|
11
|
+
beforeEach(() => {
|
|
12
|
+
mockNostrService = {
|
|
13
|
+
createChallenge: jest.fn(),
|
|
14
|
+
verifyChallenge: jest.fn(),
|
|
15
|
+
createEnrollment: jest.fn(),
|
|
16
|
+
getProfile: jest.fn(),
|
|
17
|
+
generateToken: jest.fn(),
|
|
18
|
+
};
|
|
19
|
+
mockConfig = {
|
|
20
|
+
port: 3000,
|
|
21
|
+
nodeEnv: 'test',
|
|
22
|
+
corsOrigins: '*',
|
|
23
|
+
keyManagementMode: 'development',
|
|
24
|
+
testMode: true,
|
|
25
|
+
supabaseUrl: 'http://localhost:54321',
|
|
26
|
+
supabaseKey: 'test-key'
|
|
27
|
+
};
|
|
28
|
+
middleware = new NostrAuthMiddleware(mockConfig, mockNostrService);
|
|
29
|
+
mockReq = {
|
|
30
|
+
body: {},
|
|
31
|
+
headers: {},
|
|
32
|
+
params: {}
|
|
33
|
+
};
|
|
34
|
+
mockRes = {
|
|
35
|
+
status: jest.fn().mockReturnThis(),
|
|
36
|
+
json: jest.fn(),
|
|
37
|
+
};
|
|
38
|
+
mockNext = jest.fn();
|
|
39
|
+
});
|
|
40
|
+
describe('handleChallenge', () => {
|
|
41
|
+
const mockPubkey = '123abc';
|
|
42
|
+
const mockChallenge = {
|
|
43
|
+
id: '123',
|
|
44
|
+
pubkey: mockPubkey,
|
|
45
|
+
challenge: 'test-challenge',
|
|
46
|
+
event: {},
|
|
47
|
+
created_at: Date.now(),
|
|
48
|
+
expires_at: Date.now() + 300000
|
|
49
|
+
};
|
|
50
|
+
beforeEach(() => {
|
|
51
|
+
mockReq.params = { pubkey: mockPubkey };
|
|
52
|
+
mockNostrService.createChallenge.mockResolvedValue(mockChallenge);
|
|
53
|
+
});
|
|
54
|
+
it('should create and return a challenge', async () => {
|
|
55
|
+
await middleware.handleChallenge(mockReq, mockRes, mockNext);
|
|
56
|
+
expect(mockNostrService.createChallenge).toHaveBeenCalledWith(mockPubkey);
|
|
57
|
+
expect(mockRes.json).toHaveBeenCalledWith({ challenge: mockChallenge });
|
|
58
|
+
});
|
|
59
|
+
it('should handle errors', async () => {
|
|
60
|
+
const error = new Error('Test error');
|
|
61
|
+
mockNostrService.createChallenge.mockRejectedValue(error);
|
|
62
|
+
await middleware.handleChallenge(mockReq, mockRes, mockNext);
|
|
63
|
+
expect(mockNext).toHaveBeenCalledWith(error);
|
|
64
|
+
});
|
|
65
|
+
});
|
|
66
|
+
describe('handleVerification', () => {
|
|
67
|
+
const mockEvent = {
|
|
68
|
+
id: '1',
|
|
69
|
+
pubkey: '123abc',
|
|
70
|
+
created_at: Math.floor(Date.now() / 1000),
|
|
71
|
+
kind: 22242,
|
|
72
|
+
tags: [],
|
|
73
|
+
content: 'test-challenge',
|
|
74
|
+
sig: '123abc'
|
|
75
|
+
};
|
|
76
|
+
it('should verify challenge and return success', async () => {
|
|
77
|
+
const mockResult = {
|
|
78
|
+
success: true,
|
|
79
|
+
pubkey: mockEvent.pubkey
|
|
80
|
+
};
|
|
81
|
+
mockNostrService.verifyChallenge.mockResolvedValue(mockResult);
|
|
82
|
+
mockNostrService.generateToken.mockResolvedValue('test-token');
|
|
83
|
+
await middleware.handleVerification({ ...mockReq, body: { event: mockEvent } }, mockRes, mockNext);
|
|
84
|
+
expect(mockNostrService.verifyChallenge).toHaveBeenCalledWith(mockEvent);
|
|
85
|
+
expect(mockRes.json).toHaveBeenCalledWith({ ...mockResult, token: 'test-token' });
|
|
86
|
+
});
|
|
87
|
+
it('should handle verification failure', async () => {
|
|
88
|
+
const mockResult = {
|
|
89
|
+
success: false,
|
|
90
|
+
error: 'Invalid challenge'
|
|
91
|
+
};
|
|
92
|
+
mockNostrService.verifyChallenge.mockResolvedValue(mockResult);
|
|
93
|
+
await middleware.handleVerification({ ...mockReq, body: { event: mockEvent } }, mockRes, mockNext);
|
|
94
|
+
expect(mockRes.status).toHaveBeenCalledWith(401);
|
|
95
|
+
expect(mockRes.json).toHaveBeenCalledWith(mockResult);
|
|
96
|
+
});
|
|
97
|
+
it('should handle errors', async () => {
|
|
98
|
+
const error = new Error('Test error');
|
|
99
|
+
mockNostrService.verifyChallenge.mockRejectedValue(error);
|
|
100
|
+
await middleware.handleVerification({ ...mockReq, body: { event: mockEvent } }, mockRes, mockNext);
|
|
101
|
+
expect(mockNext).toHaveBeenCalledWith(error);
|
|
102
|
+
});
|
|
103
|
+
});
|
|
104
|
+
});
|
|
@@ -0,0 +1,148 @@
|
|
|
1
|
+
import { createLogger } from '../utils/logger.js';
|
|
2
|
+
import { generateKeyPair } from '../utils/crypto.utils.js';
|
|
3
|
+
import { createClient } from '@supabase/supabase-js';
|
|
4
|
+
import { writeFileSync, readFileSync } from 'fs';
|
|
5
|
+
import { resolve } from 'path';
|
|
6
|
+
import dotenv from 'dotenv';
|
|
7
|
+
const logger = createLogger('Config');
|
|
8
|
+
// Initialize config with default values
|
|
9
|
+
export const config = {
|
|
10
|
+
// Server config
|
|
11
|
+
port: parseInt(process.env.PORT || '3002'),
|
|
12
|
+
nodeEnv: process.env.NODE_ENV || 'development',
|
|
13
|
+
corsOrigins: process.env.CORS_ORIGINS?.split(',') || '*',
|
|
14
|
+
security: {
|
|
15
|
+
trustedProxies: process.env.TRUSTED_PROXIES?.split(',') || false,
|
|
16
|
+
allowedIPs: process.env.ALLOWED_IPS?.split(',') || [],
|
|
17
|
+
apiKeys: process.env.API_KEYS?.split(',') || [],
|
|
18
|
+
rateLimitWindowMs: parseInt(process.env.RATE_LIMIT_WINDOW_MS || '900000'),
|
|
19
|
+
rateLimitMaxRequests: parseInt(process.env.RATE_LIMIT_MAX_REQUESTS || '100'),
|
|
20
|
+
},
|
|
21
|
+
// Supabase config
|
|
22
|
+
supabaseUrl: process.env.SUPABASE_URL,
|
|
23
|
+
supabaseKey: process.env.SUPABASE_KEY,
|
|
24
|
+
// Nostr config
|
|
25
|
+
nostrRelays: process.env.NOSTR_RELAYS?.split(',') || [
|
|
26
|
+
'wss://relay.maiqr.app',
|
|
27
|
+
'wss://relay.damus.io',
|
|
28
|
+
'wss://relay.nostr.band'
|
|
29
|
+
],
|
|
30
|
+
privateKey: process.env.SERVER_PRIVATE_KEY,
|
|
31
|
+
keyManagementMode: process.env.KEY_MANAGEMENT_MODE || 'development',
|
|
32
|
+
// Auth config
|
|
33
|
+
jwtSecret: process.env.JWT_SECRET || 'maiqr_nostr_auth_secret_key_2024',
|
|
34
|
+
jwtExpiresIn: '1h',
|
|
35
|
+
testMode: process.env.TEST_MODE === 'true',
|
|
36
|
+
// Optional configs
|
|
37
|
+
eventTimeoutMs: 5000,
|
|
38
|
+
challengePrefix: 'nostr:auth:'
|
|
39
|
+
};
|
|
40
|
+
export async function loadConfig(envPath) {
|
|
41
|
+
// Load environment variables
|
|
42
|
+
if (envPath) {
|
|
43
|
+
dotenv.config({ path: envPath });
|
|
44
|
+
}
|
|
45
|
+
else {
|
|
46
|
+
dotenv.config();
|
|
47
|
+
}
|
|
48
|
+
const loadedConfig = {
|
|
49
|
+
// Server config
|
|
50
|
+
port: parseInt(process.env.PORT || '3002'),
|
|
51
|
+
nodeEnv: process.env.NODE_ENV || 'development',
|
|
52
|
+
corsOrigins: process.env.CORS_ORIGINS?.split(',') || '*',
|
|
53
|
+
security: {
|
|
54
|
+
trustedProxies: process.env.TRUSTED_PROXIES?.split(',') || false,
|
|
55
|
+
allowedIPs: process.env.ALLOWED_IPS?.split(',') || [],
|
|
56
|
+
apiKeys: process.env.API_KEYS?.split(',') || [],
|
|
57
|
+
rateLimitWindowMs: parseInt(process.env.RATE_LIMIT_WINDOW_MS || '900000'),
|
|
58
|
+
rateLimitMaxRequests: parseInt(process.env.RATE_LIMIT_MAX_REQUESTS || '100'),
|
|
59
|
+
},
|
|
60
|
+
// Supabase config
|
|
61
|
+
supabaseUrl: process.env.SUPABASE_URL,
|
|
62
|
+
supabaseKey: process.env.SUPABASE_KEY,
|
|
63
|
+
// Nostr config
|
|
64
|
+
nostrRelays: process.env.NOSTR_RELAYS?.split(',') || [
|
|
65
|
+
'wss://relay.maiqr.app',
|
|
66
|
+
'wss://relay.damus.io',
|
|
67
|
+
'wss://relay.nostr.band'
|
|
68
|
+
],
|
|
69
|
+
privateKey: process.env.SERVER_PRIVATE_KEY,
|
|
70
|
+
publicKey: process.env.SERVER_PUBLIC_KEY,
|
|
71
|
+
keyManagementMode: process.env.KEY_MANAGEMENT_MODE,
|
|
72
|
+
// Auth config
|
|
73
|
+
jwtSecret: process.env.JWT_SECRET,
|
|
74
|
+
jwtExpiresIn: process.env.JWT_EXPIRES_IN || '24h',
|
|
75
|
+
testMode: process.env.NODE_ENV !== 'production',
|
|
76
|
+
// Optional configs
|
|
77
|
+
eventTimeoutMs: parseInt(process.env.EVENT_TIMEOUT_MS || '5000'),
|
|
78
|
+
challengePrefix: process.env.CHALLENGE_PREFIX || 'nostr:auth:'
|
|
79
|
+
};
|
|
80
|
+
// Try to load keys from environment
|
|
81
|
+
if (process.env.SERVER_PRIVATE_KEY) {
|
|
82
|
+
const keyPair = await generateKeyPair();
|
|
83
|
+
loadedConfig.privateKey = process.env.SERVER_PRIVATE_KEY;
|
|
84
|
+
loadedConfig.publicKey = keyPair.publicKey;
|
|
85
|
+
logger.info('Loaded server keys from environment');
|
|
86
|
+
return loadedConfig;
|
|
87
|
+
}
|
|
88
|
+
// If in production, try to load from Supabase
|
|
89
|
+
if (!loadedConfig.testMode && loadedConfig.supabaseUrl && loadedConfig.supabaseKey) {
|
|
90
|
+
const supabase = createClient(loadedConfig.supabaseUrl, loadedConfig.supabaseKey);
|
|
91
|
+
try {
|
|
92
|
+
const { data, error } = await supabase
|
|
93
|
+
.from('server_keys')
|
|
94
|
+
.select('private_key, public_key')
|
|
95
|
+
.single();
|
|
96
|
+
if (error)
|
|
97
|
+
throw error;
|
|
98
|
+
if (data) {
|
|
99
|
+
loadedConfig.privateKey = data.private_key;
|
|
100
|
+
loadedConfig.publicKey = data.public_key;
|
|
101
|
+
logger.info('Loaded server keys from Supabase');
|
|
102
|
+
return loadedConfig;
|
|
103
|
+
}
|
|
104
|
+
}
|
|
105
|
+
catch (error) {
|
|
106
|
+
logger.warn('Failed to load keys from Supabase:', error);
|
|
107
|
+
}
|
|
108
|
+
}
|
|
109
|
+
// Generate new keys if none exist
|
|
110
|
+
logger.warn('No server keys found - generating new keypair');
|
|
111
|
+
const keyPair = await generateKeyPair();
|
|
112
|
+
loadedConfig.privateKey = Buffer.from(keyPair.privateKey).toString('hex');
|
|
113
|
+
loadedConfig.publicKey = keyPair.publicKey;
|
|
114
|
+
// Save to .env file in development
|
|
115
|
+
if (loadedConfig.testMode) {
|
|
116
|
+
try {
|
|
117
|
+
const envPath = resolve(process.cwd(), '.env');
|
|
118
|
+
const envContent = readFileSync(envPath, 'utf8');
|
|
119
|
+
const updatedContent = envContent
|
|
120
|
+
.replace(/^SERVER_PRIVATE_KEY=.*$/m, `SERVER_PRIVATE_KEY=${loadedConfig.privateKey}`)
|
|
121
|
+
.replace(/^SERVER_PUBLIC_KEY=.*$/m, `SERVER_PUBLIC_KEY=${loadedConfig.publicKey}`);
|
|
122
|
+
writeFileSync(envPath, updatedContent);
|
|
123
|
+
logger.info('Saved new server keys to .env file');
|
|
124
|
+
}
|
|
125
|
+
catch (error) {
|
|
126
|
+
logger.warn('Failed to save keys to .env file:', error);
|
|
127
|
+
}
|
|
128
|
+
}
|
|
129
|
+
// Save to Supabase in production
|
|
130
|
+
else if (loadedConfig.supabaseUrl && loadedConfig.supabaseKey) {
|
|
131
|
+
const supabase = createClient(loadedConfig.supabaseUrl, loadedConfig.supabaseKey);
|
|
132
|
+
try {
|
|
133
|
+
const { error } = await supabase
|
|
134
|
+
.from('server_keys')
|
|
135
|
+
.upsert({
|
|
136
|
+
private_key: loadedConfig.privateKey,
|
|
137
|
+
public_key: loadedConfig.publicKey
|
|
138
|
+
});
|
|
139
|
+
if (error)
|
|
140
|
+
throw error;
|
|
141
|
+
logger.info('Saved new server keys to Supabase');
|
|
142
|
+
}
|
|
143
|
+
catch (error) {
|
|
144
|
+
logger.warn('Failed to save keys to Supabase:', error);
|
|
145
|
+
}
|
|
146
|
+
}
|
|
147
|
+
return loadedConfig;
|
|
148
|
+
}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/config/index.ts"],"names":[],"mappings":"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"}
|
package/dist/config.d.ts
ADDED
package/dist/config.js
ADDED
|
@@ -0,0 +1,68 @@
|
|
|
1
|
+
import { createLogger } from './utils/logger';
|
|
2
|
+
const logger = createLogger('Config');
|
|
3
|
+
function getEnvWithWarning(key) {
|
|
4
|
+
const value = process.env[key];
|
|
5
|
+
if (!value) {
|
|
6
|
+
logger.warn(`${key} not set in environment variables`);
|
|
7
|
+
}
|
|
8
|
+
return value;
|
|
9
|
+
}
|
|
10
|
+
function validatePrivateKey(privateKey) {
|
|
11
|
+
if (!privateKey) {
|
|
12
|
+
return undefined;
|
|
13
|
+
}
|
|
14
|
+
try {
|
|
15
|
+
// Validate hex format
|
|
16
|
+
if (!/^[0-9a-f]{64}$/.test(privateKey)) {
|
|
17
|
+
throw new Error('Invalid private key format');
|
|
18
|
+
}
|
|
19
|
+
return privateKey;
|
|
20
|
+
}
|
|
21
|
+
catch (error) {
|
|
22
|
+
logger.error('Invalid SERVER_PRIVATE_KEY:', error);
|
|
23
|
+
throw error;
|
|
24
|
+
}
|
|
25
|
+
}
|
|
26
|
+
export const config = {
|
|
27
|
+
keyManagementMode: process.env.KEY_MANAGEMENT_MODE === 'production' ? 'production' : 'development',
|
|
28
|
+
port: parseInt(process.env.PORT || '3002', 10),
|
|
29
|
+
nodeEnv: process.env.NODE_ENV || 'development',
|
|
30
|
+
corsOrigin: process.env.CORS_ORIGIN || '*',
|
|
31
|
+
corsCredentials: process.env.CORS_CREDENTIALS === 'true',
|
|
32
|
+
eventTimeoutMs: parseInt(process.env.EVENT_TIMEOUT_MS || '5000', 10),
|
|
33
|
+
challengePrefix: process.env.CHALLENGE_PREFIX || 'nostr:auth:',
|
|
34
|
+
testMode: process.env.TEST_MODE === 'true',
|
|
35
|
+
logLevel: process.env.LOG_LEVEL || 'info',
|
|
36
|
+
jwtSecret: getEnvWithWarning('JWT_SECRET'),
|
|
37
|
+
jwtExpiresIn: process.env.JWT_EXPIRES_IN || '24h',
|
|
38
|
+
supabaseUrl: getEnvWithWarning('SUPABASE_URL'),
|
|
39
|
+
supabaseKey: getEnvWithWarning('SUPABASE_KEY'),
|
|
40
|
+
privateKey: validatePrivateKey(process.env.SERVER_PRIVATE_KEY),
|
|
41
|
+
publicKey: process.env.SERVER_PUBLIC_KEY
|
|
42
|
+
};
|
|
43
|
+
export function validateConfig(config) {
|
|
44
|
+
if (!config) {
|
|
45
|
+
throw new Error('Config is required');
|
|
46
|
+
}
|
|
47
|
+
if (!config.keyManagementMode) {
|
|
48
|
+
throw new Error('keyManagementMode is required in config');
|
|
49
|
+
}
|
|
50
|
+
if (config.keyManagementMode === 'production') {
|
|
51
|
+
if (!config.privateKey) {
|
|
52
|
+
throw new Error('privateKey is required in production mode');
|
|
53
|
+
}
|
|
54
|
+
// Validate private key format
|
|
55
|
+
if (!/^[0-9a-f]{64}$/.test(config.privateKey)) {
|
|
56
|
+
throw new Error('Invalid private key format');
|
|
57
|
+
}
|
|
58
|
+
}
|
|
59
|
+
// Log config (excluding sensitive values)
|
|
60
|
+
const sanitizedConfig = {
|
|
61
|
+
...config,
|
|
62
|
+
privateKey: config.privateKey ? '***' : undefined,
|
|
63
|
+
jwtSecret: config.jwtSecret ? '***' : undefined,
|
|
64
|
+
supabaseKey: config.supabaseKey ? '***' : undefined
|
|
65
|
+
};
|
|
66
|
+
logger.info('Config validated:', sanitizedConfig);
|
|
67
|
+
}
|
|
68
|
+
validateConfig(config);
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"config.js","sourceRoot":"","sources":["../src/config.ts"],"names":[],"mappings":"AAAA,OAAO,MAAM,MAAM,QAAQ,CAAC;AAC5B,OAAO,EAAE,YAAY,EAAE,MAAM,mBAAmB,CAAC;AACjD,OAAO,EAAE,UAAU,EAAE,MAAM,qBAAqB,CAAC;AACjD,OAAO,EAAE,YAAY,EAAE,MAAM,yBAAyB,CAAC;AAEvD,MAAM,CAAC,MAAM,EAAE,CAAC;AAEhB,MAAM,MAAM,GAAG,YAAY,CAAC,QAAQ,CAAC,CAAC;AAEtC,SAAS,iBAAiB,CAAC,GAAW;IACpC,MAAM,KAAK,GAAG,OAAO,CAAC,GAAG,CAAC,GAAG,CAAC,CAAC;IAC/B,IAAI,CAAC,KAAK,EAAE,CAAC;QACX,MAAM,CAAC,IAAI,CAAC,iCAAiC,GAAG,iCAAiC,CAAC,CAAC;IACrF,CAAC;IACD,OAAO,KAAK,CAAC;AACf,CAAC;AAED,SAAS,kBAAkB,CAAC,GAAuB;IACjD,IAAI,CAAC,GAAG,EAAE,CAAC;QACT,MAAM,IAAI,KAAK,CAAC,gCAAgC,CAAC,CAAC;IACpD,CAAC;IACD,IAAI,CAAC;QACH,sBAAsB;QACtB,IAAI,CAAC,gBAAgB,CAAC,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC;YAChC,MAAM,IAAI,KAAK,CAAC,sDAAsD,CAAC,CAAC;QAC1E,CAAC;QACD,sBAAsB;QACtB,MAAM,eAAe,GAAG,UAAU,CAAC,GAAG,CAAC,CAAC;QACxC,MAAM,MAAM,GAAG,YAAY,CAAC,eAAe,CAAC,CAAC;QAC7C,MAAM,CAAC,IAAI,CAAC,oCAAoC,EAAE,MAAM,CAAC,CAAC;QAC1D,OAAO,GAAG,CAAC;IACb,CAAC;IAAC,OAAO,KAAK,EAAE,CAAC;QACf,MAAM,CAAC,KAAK,CAAC,6BAA6B,EAAE,KAAK,CAAC,CAAC;QACnD,MAAM,KAAK,CAAC;IACd,CAAC;AACH,CAAC;AAED,MAAM,CAAC,MAAM,MAAM,GAAG;IACpB,gBAAgB;IAChB,IAAI,EAAE,QAAQ,CAAC,OAAO,CAAC,GAAG,CAAC,IAAI,IAAI,MAAM,EAAE,EAAE,CAAC;IAC9C,OAAO,EAAE,OAAO,CAAC,GAAG,CAAC,QAAQ,IAAI,aAAa;IAE9C,OAAO;IACP,WAAW,EAAE,OAAO,CAAC,GAAG,CAAC,YAAY,EAAE,KAAK,CAAC,GAAG,CAAC,IAAI,GAAG;IAExD,eAAe;IACf,WAAW,EAAE,OAAO,CAAC,GAAG,CAAC,YAAY,EAAE,KAAK,CAAC,GAAG,CAAC,IAAI;QACnD,sBAAsB;QACtB,wBAAwB;KACzB;IAED,yCAAyC;IACzC,WAAW,EAAE,iBAAiB,CAAC,cAAc,CAAC;IAC9C,WAAW,EAAE,iBAAiB,CAAC,cAAc,CAAC;IAE9C,oCAAoC;IACpC,SAAS,EAAE,iBAAiB,CAAC,YAAY,CAAC;IAC1C,YAAY,EAAE,OAAO,CAAC,GAAG,CAAC,cAAc,IAAI,KAAK;IAEjD,sBAAsB;IACtB,iBAAiB,EAAE,CAAC,OAAO,CAAC,GAAG,CAAC,mBAAmB,KAAK,YAAY,CAAC,CAAC,CAAC,YAAY,CAAC,CAAC,CAAC,aAAa,CAAiC;IAEpI,2CAA2C;IAC3C,UAAU,EAAE,kBAAkB,CAAC,OAAO,CAAC,GAAG,CAAC,kBAAkB,CAAC;IAC9D,SAAS,EAAE,OAAO,CAAC,GAAG,CAAC,iBAAiB;IAExC,wDAAwD;IACxD,QAAQ,EAAE,OAAO,CAAC,GAAG,CAAC,SAAS,KAAK,MAAM;IAE1C,UAAU;IACV,QAAQ,EAAE,OAAO,CAAC,GAAG,CAAC,SAAS,IAAI,MAAM;CACjC,CAAC"}
|
package/dist/index.d.ts
ADDED
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Main exports for the Nostr Auth Middleware package
|
|
3
|
+
* @module @maiqr/nostr-auth-enroll
|
|
4
|
+
*/
|
|
5
|
+
import { NostrAuthMiddleware } from './middleware/nostr-auth.middleware.js';
|
|
6
|
+
import type { NostrAuthConfig } from './types/index.js';
|
|
7
|
+
export { NostrAuthMiddleware };
|
|
8
|
+
export type { NostrAuthConfig, NostrChallenge, NostrProfile, NostrEnrollment, VerificationResult } from './types/index.js';
|
|
9
|
+
export type { NostrEvent } from './utils/types.js';
|
|
10
|
+
export { generateChallenge, generateEventHash, getPublicKey, verifySignature } from './utils/crypto.utils.js';
|
|
11
|
+
export { NostrService } from './services/nostr.service.js';
|
|
12
|
+
export { validateEvent, validateChallengeEvent, validateEnrollmentEvent } from './validators/event.validator.js';
|
|
13
|
+
export { config } from './config.js';
|
|
14
|
+
/**
|
|
15
|
+
* Create and configure a new Nostr Auth Middleware instance
|
|
16
|
+
* @param config Configuration options for the middleware
|
|
17
|
+
* @returns Configured NostrAuthMiddleware instance
|
|
18
|
+
*
|
|
19
|
+
* @example
|
|
20
|
+
* ```typescript
|
|
21
|
+
* import { createNostrAuth } from '@maiqr/nostr-auth-enroll';
|
|
22
|
+
*
|
|
23
|
+
* const nostrAuth = createNostrAuth({
|
|
24
|
+
* supabaseUrl: process.env.SUPABASE_URL,
|
|
25
|
+
* supabaseKey: process.env.SUPABASE_KEY,
|
|
26
|
+
* privateKey: process.env.SERVER_PRIVATE_KEY
|
|
27
|
+
* });
|
|
28
|
+
*
|
|
29
|
+
* app.use('/auth/nostr', nostrAuth.router);
|
|
30
|
+
* ```
|
|
31
|
+
*/
|
|
32
|
+
export declare const createNostrAuth: (config: NostrAuthConfig) => NostrAuthMiddleware;
|
|
33
|
+
export default NostrAuthMiddleware;
|
package/dist/index.js
ADDED
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Main exports for the Nostr Auth Middleware package
|
|
3
|
+
* @module @maiqr/nostr-auth-enroll
|
|
4
|
+
*/
|
|
5
|
+
// Core middleware
|
|
6
|
+
import { NostrAuthMiddleware } from './middleware/nostr-auth.middleware.js';
|
|
7
|
+
// Re-export middleware
|
|
8
|
+
export { NostrAuthMiddleware };
|
|
9
|
+
// Crypto utilities
|
|
10
|
+
export { generateChallenge, generateEventHash, getPublicKey, verifySignature } from './utils/crypto.utils.js';
|
|
11
|
+
// Services
|
|
12
|
+
export { NostrService } from './services/nostr.service.js';
|
|
13
|
+
// Validators
|
|
14
|
+
export { validateEvent, validateChallengeEvent, validateEnrollmentEvent } from './validators/event.validator.js';
|
|
15
|
+
// Configuration
|
|
16
|
+
export { config } from './config.js';
|
|
17
|
+
/**
|
|
18
|
+
* Create and configure a new Nostr Auth Middleware instance
|
|
19
|
+
* @param config Configuration options for the middleware
|
|
20
|
+
* @returns Configured NostrAuthMiddleware instance
|
|
21
|
+
*
|
|
22
|
+
* @example
|
|
23
|
+
* ```typescript
|
|
24
|
+
* import { createNostrAuth } from '@maiqr/nostr-auth-enroll';
|
|
25
|
+
*
|
|
26
|
+
* const nostrAuth = createNostrAuth({
|
|
27
|
+
* supabaseUrl: process.env.SUPABASE_URL,
|
|
28
|
+
* supabaseKey: process.env.SUPABASE_KEY,
|
|
29
|
+
* privateKey: process.env.SERVER_PRIVATE_KEY
|
|
30
|
+
* });
|
|
31
|
+
*
|
|
32
|
+
* app.use('/auth/nostr', nostrAuth.router);
|
|
33
|
+
* ```
|
|
34
|
+
*/
|
|
35
|
+
export const createNostrAuth = (config) => {
|
|
36
|
+
return new NostrAuthMiddleware(config);
|
|
37
|
+
};
|
|
38
|
+
// Default export for CommonJS compatibility
|
|
39
|
+
export default NostrAuthMiddleware;
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAEH,kBAAkB;AAClB,OAAO,EAAE,mBAAmB,EAAE,MAAM,uCAAuC,CAAC;AAG5E,uBAAuB;AACvB,OAAO,EAAE,mBAAmB,EAAE,CAAC;AAa/B,mBAAmB;AACnB,OAAO,EACL,iBAAiB,EACjB,iBAAiB,EACjB,YAAY,EACZ,eAAe,EAChB,MAAM,yBAAyB,CAAC;AAEjC,WAAW;AACX,OAAO,EAAE,YAAY,EAAE,MAAM,6BAA6B,CAAC;AAE3D,aAAa;AACb,OAAO,EAAE,mBAAmB,EAAE,MAAM,iCAAiC,CAAC;AAEtE,gBAAgB;AAChB,OAAO,EAAE,MAAM,EAAE,MAAM,aAAa,CAAC;AAErC;;;;;;;;;;;;;;;;;GAiBG;AACH,MAAM,CAAC,MAAM,eAAe,GAAG,CAAC,MAAuB,EAAuB,EAAE;IAC9E,OAAO,IAAI,mBAAmB,CAAC,MAAM,CAAC,CAAC;AACzC,CAAC,CAAC;AAEF,4CAA4C;AAC5C,eAAe,mBAAmB,CAAC"}
|