@prauga/flexdoc-backend 2.1.0 → 2.3.0
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/README.md +227 -227
- package/dist/auth.d.ts +11 -0
- package/dist/auth.js +99 -0
- package/dist/auth.js.map +1 -0
- package/dist/auth.test.d.ts +1 -0
- package/dist/auth.test.js +57 -0
- package/dist/auth.test.js.map +1 -0
- package/dist/flexdoc.module.test.js +9 -0
- package/dist/flexdoc.module.test.js.map +1 -1
- package/dist/framework-adapters.d.ts +3 -0
- package/dist/framework-adapters.js +34 -3
- package/dist/framework-adapters.js.map +1 -1
- package/dist/framework-adapters.test.js +44 -13
- package/dist/framework-adapters.test.js.map +1 -1
- package/dist/hono-adapter.d.ts +12 -0
- package/dist/hono-adapter.js +63 -0
- package/dist/hono-adapter.js.map +1 -0
- package/dist/hono-adapter.test.d.ts +1 -0
- package/dist/hono-adapter.test.js +82 -0
- package/dist/hono-adapter.test.js.map +1 -0
- package/dist/index.d.ts +3 -1
- package/dist/index.js +4 -1
- package/dist/index.js.map +1 -1
- package/dist/interfaces.d.ts +5 -0
- package/dist/renderer/flexdoc.standalone.css +1 -1
- package/dist/renderer/flexdoc.standalone.js +49 -197
- package/dist/renderer-assets.d.ts +1 -0
- package/dist/renderer-assets.js +6 -2
- package/dist/renderer-assets.js.map +1 -1
- package/dist/setup.js +10 -62
- package/dist/setup.js.map +1 -1
- package/dist/setup.test.js +6 -1
- package/dist/setup.test.js.map +1 -1
- package/dist/template.d.ts +1 -0
- package/dist/template.js +44 -43
- package/dist/template.js.map +1 -1
- package/dist/template.test.js +8 -0
- package/dist/template.test.js.map +1 -1
- package/dist/tsconfig.tsbuildinfo +1 -1
- package/package.json +34 -34
- package/dist/templates/code-examples.njk +0 -106
- package/dist/templates/content.njk +0 -272
- package/dist/templates/footer.njk +0 -38
- package/dist/templates/header.njk +0 -57
- package/dist/templates/layout.njk +0 -647
- package/dist/templates/parameters.njk +0 -64
- package/dist/templates/request-body.njk +0 -63
- package/dist/templates/responses.njk +0 -78
- package/dist/templates/sidebar.njk +0 -117
package/README.md
CHANGED
|
@@ -1,227 +1,227 @@
|
|
|
1
|
-
# FlexDoc Backend
|
|
2
|
-
|
|
3
|
-
[](https://www.npmjs.com/package/@prauga/flexdoc-backend)
|
|
4
|
-
[](https://opensource.org/licenses/MIT)
|
|
5
|
-
|
|
6
|
-
The backend package for FlexDoc, a modern, customizable OpenAPI documentation generator that creates beautiful API documentation.
|
|
7
|
-
|
|
8
|
-
## Screenshots
|
|
9
|
-
|
|
10
|
-
### Light Mode
|
|
11
|
-
|
|
12
|
-

|
|
13
|
-
|
|
14
|
-
### Dark Mode
|
|
15
|
-
|
|
16
|
-

|
|
17
|
-
|
|
18
|
-
## Features
|
|
19
|
-
|
|
20
|
-
- **Modern UI**: Clean, responsive interface with dark mode support
|
|
21
|
-
- **Customizable**: Easily customize colors, typography, and layout
|
|
22
|
-
- **Interactive**: Test API endpoints directly from the documentation
|
|
23
|
-
- **Framework Agnostic**: Works with any JavaScript framework
|
|
24
|
-
- **OpenAPI Compatible**: Supports OpenAPI 3.0 specifications
|
|
25
|
-
|
|
26
|
-
## Installation
|
|
27
|
-
|
|
28
|
-
```bash
|
|
29
|
-
npm install @prauga/flexdoc-backend
|
|
30
|
-
```
|
|
31
|
-
|
|
32
|
-
## Usage
|
|
33
|
-
|
|
34
|
-
### Basic Usage
|
|
35
|
-
|
|
36
|
-
```typescript
|
|
37
|
-
import { FlexDoc } from '@prauga/flexdoc-backend';
|
|
38
|
-
import { OpenAPIObject } from '@nestjs/swagger';
|
|
39
|
-
|
|
40
|
-
// Create a new FlexDoc instance with your OpenAPI spec
|
|
41
|
-
const flexdoc = new FlexDoc({
|
|
42
|
-
spec: yourOpenAPISpec as OpenAPIObject,
|
|
43
|
-
title: 'My API Documentation',
|
|
44
|
-
description: 'Documentation for my awesome API',
|
|
45
|
-
});
|
|
46
|
-
|
|
47
|
-
// Generate HTML documentation
|
|
48
|
-
const html = flexdoc.generateHTML();
|
|
49
|
-
|
|
50
|
-
// Serve the documentation
|
|
51
|
-
app.get('/api/docs', (req, res) => {
|
|
52
|
-
res.send(html);
|
|
53
|
-
});
|
|
54
|
-
```
|
|
55
|
-
|
|
56
|
-
### Configuration Options
|
|
57
|
-
|
|
58
|
-
FlexDoc is highly customizable through the `FlexDocOptions` interface:
|
|
59
|
-
|
|
60
|
-
```typescript
|
|
61
|
-
import { FlexDoc, FlexDocOptions } from '@prauga/flexdoc-backend';
|
|
62
|
-
|
|
63
|
-
const options: FlexDocOptions = {
|
|
64
|
-
// Required
|
|
65
|
-
spec: yourOpenAPISpec,
|
|
66
|
-
|
|
67
|
-
// Basic metadata
|
|
68
|
-
title: 'My API Documentation',
|
|
69
|
-
description: 'Documentation for my awesome API',
|
|
70
|
-
|
|
71
|
-
// Theme configuration
|
|
72
|
-
themeConfig: {
|
|
73
|
-
colors: {
|
|
74
|
-
primary: {
|
|
75
|
-
main: '#3b82f6',
|
|
76
|
-
light: '#eff6ff',
|
|
77
|
-
dark: '#2563eb',
|
|
78
|
-
},
|
|
79
|
-
// Additional color options...
|
|
80
|
-
},
|
|
81
|
-
typography: {
|
|
82
|
-
fontFamily: 'Inter, system-ui, sans-serif',
|
|
83
|
-
fontSize: '16px',
|
|
84
|
-
// Additional typography options...
|
|
85
|
-
},
|
|
86
|
-
},
|
|
87
|
-
|
|
88
|
-
// Footer customization
|
|
89
|
-
footer: {
|
|
90
|
-
copyright: '© 2025 My Company',
|
|
91
|
-
links: [
|
|
92
|
-
{
|
|
93
|
-
text: 'Terms',
|
|
94
|
-
url: '/terms',
|
|
95
|
-
icon: 'file-text', // Optional Lucide icon name
|
|
96
|
-
},
|
|
97
|
-
{
|
|
98
|
-
text: 'Privacy',
|
|
99
|
-
url: '/privacy',
|
|
100
|
-
},
|
|
101
|
-
],
|
|
102
|
-
},
|
|
103
|
-
|
|
104
|
-
// Additional options...
|
|
105
|
-
};
|
|
106
|
-
|
|
107
|
-
const flexdoc = new FlexDoc(options);
|
|
108
|
-
```
|
|
109
|
-
|
|
110
|
-
### Framework Integration Examples
|
|
111
|
-
|
|
112
|
-
#### NestJS
|
|
113
|
-
|
|
114
|
-
```typescript
|
|
115
|
-
import { NestFactory } from '@nestjs/core';
|
|
116
|
-
import { SwaggerModule, DocumentBuilder } from '@nestjs/swagger';
|
|
117
|
-
import { FlexDoc } from '@prauga/flexdoc-backend';
|
|
118
|
-
import { AppModule } from './app.module';
|
|
119
|
-
|
|
120
|
-
async function bootstrap() {
|
|
121
|
-
const app = await NestFactory.create(AppModule);
|
|
122
|
-
|
|
123
|
-
// Create OpenAPI spec with Swagger
|
|
124
|
-
const config = new DocumentBuilder()
|
|
125
|
-
.setTitle('My API')
|
|
126
|
-
.setDescription('My API description')
|
|
127
|
-
.setVersion('1.0')
|
|
128
|
-
.build();
|
|
129
|
-
const document = SwaggerModule.createDocument(app, config);
|
|
130
|
-
|
|
131
|
-
// Create FlexDoc instance
|
|
132
|
-
const flexdoc = new FlexDoc({
|
|
133
|
-
spec: document,
|
|
134
|
-
title: 'My API Documentation',
|
|
135
|
-
description: 'Documentation for my awesome API',
|
|
136
|
-
footer: {
|
|
137
|
-
copyright: '© 2025 My Company',
|
|
138
|
-
},
|
|
139
|
-
});
|
|
140
|
-
|
|
141
|
-
// Serve FlexDoc at /api/docs
|
|
142
|
-
app.use('/api/docs', (req, res) => {
|
|
143
|
-
res.send(flexdoc.generateHTML());
|
|
144
|
-
});
|
|
145
|
-
|
|
146
|
-
await app.listen(3000);
|
|
147
|
-
}
|
|
148
|
-
bootstrap();
|
|
149
|
-
```
|
|
150
|
-
|
|
151
|
-
#### Express
|
|
152
|
-
|
|
153
|
-
```typescript
|
|
154
|
-
import express from 'express';
|
|
155
|
-
import { FlexDoc } from '@prauga/flexdoc-backend';
|
|
156
|
-
import swaggerJsdoc from 'swagger-jsdoc';
|
|
157
|
-
|
|
158
|
-
const app = express();
|
|
159
|
-
|
|
160
|
-
// Generate OpenAPI spec
|
|
161
|
-
const options = {
|
|
162
|
-
definition: {
|
|
163
|
-
openapi: '3.0.0',
|
|
164
|
-
info: {
|
|
165
|
-
title: 'My API',
|
|
166
|
-
version: '1.0.0',
|
|
167
|
-
},
|
|
168
|
-
},
|
|
169
|
-
apis: ['./src/routes/*.js'],
|
|
170
|
-
};
|
|
171
|
-
const openapiSpec = swaggerJsdoc(options);
|
|
172
|
-
|
|
173
|
-
// Create FlexDoc instance
|
|
174
|
-
const flexdoc = new FlexDoc({
|
|
175
|
-
spec: openapiSpec,
|
|
176
|
-
title: 'My API Documentation',
|
|
177
|
-
});
|
|
178
|
-
|
|
179
|
-
// Serve FlexDoc
|
|
180
|
-
app.get('/api/docs', (req, res) => {
|
|
181
|
-
res.send(flexdoc.generateHTML());
|
|
182
|
-
});
|
|
183
|
-
|
|
184
|
-
app.listen(3000);
|
|
185
|
-
```
|
|
186
|
-
|
|
187
|
-
## API Reference
|
|
188
|
-
|
|
189
|
-
### `FlexDoc` Class
|
|
190
|
-
|
|
191
|
-
The main class for generating API documentation.
|
|
192
|
-
|
|
193
|
-
#### Constructor
|
|
194
|
-
|
|
195
|
-
```typescript
|
|
196
|
-
constructor(options: FlexDocOptions)
|
|
197
|
-
```
|
|
198
|
-
|
|
199
|
-
#### Methods
|
|
200
|
-
|
|
201
|
-
- `generateHTML()`: Generates the HTML documentation
|
|
202
|
-
- `getOpenAPISpec()`: Returns the processed OpenAPI specification
|
|
203
|
-
|
|
204
|
-
### `FlexDocOptions` Interface
|
|
205
|
-
|
|
206
|
-
Configuration options for FlexDoc:
|
|
207
|
-
|
|
208
|
-
| Property | Type | Description |
|
|
209
|
-
| -------------- | ------------------------------- | -------------------------------- |
|
|
210
|
-
| `spec` | `OpenAPIObject` | The OpenAPI specification object |
|
|
211
|
-
| `title` | `string` | Documentation title |
|
|
212
|
-
| `description` | `string` | Documentation description |
|
|
213
|
-
| `themeConfig` | `ThemeConfig` | Theme configuration |
|
|
214
|
-
| `footer` | `FooterConfig` | Footer configuration |
|
|
215
|
-
| `favicon` | `string` | URL to favicon |
|
|
216
|
-
| `customCss` | `string` | Custom CSS to inject |
|
|
217
|
-
| `customJs` | `string` | Custom JavaScript to inject |
|
|
218
|
-
| `defaultTheme` | `'light' \| 'dark' \| 'system'` | Default theme mode |
|
|
219
|
-
|
|
220
|
-
## Contributing
|
|
221
|
-
|
|
222
|
-
Contributions are welcome! Please feel free to submit a Pull Request.
|
|
223
|
-
|
|
224
|
-
## License
|
|
225
|
-
|
|
226
|
-
This project is licensed under the MIT License - see the LICENSE file for details.
|
|
227
|
-
|
|
1
|
+
# FlexDoc Backend
|
|
2
|
+
|
|
3
|
+
[](https://www.npmjs.com/package/@prauga/flexdoc-backend)
|
|
4
|
+
[](https://opensource.org/licenses/MIT)
|
|
5
|
+
|
|
6
|
+
The backend package for FlexDoc, a modern, customizable OpenAPI documentation generator that creates beautiful API documentation.
|
|
7
|
+
|
|
8
|
+
## Screenshots
|
|
9
|
+
|
|
10
|
+
### Light Mode
|
|
11
|
+
|
|
12
|
+

|
|
13
|
+
|
|
14
|
+
### Dark Mode
|
|
15
|
+
|
|
16
|
+

|
|
17
|
+
|
|
18
|
+
## Features
|
|
19
|
+
|
|
20
|
+
- **Modern UI**: Clean, responsive interface with dark mode support
|
|
21
|
+
- **Customizable**: Easily customize colors, typography, and layout
|
|
22
|
+
- **Interactive**: Test API endpoints directly from the documentation
|
|
23
|
+
- **Framework Agnostic**: Works with any JavaScript framework
|
|
24
|
+
- **OpenAPI Compatible**: Supports OpenAPI 3.0 specifications
|
|
25
|
+
|
|
26
|
+
## Installation
|
|
27
|
+
|
|
28
|
+
```bash
|
|
29
|
+
npm install @prauga/flexdoc-backend
|
|
30
|
+
```
|
|
31
|
+
|
|
32
|
+
## Usage
|
|
33
|
+
|
|
34
|
+
### Basic Usage
|
|
35
|
+
|
|
36
|
+
```typescript
|
|
37
|
+
import { FlexDoc } from '@prauga/flexdoc-backend';
|
|
38
|
+
import { OpenAPIObject } from '@nestjs/swagger';
|
|
39
|
+
|
|
40
|
+
// Create a new FlexDoc instance with your OpenAPI spec
|
|
41
|
+
const flexdoc = new FlexDoc({
|
|
42
|
+
spec: yourOpenAPISpec as OpenAPIObject,
|
|
43
|
+
title: 'My API Documentation',
|
|
44
|
+
description: 'Documentation for my awesome API',
|
|
45
|
+
});
|
|
46
|
+
|
|
47
|
+
// Generate HTML documentation
|
|
48
|
+
const html = flexdoc.generateHTML();
|
|
49
|
+
|
|
50
|
+
// Serve the documentation
|
|
51
|
+
app.get('/api/docs', (req, res) => {
|
|
52
|
+
res.send(html);
|
|
53
|
+
});
|
|
54
|
+
```
|
|
55
|
+
|
|
56
|
+
### Configuration Options
|
|
57
|
+
|
|
58
|
+
FlexDoc is highly customizable through the `FlexDocOptions` interface:
|
|
59
|
+
|
|
60
|
+
```typescript
|
|
61
|
+
import { FlexDoc, FlexDocOptions } from '@prauga/flexdoc-backend';
|
|
62
|
+
|
|
63
|
+
const options: FlexDocOptions = {
|
|
64
|
+
// Required
|
|
65
|
+
spec: yourOpenAPISpec,
|
|
66
|
+
|
|
67
|
+
// Basic metadata
|
|
68
|
+
title: 'My API Documentation',
|
|
69
|
+
description: 'Documentation for my awesome API',
|
|
70
|
+
|
|
71
|
+
// Theme configuration
|
|
72
|
+
themeConfig: {
|
|
73
|
+
colors: {
|
|
74
|
+
primary: {
|
|
75
|
+
main: '#3b82f6',
|
|
76
|
+
light: '#eff6ff',
|
|
77
|
+
dark: '#2563eb',
|
|
78
|
+
},
|
|
79
|
+
// Additional color options...
|
|
80
|
+
},
|
|
81
|
+
typography: {
|
|
82
|
+
fontFamily: 'Inter, system-ui, sans-serif',
|
|
83
|
+
fontSize: '16px',
|
|
84
|
+
// Additional typography options...
|
|
85
|
+
},
|
|
86
|
+
},
|
|
87
|
+
|
|
88
|
+
// Footer customization
|
|
89
|
+
footer: {
|
|
90
|
+
copyright: '© 2025 My Company',
|
|
91
|
+
links: [
|
|
92
|
+
{
|
|
93
|
+
text: 'Terms',
|
|
94
|
+
url: '/terms',
|
|
95
|
+
icon: 'file-text', // Optional Lucide icon name
|
|
96
|
+
},
|
|
97
|
+
{
|
|
98
|
+
text: 'Privacy',
|
|
99
|
+
url: '/privacy',
|
|
100
|
+
},
|
|
101
|
+
],
|
|
102
|
+
},
|
|
103
|
+
|
|
104
|
+
// Additional options...
|
|
105
|
+
};
|
|
106
|
+
|
|
107
|
+
const flexdoc = new FlexDoc(options);
|
|
108
|
+
```
|
|
109
|
+
|
|
110
|
+
### Framework Integration Examples
|
|
111
|
+
|
|
112
|
+
#### NestJS
|
|
113
|
+
|
|
114
|
+
```typescript
|
|
115
|
+
import { NestFactory } from '@nestjs/core';
|
|
116
|
+
import { SwaggerModule, DocumentBuilder } from '@nestjs/swagger';
|
|
117
|
+
import { FlexDoc } from '@prauga/flexdoc-backend';
|
|
118
|
+
import { AppModule } from './app.module';
|
|
119
|
+
|
|
120
|
+
async function bootstrap() {
|
|
121
|
+
const app = await NestFactory.create(AppModule);
|
|
122
|
+
|
|
123
|
+
// Create OpenAPI spec with Swagger
|
|
124
|
+
const config = new DocumentBuilder()
|
|
125
|
+
.setTitle('My API')
|
|
126
|
+
.setDescription('My API description')
|
|
127
|
+
.setVersion('1.0')
|
|
128
|
+
.build();
|
|
129
|
+
const document = SwaggerModule.createDocument(app, config);
|
|
130
|
+
|
|
131
|
+
// Create FlexDoc instance
|
|
132
|
+
const flexdoc = new FlexDoc({
|
|
133
|
+
spec: document,
|
|
134
|
+
title: 'My API Documentation',
|
|
135
|
+
description: 'Documentation for my awesome API',
|
|
136
|
+
footer: {
|
|
137
|
+
copyright: '© 2025 My Company',
|
|
138
|
+
},
|
|
139
|
+
});
|
|
140
|
+
|
|
141
|
+
// Serve FlexDoc at /api/docs
|
|
142
|
+
app.use('/api/docs', (req, res) => {
|
|
143
|
+
res.send(flexdoc.generateHTML());
|
|
144
|
+
});
|
|
145
|
+
|
|
146
|
+
await app.listen(3000);
|
|
147
|
+
}
|
|
148
|
+
bootstrap();
|
|
149
|
+
```
|
|
150
|
+
|
|
151
|
+
#### Express
|
|
152
|
+
|
|
153
|
+
```typescript
|
|
154
|
+
import express from 'express';
|
|
155
|
+
import { FlexDoc } from '@prauga/flexdoc-backend';
|
|
156
|
+
import swaggerJsdoc from 'swagger-jsdoc';
|
|
157
|
+
|
|
158
|
+
const app = express();
|
|
159
|
+
|
|
160
|
+
// Generate OpenAPI spec
|
|
161
|
+
const options = {
|
|
162
|
+
definition: {
|
|
163
|
+
openapi: '3.0.0',
|
|
164
|
+
info: {
|
|
165
|
+
title: 'My API',
|
|
166
|
+
version: '1.0.0',
|
|
167
|
+
},
|
|
168
|
+
},
|
|
169
|
+
apis: ['./src/routes/*.js'],
|
|
170
|
+
};
|
|
171
|
+
const openapiSpec = swaggerJsdoc(options);
|
|
172
|
+
|
|
173
|
+
// Create FlexDoc instance
|
|
174
|
+
const flexdoc = new FlexDoc({
|
|
175
|
+
spec: openapiSpec,
|
|
176
|
+
title: 'My API Documentation',
|
|
177
|
+
});
|
|
178
|
+
|
|
179
|
+
// Serve FlexDoc
|
|
180
|
+
app.get('/api/docs', (req, res) => {
|
|
181
|
+
res.send(flexdoc.generateHTML());
|
|
182
|
+
});
|
|
183
|
+
|
|
184
|
+
app.listen(3000);
|
|
185
|
+
```
|
|
186
|
+
|
|
187
|
+
## API Reference
|
|
188
|
+
|
|
189
|
+
### `FlexDoc` Class
|
|
190
|
+
|
|
191
|
+
The main class for generating API documentation.
|
|
192
|
+
|
|
193
|
+
#### Constructor
|
|
194
|
+
|
|
195
|
+
```typescript
|
|
196
|
+
constructor(options: FlexDocOptions)
|
|
197
|
+
```
|
|
198
|
+
|
|
199
|
+
#### Methods
|
|
200
|
+
|
|
201
|
+
- `generateHTML()`: Generates the HTML documentation
|
|
202
|
+
- `getOpenAPISpec()`: Returns the processed OpenAPI specification
|
|
203
|
+
|
|
204
|
+
### `FlexDocOptions` Interface
|
|
205
|
+
|
|
206
|
+
Configuration options for FlexDoc:
|
|
207
|
+
|
|
208
|
+
| Property | Type | Description |
|
|
209
|
+
| -------------- | ------------------------------- | -------------------------------- |
|
|
210
|
+
| `spec` | `OpenAPIObject` | The OpenAPI specification object |
|
|
211
|
+
| `title` | `string` | Documentation title |
|
|
212
|
+
| `description` | `string` | Documentation description |
|
|
213
|
+
| `themeConfig` | `ThemeConfig` | Theme configuration |
|
|
214
|
+
| `footer` | `FooterConfig` | Footer configuration |
|
|
215
|
+
| `favicon` | `string` | URL to favicon |
|
|
216
|
+
| `customCss` | `string` | Custom CSS to inject |
|
|
217
|
+
| `customJs` | `string` | Custom JavaScript to inject |
|
|
218
|
+
| `defaultTheme` | `'light' \| 'dark' \| 'system'` | Default theme mode |
|
|
219
|
+
|
|
220
|
+
## Contributing
|
|
221
|
+
|
|
222
|
+
Contributions are welcome! Please feel free to submit a Pull Request.
|
|
223
|
+
|
|
224
|
+
## License
|
|
225
|
+
|
|
226
|
+
This project is licensed under the MIT License - see the LICENSE file for details.
|
|
227
|
+
|
package/dist/auth.d.ts
ADDED
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
export interface FlexDocAuthOptions {
|
|
2
|
+
secretKey: string;
|
|
3
|
+
type: 'basic' | 'bearer';
|
|
4
|
+
}
|
|
5
|
+
export interface FlexDocAuthDecision {
|
|
6
|
+
authorized: boolean;
|
|
7
|
+
challenge?: string;
|
|
8
|
+
message?: string;
|
|
9
|
+
}
|
|
10
|
+
export declare function generateFlexDocPassword(username: string, secret: string): string;
|
|
11
|
+
export declare function authorizeFlexDocRequest(authHeader: string | undefined, authOptions: FlexDocAuthOptions): FlexDocAuthDecision;
|
package/dist/auth.js
ADDED
|
@@ -0,0 +1,99 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
|
|
3
|
+
if (k2 === undefined) k2 = k;
|
|
4
|
+
var desc = Object.getOwnPropertyDescriptor(m, k);
|
|
5
|
+
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
|
|
6
|
+
desc = { enumerable: true, get: function() { return m[k]; } };
|
|
7
|
+
}
|
|
8
|
+
Object.defineProperty(o, k2, desc);
|
|
9
|
+
}) : (function(o, m, k, k2) {
|
|
10
|
+
if (k2 === undefined) k2 = k;
|
|
11
|
+
o[k2] = m[k];
|
|
12
|
+
}));
|
|
13
|
+
var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
|
|
14
|
+
Object.defineProperty(o, "default", { enumerable: true, value: v });
|
|
15
|
+
}) : function(o, v) {
|
|
16
|
+
o["default"] = v;
|
|
17
|
+
});
|
|
18
|
+
var __importStar = (this && this.__importStar) || (function () {
|
|
19
|
+
var ownKeys = function(o) {
|
|
20
|
+
ownKeys = Object.getOwnPropertyNames || function (o) {
|
|
21
|
+
var ar = [];
|
|
22
|
+
for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
|
|
23
|
+
return ar;
|
|
24
|
+
};
|
|
25
|
+
return ownKeys(o);
|
|
26
|
+
};
|
|
27
|
+
return function (mod) {
|
|
28
|
+
if (mod && mod.__esModule) return mod;
|
|
29
|
+
var result = {};
|
|
30
|
+
if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
|
|
31
|
+
__setModuleDefault(result, mod);
|
|
32
|
+
return result;
|
|
33
|
+
};
|
|
34
|
+
})();
|
|
35
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
36
|
+
exports.generateFlexDocPassword = generateFlexDocPassword;
|
|
37
|
+
exports.authorizeFlexDocRequest = authorizeFlexDocRequest;
|
|
38
|
+
const crypto = __importStar(require("crypto"));
|
|
39
|
+
const jwt = __importStar(require("jsonwebtoken"));
|
|
40
|
+
function generateFlexDocPassword(username, secret) {
|
|
41
|
+
const hmac = crypto.createHmac('sha256', secret);
|
|
42
|
+
hmac.update(username);
|
|
43
|
+
const hash = hmac.digest('base64');
|
|
44
|
+
const basePassword = hash.substring(0, 12);
|
|
45
|
+
let password = basePassword;
|
|
46
|
+
if (!/[A-Z]/.test(password))
|
|
47
|
+
password += 'A';
|
|
48
|
+
if (!/[a-z]/.test(password))
|
|
49
|
+
password += 'a';
|
|
50
|
+
if (!/[0-9]/.test(password))
|
|
51
|
+
password += '1';
|
|
52
|
+
if (!/[^A-Za-z0-9]/.test(password))
|
|
53
|
+
password += '!';
|
|
54
|
+
return password;
|
|
55
|
+
}
|
|
56
|
+
function authorizeFlexDocRequest(authHeader, authOptions) {
|
|
57
|
+
const { type, secretKey } = authOptions;
|
|
58
|
+
if (type === 'basic') {
|
|
59
|
+
if (!authHeader || !authHeader.startsWith('Basic ')) {
|
|
60
|
+
return { authorized: false, challenge: 'Basic', message: 'Authentication required' };
|
|
61
|
+
}
|
|
62
|
+
const credentials = Buffer.from(authHeader.slice('Basic '.length), 'base64').toString('ascii');
|
|
63
|
+
const separatorIndex = credentials.indexOf(':');
|
|
64
|
+
const username = separatorIndex === -1 ? credentials : credentials.slice(0, separatorIndex);
|
|
65
|
+
const password = separatorIndex === -1 ? '' : credentials.slice(separatorIndex + 1);
|
|
66
|
+
if (password !== generateFlexDocPassword(username, secretKey)) {
|
|
67
|
+
return { authorized: false, challenge: 'Basic', message: 'Invalid credentials' };
|
|
68
|
+
}
|
|
69
|
+
return { authorized: true };
|
|
70
|
+
}
|
|
71
|
+
let token;
|
|
72
|
+
if (authHeader?.startsWith('Bearer ')) {
|
|
73
|
+
token = authHeader.slice('Bearer '.length);
|
|
74
|
+
}
|
|
75
|
+
else if (authHeader?.startsWith('Basic ')) {
|
|
76
|
+
const credentials = Buffer.from(authHeader.slice('Basic '.length), 'base64').toString('ascii');
|
|
77
|
+
const separatorIndex = credentials.indexOf(':');
|
|
78
|
+
token = separatorIndex === -1 ? undefined : credentials.slice(separatorIndex + 1);
|
|
79
|
+
}
|
|
80
|
+
if (token) {
|
|
81
|
+
try {
|
|
82
|
+
jwt.verify(token, secretKey);
|
|
83
|
+
return { authorized: true };
|
|
84
|
+
}
|
|
85
|
+
catch {
|
|
86
|
+
return {
|
|
87
|
+
authorized: false,
|
|
88
|
+
challenge: 'Basic realm="Enter token as password"',
|
|
89
|
+
message: 'Invalid or expired token',
|
|
90
|
+
};
|
|
91
|
+
}
|
|
92
|
+
}
|
|
93
|
+
return {
|
|
94
|
+
authorized: false,
|
|
95
|
+
challenge: 'Basic realm="Enter token as password"',
|
|
96
|
+
message: 'Authentication required',
|
|
97
|
+
};
|
|
98
|
+
}
|
|
99
|
+
//# sourceMappingURL=auth.js.map
|
package/dist/auth.js.map
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"auth.js","sourceRoot":"","sources":["../src/auth.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
|
@@ -0,0 +1,57 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
|
|
3
|
+
if (k2 === undefined) k2 = k;
|
|
4
|
+
var desc = Object.getOwnPropertyDescriptor(m, k);
|
|
5
|
+
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
|
|
6
|
+
desc = { enumerable: true, get: function() { return m[k]; } };
|
|
7
|
+
}
|
|
8
|
+
Object.defineProperty(o, k2, desc);
|
|
9
|
+
}) : (function(o, m, k, k2) {
|
|
10
|
+
if (k2 === undefined) k2 = k;
|
|
11
|
+
o[k2] = m[k];
|
|
12
|
+
}));
|
|
13
|
+
var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
|
|
14
|
+
Object.defineProperty(o, "default", { enumerable: true, value: v });
|
|
15
|
+
}) : function(o, v) {
|
|
16
|
+
o["default"] = v;
|
|
17
|
+
});
|
|
18
|
+
var __importStar = (this && this.__importStar) || (function () {
|
|
19
|
+
var ownKeys = function(o) {
|
|
20
|
+
ownKeys = Object.getOwnPropertyNames || function (o) {
|
|
21
|
+
var ar = [];
|
|
22
|
+
for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
|
|
23
|
+
return ar;
|
|
24
|
+
};
|
|
25
|
+
return ownKeys(o);
|
|
26
|
+
};
|
|
27
|
+
return function (mod) {
|
|
28
|
+
if (mod && mod.__esModule) return mod;
|
|
29
|
+
var result = {};
|
|
30
|
+
if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
|
|
31
|
+
__setModuleDefault(result, mod);
|
|
32
|
+
return result;
|
|
33
|
+
};
|
|
34
|
+
})();
|
|
35
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
36
|
+
const jwt = __importStar(require("jsonwebtoken"));
|
|
37
|
+
const auth_1 = require("./auth");
|
|
38
|
+
describe('FlexDoc route auth', () => {
|
|
39
|
+
it('validates generated basic-auth credentials', () => {
|
|
40
|
+
const secretKey = 'basic-secret';
|
|
41
|
+
const username = 'alice';
|
|
42
|
+
const password = (0, auth_1.generateFlexDocPassword)(username, secretKey);
|
|
43
|
+
const header = `Basic ${Buffer.from(`${username}:${password}`).toString('base64')}`;
|
|
44
|
+
expect((0, auth_1.authorizeFlexDocRequest)(undefined, { type: 'basic', secretKey })).toEqual(expect.objectContaining({ authorized: false, challenge: 'Basic' }));
|
|
45
|
+
expect((0, auth_1.authorizeFlexDocRequest)(header, { type: 'basic', secretKey })).toEqual({ authorized: true });
|
|
46
|
+
});
|
|
47
|
+
it('validates bearer tokens and preserves the password-field fallback', () => {
|
|
48
|
+
const secretKey = 'bearer-secret';
|
|
49
|
+
const token = jwt.sign({ sub: 'docs-user' }, secretKey);
|
|
50
|
+
const bearer = `Bearer ${token}`;
|
|
51
|
+
const basicFallback = `Basic ${Buffer.from(`token:${token}`).toString('base64')}`;
|
|
52
|
+
expect((0, auth_1.authorizeFlexDocRequest)(bearer, { type: 'bearer', secretKey })).toEqual({ authorized: true });
|
|
53
|
+
expect((0, auth_1.authorizeFlexDocRequest)(basicFallback, { type: 'bearer', secretKey })).toEqual({ authorized: true });
|
|
54
|
+
expect((0, auth_1.authorizeFlexDocRequest)('Bearer invalid', { type: 'bearer', secretKey })).toEqual(expect.objectContaining({ authorized: false, message: 'Invalid or expired token' }));
|
|
55
|
+
});
|
|
56
|
+
});
|
|
57
|
+
//# sourceMappingURL=auth.test.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"auth.test.js","sourceRoot":"","sources":["../src/auth.test.ts"],"names":[],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AAAA,kDAAoC;AACpC,iCAGgB;AAEhB,QAAQ,CAAC,oBAAoB,EAAE,GAAG,EAAE;IAClC,EAAE,CAAC,4CAA4C,EAAE,GAAG,EAAE;QACpD,MAAM,SAAS,GAAG,cAAc,CAAC;QACjC,MAAM,QAAQ,GAAG,OAAO,CAAC;QACzB,MAAM,QAAQ,GAAG,IAAA,8BAAuB,EAAC,QAAQ,EAAE,SAAS,CAAC,CAAC;QAC9D,MAAM,MAAM,GAAG,SAAS,MAAM,CAAC,IAAI,CAAC,GAAG,QAAQ,IAAI,QAAQ,EAAE,CAAC,CAAC,QAAQ,CAAC,QAAQ,CAAC,EAAE,CAAC;QAEpF,MAAM,CAAC,IAAA,8BAAuB,EAAC,SAAS,EAAE,EAAE,IAAI,EAAE,OAAO,EAAE,SAAS,EAAE,CAAC,CAAC,CAAC,OAAO,CAC9E,MAAM,CAAC,gBAAgB,CAAC,EAAE,UAAU,EAAE,KAAK,EAAE,SAAS,EAAE,OAAO,EAAE,CAAC,CACnE,CAAC;QACF,MAAM,CAAC,IAAA,8BAAuB,EAAC,MAAM,EAAE,EAAE,IAAI,EAAE,OAAO,EAAE,SAAS,EAAE,CAAC,CAAC,CAAC,OAAO,CAAC,EAAE,UAAU,EAAE,IAAI,EAAE,CAAC,CAAC;IACtG,CAAC,CAAC,CAAC;IAEH,EAAE,CAAC,mEAAmE,EAAE,GAAG,EAAE;QAC3E,MAAM,SAAS,GAAG,eAAe,CAAC;QAClC,MAAM,KAAK,GAAG,GAAG,CAAC,IAAI,CAAC,EAAE,GAAG,EAAE,WAAW,EAAE,EAAE,SAAS,CAAC,CAAC;QACxD,MAAM,MAAM,GAAG,UAAU,KAAK,EAAE,CAAC;QACjC,MAAM,aAAa,GAAG,SAAS,MAAM,CAAC,IAAI,CAAC,SAAS,KAAK,EAAE,CAAC,CAAC,QAAQ,CAAC,QAAQ,CAAC,EAAE,CAAC;QAElF,MAAM,CAAC,IAAA,8BAAuB,EAAC,MAAM,EAAE,EAAE,IAAI,EAAE,QAAQ,EAAE,SAAS,EAAE,CAAC,CAAC,CAAC,OAAO,CAAC,EAAE,UAAU,EAAE,IAAI,EAAE,CAAC,CAAC;QACrG,MAAM,CAAC,IAAA,8BAAuB,EAAC,aAAa,EAAE,EAAE,IAAI,EAAE,QAAQ,EAAE,SAAS,EAAE,CAAC,CAAC,CAAC,OAAO,CAAC,EAAE,UAAU,EAAE,IAAI,EAAE,CAAC,CAAC;QAC5G,MAAM,CAAC,IAAA,8BAAuB,EAAC,gBAAgB,EAAE,EAAE,IAAI,EAAE,QAAQ,EAAE,SAAS,EAAE,CAAC,CAAC,CAAC,OAAO,CACtF,MAAM,CAAC,gBAAgB,CAAC,EAAE,UAAU,EAAE,KAAK,EAAE,OAAO,EAAE,0BAA0B,EAAE,CAAC,CACpF,CAAC;IACJ,CAAC,CAAC,CAAC;AACL,CAAC,CAAC,CAAC"}
|
|
@@ -2,6 +2,15 @@
|
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
3
|
const flexdoc_module_1 = require("./flexdoc.module");
|
|
4
4
|
const setup_1 = require("./setup");
|
|
5
|
+
jest.mock('@nestjs/common', () => ({
|
|
6
|
+
Module: () => (target) => target,
|
|
7
|
+
Inject: () => () => undefined,
|
|
8
|
+
Injectable: () => (target) => target,
|
|
9
|
+
}));
|
|
10
|
+
jest.mock('@nestjs/core', () => ({
|
|
11
|
+
HttpAdapterHost: class HttpAdapterHost {
|
|
12
|
+
},
|
|
13
|
+
}));
|
|
5
14
|
jest.mock('./setup', () => ({
|
|
6
15
|
setupFlexDoc: jest.fn(),
|
|
7
16
|
}));
|