adminforth 1.1.92 → 1.1.93
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/dataConnectors/baseConnector.ts +2 -2
- package/dataConnectors/mongo.ts +2 -2
- package/dataConnectors/postgres.ts +2 -2
- package/dataConnectors/sqlite.ts +2 -2
- package/dist/plugins/TwoFactorsAuthPlugin/index.js +2 -3
- package/dist/spa/spa/src/components/Toast.vue +1 -1
- package/index.ts +5 -5
- package/modules/codeInjector.ts +2 -2
- package/package.json +2 -2
- package/plugins/AuditLogPlugin/index.ts +3 -3
- package/plugins/ForeignInlineListPlugin/index.ts +4 -4
- package/plugins/S3UploadPlugin/custom/s3uploader.vue +24 -4
- package/plugins/S3UploadPlugin/index.ts +4 -4
- package/plugins/S3UploadPlugin/package.json +1 -1
- package/plugins/TwoFactorsAuthPlugin/dist/auth.js +108 -0
- package/plugins/TwoFactorsAuthPlugin/dist/dataConnectors/baseConnector.js +90 -0
- package/plugins/TwoFactorsAuthPlugin/dist/dataConnectors/mongo.js +191 -0
- package/plugins/TwoFactorsAuthPlugin/dist/dataConnectors/postgres.js +295 -0
- package/plugins/TwoFactorsAuthPlugin/dist/dataConnectors/sqlite.js +246 -0
- package/plugins/TwoFactorsAuthPlugin/dist/index.js +1186 -0
- package/plugins/TwoFactorsAuthPlugin/dist/modules/codeInjector.js +546 -0
- package/plugins/TwoFactorsAuthPlugin/dist/modules/styleGenerator.js +43 -0
- package/plugins/TwoFactorsAuthPlugin/dist/modules/styles.js +92 -0
- package/plugins/TwoFactorsAuthPlugin/dist/modules/utils.js +301 -0
- package/plugins/TwoFactorsAuthPlugin/dist/plugins/TwoFactorsAuthPlugin/index.js +149 -0
- package/plugins/TwoFactorsAuthPlugin/dist/plugins/TwoFactorsAuthPlugin/types.js +1 -0
- package/plugins/TwoFactorsAuthPlugin/dist/plugins/base.js +34 -0
- package/plugins/TwoFactorsAuthPlugin/dist/servers/express.js +230 -0
- package/plugins/TwoFactorsAuthPlugin/dist/types/AdminForthConfig.js +105 -0
- package/plugins/TwoFactorsAuthPlugin/index.ts +10 -10
- package/plugins/TwoFactorsAuthPlugin/package-lock.json +2 -2
- package/plugins/TwoFactorsAuthPlugin/package.json +8 -6
- package/plugins/TwoFactorsAuthPlugin/tsconfig.json +112 -0
- package/plugins/base.ts +4 -4
- package/servers/express.ts +4 -4
- package/spa/src/components/Toast.vue +1 -1
- package/tsconfig.json +1 -1
- package/types/AdminForthConfig.ts +34 -28
- package/types/FrontendAPI.ts +2 -1
|
@@ -0,0 +1,92 @@
|
|
|
1
|
+
export const styles = () => ({
|
|
2
|
+
colors: {
|
|
3
|
+
lightHtml: "#FFFFFF", // main background
|
|
4
|
+
lightNavbar: "#FFFFFF", // navbar background
|
|
5
|
+
lightNavbarBorder: "rgb(229 231 235)", // border
|
|
6
|
+
lightNavbarText: "#111827", // navbar text
|
|
7
|
+
lightNavbarTextHover: "alias:lightNavbarText darken", // navbar text hover
|
|
8
|
+
lightNavbarTextActive: "alias:lightNavbarText darken", // navbar text active
|
|
9
|
+
lightNavbarIcons: "alias:lightNavbarText opacity:0.7", // navbar icons
|
|
10
|
+
lightSidebar: "#ffffff", // sidebar background
|
|
11
|
+
lightSidebarBorder: "alias:lightSidebarText opacity:0.3", // sidebar right border
|
|
12
|
+
lightSidebarItemHover: "alias:lightSidebarText opacity:0.1", // sidebar list item hover
|
|
13
|
+
lightSidebarItemActive: "alias:lightSidebarText opacity:0.4", // sidebar list item active
|
|
14
|
+
lightSidebarText: "#1f2937", // sidebar list item text
|
|
15
|
+
lightSidebarTextHover: "alias:lightSidebarText darken", // sidebar list item text hover
|
|
16
|
+
lightSidebarTextActive: "alias:lightSidebarText darken", // sidebar list item text active
|
|
17
|
+
lightSidebarDevider: "alias:lightSidebarText opacity:0.3", // sidebar devider
|
|
18
|
+
lightSidebarIcons: "alias:lightSidebarText opacity:0.7", // sidebar list item icons
|
|
19
|
+
lightSidebarIconsHover: "alias:lightSidebarText", // sidebar list item icons hover
|
|
20
|
+
lightSidebarHeading: "alias:lightSidebarText opacity:0.3", // sidebar heading
|
|
21
|
+
lightList: "#FFFFFF", // list view background
|
|
22
|
+
lightListTable: "#FFFFFF", // list view table background
|
|
23
|
+
lightListTableHeading: "rgb(249 250 251)", // list view table heading
|
|
24
|
+
lightListTableHeadingText: "#333333", // list view table heading text
|
|
25
|
+
lightListTableText: "#333333", // list view table text
|
|
26
|
+
lightListTableRowHover: "rgb(249 250 251)", // list view row hover
|
|
27
|
+
lightListBreadcrumbsText: "#666666", // list view breadcrumbs text
|
|
28
|
+
lightListBorder: "#DDDDDD", // list view rows border
|
|
29
|
+
// lightListButton: "#FFFFFF", // list view button
|
|
30
|
+
// lightListButtonBorder: "#d1d5db", // list view button border
|
|
31
|
+
// lightListButtonHover: "#f3f4f6", // list view button hover
|
|
32
|
+
// lightListButtonBorderHover: "#f3f4f6", // list view button border hover
|
|
33
|
+
// lightListButtonActive: "#f3f4f6", // list view button active
|
|
34
|
+
// lightListButtonDisabled: "#f3f4f6", // list view button disabled
|
|
35
|
+
// lightListButtonDisabledText: "#f3f4f6", // list view button disabled text
|
|
36
|
+
// lightListButtonIcon: "#333333", // list view button icon
|
|
37
|
+
lightForm: "#FFFFFF", // show view background
|
|
38
|
+
lightFormBorder: "#F5F5F5", // show view rows border
|
|
39
|
+
lightFormHeading: "rgb(249 250 251)", // show view heading
|
|
40
|
+
lightButtons: "#FFFFFF", // button background
|
|
41
|
+
lightButtonsBorder: "#DDDDDD", // button border
|
|
42
|
+
lightButtonsText: "#111827", // button text
|
|
43
|
+
lightButtonsHover: "#f3f4f6", // button hover
|
|
44
|
+
lightButtonsBorderHover: "#f3f4f6", // button border hover
|
|
45
|
+
lightButtonsActive: "#f3f4f6", // button active
|
|
46
|
+
lightButtonsDisabled: "#f3f4f6", // button disabled
|
|
47
|
+
lightButtonsDisabledText: "#f3f4f6", // button disabled text
|
|
48
|
+
lightButtonsIcon: "#333333", // button icon
|
|
49
|
+
// colors for dark theme
|
|
50
|
+
darkHtml: "#111827",
|
|
51
|
+
darkNavbar: "#111827",
|
|
52
|
+
darkNavbarBorder: "#e5e7eb",
|
|
53
|
+
darkNavbarText: "#9ca3af",
|
|
54
|
+
darkNavbarTextHover: "alias:darkNavbarText lighten",
|
|
55
|
+
darkNavbarTextActive: "alias:darkNavbarText lighten",
|
|
56
|
+
darkNavbarIcons: "alias:darkNavbarText opacity:0.7",
|
|
57
|
+
darkSidebar: "#1f2937",
|
|
58
|
+
darkSidebarBorder: "alias:darkSidebarText opacity:0.3",
|
|
59
|
+
darkSidebarItemHover: "alias:darkSidebarText opacity:0.1",
|
|
60
|
+
darkSidebarItemActive: "alias:darkSidebarText opacity:0.4",
|
|
61
|
+
darkSidebarText: "#9ca3af",
|
|
62
|
+
darkSidebarTextHover: "alias:darkSidebarText lighten",
|
|
63
|
+
darkSidebarTextActive: "alias:darkSidebarText lighten",
|
|
64
|
+
darkSidebarDevider: "alias:darkSidebarText opacity:0.3",
|
|
65
|
+
darkSidebarIcons: "alias:darkSidebarText opacity:0.7",
|
|
66
|
+
darkSidebarIconsHover: "alias:darkSidebarText",
|
|
67
|
+
darkSidebarHeading: "alias:darkSidebarText opacity:0.3",
|
|
68
|
+
darkList: "#111111",
|
|
69
|
+
darkListTable: "#1f2937",
|
|
70
|
+
darkListTableHeading: "#334155",
|
|
71
|
+
darkListTableHeadingText: "#9ca3af",
|
|
72
|
+
darkListTableText: "#9ca3af",
|
|
73
|
+
darkListTableRowHover: "#4b5563",
|
|
74
|
+
darkListBreadcrumbsText: "#BBBBBB",
|
|
75
|
+
darkListBorder: "#444444",
|
|
76
|
+
darkForm: "#111111",
|
|
77
|
+
darkFormBorder: "#222222",
|
|
78
|
+
darkFormHeading: "#334155"
|
|
79
|
+
},
|
|
80
|
+
boxShadow: {
|
|
81
|
+
customLight: "0 4px 8px rgba(0, 0, 0, 0.1)", // Lighter shadow
|
|
82
|
+
headerShadow: "0 4px 8px rgba(0, 0, 0, 0.1)", // Lighter shadow
|
|
83
|
+
listTableShadow: "0 4px 8px rgba(0, 0, 0, 0.1)", // Lighter shadow
|
|
84
|
+
resourseFormShadow: "0 4px 8px rgba(0, 0, 0, 0.1)" // Lighter shadow
|
|
85
|
+
},
|
|
86
|
+
fontSize: {
|
|
87
|
+
"headerText-size": "1rem"
|
|
88
|
+
},
|
|
89
|
+
borderRadius: {
|
|
90
|
+
"default": "2px"
|
|
91
|
+
}
|
|
92
|
+
});
|
|
@@ -0,0 +1,301 @@
|
|
|
1
|
+
import path from 'path';
|
|
2
|
+
import { fileURLToPath } from 'url';
|
|
3
|
+
import fs from 'fs';
|
|
4
|
+
// @ts-ignore-next-line
|
|
5
|
+
const csscolors = {
|
|
6
|
+
"aliceblue": "#f0f8ff",
|
|
7
|
+
"antiquewhite": "#faebd7",
|
|
8
|
+
"aqua": "#00ffff",
|
|
9
|
+
"aquamarine": "#7fffd4",
|
|
10
|
+
"azure": "#f0ffff",
|
|
11
|
+
"beige": "#f5f5dc",
|
|
12
|
+
"bisque": "#ffe4c4",
|
|
13
|
+
"black": "#000000",
|
|
14
|
+
"blanchedalmond": "#ffebcd",
|
|
15
|
+
"blue": "#0000ff",
|
|
16
|
+
"blueviolet": "#8a2be2",
|
|
17
|
+
"brown": "#a52a2a",
|
|
18
|
+
"burlywood": "#deb887",
|
|
19
|
+
"cadetblue": "#5f9ea0",
|
|
20
|
+
"chartreuse": "#7fff00",
|
|
21
|
+
"chocolate": "#d2691e",
|
|
22
|
+
"coral": "#ff7f50",
|
|
23
|
+
"cornflowerblue": "#6495ed",
|
|
24
|
+
"cornsilk": "#fff8dc",
|
|
25
|
+
"crimson": "#dc143c",
|
|
26
|
+
"cyan": "#00ffff",
|
|
27
|
+
"darkblue": "#00008b",
|
|
28
|
+
"darkcyan": "#008b8b",
|
|
29
|
+
"darkgoldenrod": "#b8860b",
|
|
30
|
+
"darkgray": "#a9a9a9",
|
|
31
|
+
"darkgreen": "#006400",
|
|
32
|
+
"darkgrey": "#a9a9a9",
|
|
33
|
+
"darkkhaki": "#bdb76b",
|
|
34
|
+
"darkmagenta": "#8b008b",
|
|
35
|
+
"darkolivegreen": "#556b2f",
|
|
36
|
+
"darkorange": "#ff8c00",
|
|
37
|
+
"darkorchid": "#9932cc",
|
|
38
|
+
"darkred": "#8b0000",
|
|
39
|
+
"darksalmon": "#e9967a",
|
|
40
|
+
"darkseagreen": "#8fbc8f",
|
|
41
|
+
"darkslateblue": "#483d8b",
|
|
42
|
+
"darkslategray": "#2f4f4f",
|
|
43
|
+
"darkslategrey": "#2f4f4f",
|
|
44
|
+
"darkturquoise": "#00ced1",
|
|
45
|
+
"darkviolet": "#9400d3",
|
|
46
|
+
"deeppink": "#ff1493",
|
|
47
|
+
"deepskyblue": "#00bfff",
|
|
48
|
+
"dimgray": "#696969",
|
|
49
|
+
"dimgrey": "#696969",
|
|
50
|
+
"dodgerblue": "#1e90ff",
|
|
51
|
+
"firebrick": "#b22222",
|
|
52
|
+
"floralwhite": "#fffaf0",
|
|
53
|
+
"forestgreen": "#228b22",
|
|
54
|
+
"fuchsia": "#ff00ff",
|
|
55
|
+
"gainsboro": "#dcdcdc",
|
|
56
|
+
"ghostwhite": "#f8f8ff",
|
|
57
|
+
"goldenrod": "#daa520",
|
|
58
|
+
"gold": "#ffd700",
|
|
59
|
+
"gray": "#808080",
|
|
60
|
+
"green": "#008000",
|
|
61
|
+
"greenyellow": "#adff2f",
|
|
62
|
+
"grey": "#808080",
|
|
63
|
+
"honeydew": "#f0fff0",
|
|
64
|
+
"hotpink": "#ff69b4",
|
|
65
|
+
"indianred": "#cd5c5c",
|
|
66
|
+
"indigo": "#4b0082",
|
|
67
|
+
"ivory": "#fffff0",
|
|
68
|
+
"khaki": "#f0e68c",
|
|
69
|
+
"lavenderblush": "#fff0f5",
|
|
70
|
+
"lavender": "#e6e6fa",
|
|
71
|
+
"lawngreen": "#7cfc00",
|
|
72
|
+
"lemonchiffon": "#fffacd",
|
|
73
|
+
"lightblue": "#add8e6",
|
|
74
|
+
"lightcoral": "#f08080",
|
|
75
|
+
"lightcyan": "#e0ffff",
|
|
76
|
+
"lightgoldenrodyellow": "#fafad2",
|
|
77
|
+
"lightgray": "#d3d3d3",
|
|
78
|
+
"lightgreen": "#90ee90",
|
|
79
|
+
"lightgrey": "#d3d3d3",
|
|
80
|
+
"lightpink": "#ffb6c1",
|
|
81
|
+
"lightsalmon": "#ffa07a",
|
|
82
|
+
"lightseagreen": "#20b2aa",
|
|
83
|
+
"lightskyblue": "#87cefa",
|
|
84
|
+
"lightslategray": "#778899",
|
|
85
|
+
"lightslategrey": "#778899",
|
|
86
|
+
"lightsteelblue": "#b0c4de",
|
|
87
|
+
"lightyellow": "#ffffe0",
|
|
88
|
+
"lime": "#00ff00",
|
|
89
|
+
"limegreen": "#32cd32",
|
|
90
|
+
"linen": "#faf0e6",
|
|
91
|
+
"magenta": "#ff00ff",
|
|
92
|
+
"maroon": "#800000",
|
|
93
|
+
"mediumaquamarine": "#66cdaa",
|
|
94
|
+
"mediumblue": "#0000cd",
|
|
95
|
+
"mediumorchid": "#ba55d3",
|
|
96
|
+
"mediumpurple": "#9370db",
|
|
97
|
+
"mediumseagreen": "#3cb371",
|
|
98
|
+
"mediumslateblue": "#7b68ee",
|
|
99
|
+
"mediumspringgreen": "#00fa9a",
|
|
100
|
+
"mediumturquoise": "#48d1cc",
|
|
101
|
+
"mediumvioletred": "#c71585",
|
|
102
|
+
"midnightblue": "#191970",
|
|
103
|
+
"mintcream": "#f5fffa",
|
|
104
|
+
"mistyrose": "#ffe4e1",
|
|
105
|
+
"moccasin": "#ffe4b5",
|
|
106
|
+
"navajowhite": "#ffdead",
|
|
107
|
+
"navy": "#000080",
|
|
108
|
+
"oldlace": "#fdf5e6",
|
|
109
|
+
"olive": "#808000",
|
|
110
|
+
"olivedrab": "#6b8e23",
|
|
111
|
+
"orange": "#ffa500",
|
|
112
|
+
"orangered": "#ff4500",
|
|
113
|
+
"orchid": "#da70d6",
|
|
114
|
+
"palegoldenrod": "#eee8aa",
|
|
115
|
+
"palegreen": "#98fb98",
|
|
116
|
+
"paleturquoise": "#afeeee",
|
|
117
|
+
"palevioletred": "#db7093",
|
|
118
|
+
"papayawhip": "#ffefd5",
|
|
119
|
+
"peachpuff": "#ffdab9",
|
|
120
|
+
"peru": "#cd853f",
|
|
121
|
+
"pink": "#ffc0cb",
|
|
122
|
+
"plum": "#dda0dd",
|
|
123
|
+
"powderblue": "#b0e0e6",
|
|
124
|
+
"purple": "#800080",
|
|
125
|
+
"rebeccapurple": "#663399",
|
|
126
|
+
"red": "#ff0000",
|
|
127
|
+
"rosybrown": "#bc8f8f",
|
|
128
|
+
"royalblue": "#4169e1",
|
|
129
|
+
"saddlebrown": "#8b4513",
|
|
130
|
+
"salmon": "#fa8072",
|
|
131
|
+
"sandybrown": "#f4a460",
|
|
132
|
+
"seagreen": "#2e8b57",
|
|
133
|
+
"seashell": "#fff5ee",
|
|
134
|
+
"sienna": "#a0522d",
|
|
135
|
+
"silver": "#c0c0c0",
|
|
136
|
+
"skyblue": "#87ceeb",
|
|
137
|
+
"slateblue": "#6a5acd",
|
|
138
|
+
"slategray": "#708090",
|
|
139
|
+
"slategrey": "#708090",
|
|
140
|
+
"snow": "#fffafa",
|
|
141
|
+
"springgreen": "#00ff7f",
|
|
142
|
+
"steelblue": "#4682b4",
|
|
143
|
+
"tan": "#d2b48c",
|
|
144
|
+
"teal": "#008080",
|
|
145
|
+
"thistle": "#d8bfd8",
|
|
146
|
+
"tomato": "#ff6347",
|
|
147
|
+
"turquoise": "#40e0d0",
|
|
148
|
+
"violet": "#ee82ee",
|
|
149
|
+
"wheat": "#f5deb3",
|
|
150
|
+
"white": "#ffffff",
|
|
151
|
+
"whitesmoke": "#f5f5f5",
|
|
152
|
+
"yellow": "#ffff00",
|
|
153
|
+
"yellowgreen": "#9acd32"
|
|
154
|
+
};
|
|
155
|
+
export function guessLabelFromName(name) {
|
|
156
|
+
if (name.includes('_')) {
|
|
157
|
+
return name.split('_').map((part) => part.charAt(0).toUpperCase() + part.slice(1)).join(' ');
|
|
158
|
+
}
|
|
159
|
+
else if (name.includes('-')) {
|
|
160
|
+
return name.split('-').map((part) => part.charAt(0).toUpperCase() + part.slice(1)).join(' ');
|
|
161
|
+
}
|
|
162
|
+
else {
|
|
163
|
+
// split by capital letters
|
|
164
|
+
return name.split(/(?=[A-Z])/).map((part) => part.charAt(0).toUpperCase() + part.slice(1)).join(' ');
|
|
165
|
+
}
|
|
166
|
+
}
|
|
167
|
+
export const currentFileDir = (metaUrl) => {
|
|
168
|
+
const __filename = fileURLToPath(metaUrl);
|
|
169
|
+
let __dirname = path.dirname(__filename);
|
|
170
|
+
if (__dirname.endsWith('/dist/modules')) {
|
|
171
|
+
// in prod build we are in dist also, so make another back jump to go true sorces
|
|
172
|
+
__dirname = path.join(__dirname, '..');
|
|
173
|
+
}
|
|
174
|
+
return __dirname;
|
|
175
|
+
};
|
|
176
|
+
export const ADMIN_FORTH_ABSOLUTE_PATH = path.join(currentFileDir(import.meta.url), '..');
|
|
177
|
+
const package_json = JSON.parse(fs.readFileSync(path.join(ADMIN_FORTH_ABSOLUTE_PATH, 'package.json'), 'utf8'));
|
|
178
|
+
export const ADMINFORTH_VERSION = package_json.version;
|
|
179
|
+
export function getComponentNameFromPath(filePath) {
|
|
180
|
+
return filePath.replace(/@/g, '').replace(/\./g, '').replace(/\//g, '');
|
|
181
|
+
}
|
|
182
|
+
export function listify(param) {
|
|
183
|
+
return param || [];
|
|
184
|
+
}
|
|
185
|
+
export function deepMerge(target, source) {
|
|
186
|
+
if (typeof target !== 'object' || target === null) {
|
|
187
|
+
return source;
|
|
188
|
+
}
|
|
189
|
+
for (let key in source) {
|
|
190
|
+
if (source.hasOwnProperty(key)) {
|
|
191
|
+
if (typeof source[key] === 'object' && source[key] !== null) {
|
|
192
|
+
if (!target[key]) {
|
|
193
|
+
target[key] = {};
|
|
194
|
+
}
|
|
195
|
+
deepMerge(target[key], source[key]);
|
|
196
|
+
}
|
|
197
|
+
else {
|
|
198
|
+
target[key] = source[key];
|
|
199
|
+
}
|
|
200
|
+
}
|
|
201
|
+
}
|
|
202
|
+
return target;
|
|
203
|
+
}
|
|
204
|
+
function toCamelCase(str) {
|
|
205
|
+
return str.replace(/[-_](.)/g, (_, char) => char.toUpperCase());
|
|
206
|
+
}
|
|
207
|
+
export function transformObject(obj, parentKey = '', result = {}) {
|
|
208
|
+
for (const key in obj) {
|
|
209
|
+
if (obj.hasOwnProperty(key)) {
|
|
210
|
+
const camelCaseKey = toCamelCase(parentKey ? `${parentKey}_${key}` : key);
|
|
211
|
+
if (typeof obj[key] === 'object' && !Array.isArray(obj[key])) {
|
|
212
|
+
transformObject(obj[key], camelCaseKey, result);
|
|
213
|
+
}
|
|
214
|
+
else {
|
|
215
|
+
result[camelCaseKey] = obj[key];
|
|
216
|
+
}
|
|
217
|
+
}
|
|
218
|
+
}
|
|
219
|
+
//remove 'Default' from keys
|
|
220
|
+
for (const key in result) {
|
|
221
|
+
if (key.includes('Main')) {
|
|
222
|
+
const newKey = key.replace('Main', '');
|
|
223
|
+
result[newKey] = result[key];
|
|
224
|
+
delete result[key];
|
|
225
|
+
}
|
|
226
|
+
}
|
|
227
|
+
return result;
|
|
228
|
+
}
|
|
229
|
+
function hexToRGBA(hex, opacity) {
|
|
230
|
+
var c;
|
|
231
|
+
if (/^#([A-Fa-f0-9]{3}){1,2}$/.test(hex)) {
|
|
232
|
+
c = hex.substring(1).split('');
|
|
233
|
+
if (c.length == 3) {
|
|
234
|
+
c = [c[0], c[0], c[1], c[1], c[2], c[2]];
|
|
235
|
+
}
|
|
236
|
+
c = '0x' + c.join('');
|
|
237
|
+
return 'rgba(' + [(c >> 16) & 255, (c >> 8) & 255, c & 255].join(',') + ',' + opacity + ')';
|
|
238
|
+
}
|
|
239
|
+
throw new Error('Bad Hex');
|
|
240
|
+
}
|
|
241
|
+
export function createRGBA(color, opacity) {
|
|
242
|
+
if (!color)
|
|
243
|
+
return;
|
|
244
|
+
else if (color.startsWith("rgba")) {
|
|
245
|
+
//add opacity to existing rgba color
|
|
246
|
+
const rgb = color.match(/[\d.]+/g);
|
|
247
|
+
console.log('rgb', rgb);
|
|
248
|
+
return `rgba(${rgb[0]}, ${rgb[1]}, ${rgb[2]}, ${Number(rgb[3]) * opacity})`;
|
|
249
|
+
}
|
|
250
|
+
else if (color.startsWith("rgb")) {
|
|
251
|
+
const rgb = color.match(/\d+/g);
|
|
252
|
+
return `rgba(${rgb[0]}, ${rgb[1]}, ${rgb[2]}, ${opacity})`;
|
|
253
|
+
}
|
|
254
|
+
else if (color.startsWith("#")) {
|
|
255
|
+
return hexToRGBA(color, opacity);
|
|
256
|
+
}
|
|
257
|
+
else if (csscolors[color]) {
|
|
258
|
+
return hexToRGBA(csscolors[color], opacity);
|
|
259
|
+
}
|
|
260
|
+
else {
|
|
261
|
+
return color;
|
|
262
|
+
}
|
|
263
|
+
}
|
|
264
|
+
export function parseColorForAliases(str) {
|
|
265
|
+
const aliasRegex = /alias:([^ ]+)/;
|
|
266
|
+
const opacityRegex = /opacity:([0-9.]+)/;
|
|
267
|
+
const darkenRegex = /darken/;
|
|
268
|
+
const lightenRegex = /lighten/;
|
|
269
|
+
// Extract alias and properties
|
|
270
|
+
const aliasMatch = str.match(aliasRegex);
|
|
271
|
+
const opacityMatch = str.match(opacityRegex);
|
|
272
|
+
const darkenMatch = str.match(darkenRegex);
|
|
273
|
+
const lightenMatch = str.match(lightenRegex);
|
|
274
|
+
return { aliasMatch, opacityMatch, darkenMatch, lightenMatch };
|
|
275
|
+
}
|
|
276
|
+
export function darkenRGBA(rgba) {
|
|
277
|
+
let amount = 0.2;
|
|
278
|
+
// Extract the RGBA components
|
|
279
|
+
let [r, g, b, a] = rgba.match(/\d+/g).map(Number);
|
|
280
|
+
// Ensure amount is between 0 and 1
|
|
281
|
+
amount = Math.max(0, Math.min(1, amount));
|
|
282
|
+
// Calculate the new RGB values
|
|
283
|
+
r = Math.max(0, r * (1 - amount));
|
|
284
|
+
g = Math.max(0, g * (1 - amount));
|
|
285
|
+
b = Math.max(0, b * (1 - amount));
|
|
286
|
+
// Return the new RGBA color
|
|
287
|
+
return `rgba(${Math.round(r)}, ${Math.round(g)}, ${Math.round(b)}, ${a})`;
|
|
288
|
+
}
|
|
289
|
+
export function lightenRGBA(rgba) {
|
|
290
|
+
let amount = 0.2;
|
|
291
|
+
// Extract the RGBA components
|
|
292
|
+
let [r, g, b, a] = rgba.match(/\d+/g).map(Number);
|
|
293
|
+
// Ensure amount is between 0 and 1
|
|
294
|
+
amount = Math.max(0, Math.min(1, amount));
|
|
295
|
+
// Calculate the new RGB values
|
|
296
|
+
r = Math.min(255, r * (1 + amount));
|
|
297
|
+
g = Math.min(255, g * (1 + amount));
|
|
298
|
+
b = Math.min(255, b * (1 + amount));
|
|
299
|
+
// Return the new RGBA color
|
|
300
|
+
return `rgba(${Math.round(r)}, ${Math.round(g)}, ${Math.round(b)}, ${a})`;
|
|
301
|
+
}
|
|
@@ -0,0 +1,149 @@
|
|
|
1
|
+
var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
|
|
2
|
+
function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
|
|
3
|
+
return new (P || (P = Promise))(function (resolve, reject) {
|
|
4
|
+
function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
|
|
5
|
+
function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
|
|
6
|
+
function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
|
|
7
|
+
step((generator = generator.apply(thisArg, _arguments || [])).next());
|
|
8
|
+
});
|
|
9
|
+
};
|
|
10
|
+
import AdminForthPlugin from "../base.js";
|
|
11
|
+
import twofactor from 'node-2fa';
|
|
12
|
+
export default class TwoFactorsAuthPlugin extends AdminForthPlugin {
|
|
13
|
+
constructor(options) {
|
|
14
|
+
super(options, import.meta.url);
|
|
15
|
+
this.options = options;
|
|
16
|
+
}
|
|
17
|
+
modifyResourceConfig(adminforth, resourceConfig) {
|
|
18
|
+
super.modifyResourceConfig(adminforth, resourceConfig);
|
|
19
|
+
this.adminforth = adminforth;
|
|
20
|
+
this.adminForthAuth = adminforth.auth;
|
|
21
|
+
const customPages = this.adminforth.config.customization.customPages;
|
|
22
|
+
customPages.push({
|
|
23
|
+
path: '/confirm2fa',
|
|
24
|
+
component: { file: this.componentPath('TwoFactorsConfirmation.vue'), meta: { customLayout: true } }
|
|
25
|
+
});
|
|
26
|
+
customPages.push({
|
|
27
|
+
path: '/setup2fa',
|
|
28
|
+
component: { file: this.componentPath('TwoFactorsSetup.vue'), meta: { title: 'Setup 2FA', customLayout: true } }
|
|
29
|
+
});
|
|
30
|
+
this.activate(resourceConfig, adminforth);
|
|
31
|
+
}
|
|
32
|
+
activate(resourceConfig, adminforth) {
|
|
33
|
+
if (!this.options.twoFaSecretFieldName) {
|
|
34
|
+
throw new Error('twoFaSecretFieldName is required');
|
|
35
|
+
}
|
|
36
|
+
if (typeof this.options.twoFaSecretFieldName !== 'string') {
|
|
37
|
+
throw new Error('twoFaSecretFieldName must be a string');
|
|
38
|
+
}
|
|
39
|
+
this.authResource = resourceConfig;
|
|
40
|
+
if (!this.authResource.columns.some((col) => col.name === this.options.twoFaSecretFieldName)) {
|
|
41
|
+
throw new Error(`Column ${this.options.twoFaSecretFieldName} not found in ${this.authResource.label}`);
|
|
42
|
+
}
|
|
43
|
+
const beforeLoginConfirmation = this.adminforth.config.auth;
|
|
44
|
+
if (!beforeLoginConfirmation.beforeLoginConfirmation) {
|
|
45
|
+
beforeLoginConfirmation.beforeLoginConfirmation = [];
|
|
46
|
+
}
|
|
47
|
+
beforeLoginConfirmation.beforeLoginConfirmation.push((_a) => __awaiter(this, [_a], void 0, function* ({ adminUser }) {
|
|
48
|
+
if (adminUser.isRoot) {
|
|
49
|
+
return { body: { loginAllowed: true }, ok: true };
|
|
50
|
+
}
|
|
51
|
+
const secret = adminUser.dbUser[this.options.twoFaSecretFieldName];
|
|
52
|
+
const userName = adminUser.dbUser[adminforth.config.auth.usernameField];
|
|
53
|
+
const brandName = adminforth.config.customization.brandName;
|
|
54
|
+
const authResource = adminforth.config.resources.find((res) => res.resourceId === adminforth.config.auth.resourceId);
|
|
55
|
+
const authPk = authResource.columns.find((col) => col.primaryKey).name;
|
|
56
|
+
const userPk = adminUser.dbUser[authPk];
|
|
57
|
+
let newSecret = null;
|
|
58
|
+
if (!secret) {
|
|
59
|
+
const tempSecret = twofactor.generateSecret({ name: brandName, account: userName });
|
|
60
|
+
newSecret = tempSecret.secret;
|
|
61
|
+
}
|
|
62
|
+
else {
|
|
63
|
+
return {
|
|
64
|
+
body: {
|
|
65
|
+
loginAllowed: false,
|
|
66
|
+
redirectTo: '/confirm2fa',
|
|
67
|
+
setCookie: [{
|
|
68
|
+
name: 'totpTemporaryJWT',
|
|
69
|
+
value: this.adminforth.auth.issueJWT({ userName, issuer: brandName, pk: userPk }, 'tempTotp'),
|
|
70
|
+
expiry: '1h',
|
|
71
|
+
httpOnly: true
|
|
72
|
+
},]
|
|
73
|
+
},
|
|
74
|
+
ok: true
|
|
75
|
+
};
|
|
76
|
+
}
|
|
77
|
+
const totpTemporaryJWT = this.adminforth.auth.issueJWT({ userName, newSecret, issuer: brandName, pk: userPk }, 'tempTotp');
|
|
78
|
+
return {
|
|
79
|
+
body: {
|
|
80
|
+
loginAllowed: false,
|
|
81
|
+
redirectTo: secret ? '/confirm2fa' : '/setup2fa',
|
|
82
|
+
setCookie: [{
|
|
83
|
+
name: 'totpTemporaryJWT',
|
|
84
|
+
value: totpTemporaryJWT,
|
|
85
|
+
expiry: '1h',
|
|
86
|
+
httpOnly: true
|
|
87
|
+
},]
|
|
88
|
+
},
|
|
89
|
+
ok: true
|
|
90
|
+
};
|
|
91
|
+
}));
|
|
92
|
+
}
|
|
93
|
+
setupEndpoints(server) {
|
|
94
|
+
server.endpoint({
|
|
95
|
+
method: 'POST',
|
|
96
|
+
path: `/plugin/twofa/initSetup`,
|
|
97
|
+
noAuth: true,
|
|
98
|
+
handler: (server) => __awaiter(this, void 0, void 0, function* () {
|
|
99
|
+
const toReturn = { totpJWT: null, status: 'ok', };
|
|
100
|
+
const totpTemporaryJWT = server.cookies['adminforth_totpTemporaryJWT'];
|
|
101
|
+
if (totpTemporaryJWT) {
|
|
102
|
+
toReturn.totpJWT = totpTemporaryJWT;
|
|
103
|
+
}
|
|
104
|
+
return toReturn;
|
|
105
|
+
})
|
|
106
|
+
});
|
|
107
|
+
server.endpoint({
|
|
108
|
+
method: 'POST',
|
|
109
|
+
path: `/plugin/twofa/confirmSetup`,
|
|
110
|
+
noAuth: true,
|
|
111
|
+
handler: (_a) => __awaiter(this, [_a], void 0, function* ({ body, adminUser, response, cookies }) {
|
|
112
|
+
const totpTemporaryJWT = cookies['adminforth_totpTemporaryJWT'];
|
|
113
|
+
const decoded = yield this.adminforth.auth.verify(totpTemporaryJWT, 'tempTotp');
|
|
114
|
+
if (!decoded) {
|
|
115
|
+
return { status: 'error', message: 'Invalid token' };
|
|
116
|
+
}
|
|
117
|
+
if (decoded.newSecret) {
|
|
118
|
+
const verified = twofactor.verifyToken(decoded.newSecret, body.code);
|
|
119
|
+
if (verified) {
|
|
120
|
+
this.connectors = this.adminforth.connectors;
|
|
121
|
+
const connector = this.connectors[this.authResource.dataSource];
|
|
122
|
+
yield connector.updateRecord({ resource: this.authResource, recordId: decoded.pk, newValues: { [this.options.twoFaSecretFieldName]: decoded.newSecret } });
|
|
123
|
+
this.adminForthAuth.removeCustomCookie({ response, name: 'totpTemporaryJWT' });
|
|
124
|
+
this.adminForthAuth.setAuthCookie({ response, username: decoded.userName, pk: decoded.pk });
|
|
125
|
+
return { status: 'ok', allowedLogin: true };
|
|
126
|
+
}
|
|
127
|
+
else {
|
|
128
|
+
return { error: 'Wrong or expired OTP code' };
|
|
129
|
+
}
|
|
130
|
+
}
|
|
131
|
+
else {
|
|
132
|
+
// user already has secret, get it
|
|
133
|
+
this.connectors = this.adminforth.connectors;
|
|
134
|
+
const connector = this.connectors[this.authResource.dataSource];
|
|
135
|
+
const user = yield connector.getRecordByPrimaryKey(this.authResource, decoded.pk);
|
|
136
|
+
const verified = twofactor.verifyToken(user[this.options.twoFaSecretFieldName], body.code);
|
|
137
|
+
if (verified) {
|
|
138
|
+
this.adminForthAuth.removeCustomCookie({ response, name: 'totpTemporaryJWT' });
|
|
139
|
+
this.adminForthAuth.setAuthCookie({ response, username: decoded.userName, pk: decoded.pk });
|
|
140
|
+
return { status: 'ok', allowedLogin: true };
|
|
141
|
+
}
|
|
142
|
+
else {
|
|
143
|
+
return { error: 'Wrong or expired OTP code' };
|
|
144
|
+
}
|
|
145
|
+
}
|
|
146
|
+
})
|
|
147
|
+
});
|
|
148
|
+
}
|
|
149
|
+
}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
import { getComponentNameFromPath } from '../modules/utils.js';
|
|
2
|
+
import { currentFileDir } from '../modules/utils.js';
|
|
3
|
+
import path from 'path';
|
|
4
|
+
import fs from 'fs';
|
|
5
|
+
import { v4 as uuidv4 } from 'uuid';
|
|
6
|
+
export default class AdminForthPlugin {
|
|
7
|
+
constructor(pluginOptions, metaUrl) {
|
|
8
|
+
this.customFolderName = 'custom';
|
|
9
|
+
// set up plugin here
|
|
10
|
+
this.pluginDir = currentFileDir(metaUrl);
|
|
11
|
+
this.pluginInstanceId = uuidv4();
|
|
12
|
+
}
|
|
13
|
+
setupEndpoints(server) {
|
|
14
|
+
}
|
|
15
|
+
modifyResourceConfig(adminforth, resourceConfig) {
|
|
16
|
+
this.adminforth = adminforth;
|
|
17
|
+
}
|
|
18
|
+
componentPath(componentFile) {
|
|
19
|
+
const key = `@@/plugins/${this.constructor.name}/${componentFile}`;
|
|
20
|
+
const componentName = getComponentNameFromPath(key);
|
|
21
|
+
const absSrcFolder = path.join(this.pluginDir, this.customFolderName);
|
|
22
|
+
if (!this.adminforth.codeInjector.srcFoldersToSync[absSrcFolder]) {
|
|
23
|
+
this.adminforth.codeInjector.srcFoldersToSync[absSrcFolder] = `./plugins/${this.constructor.name}/`;
|
|
24
|
+
}
|
|
25
|
+
if (!this.adminforth.codeInjector.allComponentNames[key]) {
|
|
26
|
+
const absSrcPath = path.join(absSrcFolder, componentFile);
|
|
27
|
+
if (!fs.existsSync(absSrcPath)) {
|
|
28
|
+
throw new Error(`Plugin "${this.constructor.name}" tried to use file as component which does not exist at "${absSrcPath}"`);
|
|
29
|
+
}
|
|
30
|
+
this.adminforth.codeInjector.allComponentNames[key] = componentName;
|
|
31
|
+
}
|
|
32
|
+
return key;
|
|
33
|
+
}
|
|
34
|
+
}
|