lupine.api 1.1.45 → 1.1.47
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/admin/admin-frame-helper.tsx +364 -0
- package/admin/admin-frame.tsx +25 -327
- package/admin/admin-index.tsx +6 -7
- package/admin/admin-login.tsx +39 -27
- package/admin/admin-menu-list.tsx +4 -4
- package/admin/admin-page-list.tsx +4 -4
- package/admin/admin-release.tsx +40 -31
- package/admin/admin-table-list.tsx +3 -4
- package/admin/index.ts +6 -3
- package/package.json +1 -1
- package/src/admin-api/admin-api-helper.ts +205 -0
- package/src/admin-api/admin-api.ts +5 -2
- package/src/admin-api/admin-auth.ts +61 -8
- package/src/admin-api/admin-config.ts +1 -12
- package/src/admin-api/admin-performance.ts +2 -2
- package/src/admin-api/admin-release.ts +66 -20
- package/src/admin-api/admin-resources.ts +3 -3
- package/src/admin-api/admin-token-helper.ts +2 -2
- package/src/admin-api/index.ts +1 -1
- package/src/lang/api-lang-en.ts +0 -1
- package/src/lang/api-lang-zh-cn.ts +0 -1
- package/src/lib/utils/fs-utils.ts +15 -1
- package/admin/admin-frame-props.tsx +0 -9
- package/src/admin-api/admin-helper.ts +0 -111
package/admin/admin-release.tsx
CHANGED
|
@@ -10,13 +10,6 @@ import {
|
|
|
10
10
|
downloadStream,
|
|
11
11
|
} from 'lupine.components';
|
|
12
12
|
|
|
13
|
-
interface DirProps {
|
|
14
|
-
name: string;
|
|
15
|
-
time: string;
|
|
16
|
-
size: number;
|
|
17
|
-
dir: boolean;
|
|
18
|
-
items?: DirProps[];
|
|
19
|
-
}
|
|
20
13
|
interface ReleaseListProps {
|
|
21
14
|
result: any;
|
|
22
15
|
onUpdate: () => void;
|
|
@@ -101,7 +94,7 @@ const ReleaseList = (props: ReleaseListProps) => {
|
|
|
101
94
|
</label>
|
|
102
95
|
</div>
|
|
103
96
|
))}
|
|
104
|
-
<label class='label mr-m release-label'>(
|
|
97
|
+
<label class='label mr-m release-label'>(Skip *.js.map files)</label>
|
|
105
98
|
</div>
|
|
106
99
|
</div>
|
|
107
100
|
<LogList logs={props.result.logs} onLogClick={props.onLogClick} />
|
|
@@ -123,12 +116,13 @@ const LogList = (props: {
|
|
|
123
116
|
<div class='row-box mt-m'>
|
|
124
117
|
<label class='label mr-m release-label'>Logs:</label>
|
|
125
118
|
<div type='text'>
|
|
126
|
-
{props.logs &&
|
|
127
|
-
|
|
128
|
-
<
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
119
|
+
{props.logs &&
|
|
120
|
+
props.logs.map((log: { name: string; size: number; time: string }) => (
|
|
121
|
+
<div>
|
|
122
|
+
<label class='release-log' onClick={() => props.onLogClick(log.name)}>{`${log.name}`}</label> (
|
|
123
|
+
{log.time}; {formatBytes(log.size)}){' '}
|
|
124
|
+
</div>
|
|
125
|
+
))}
|
|
132
126
|
</div>
|
|
133
127
|
</div>
|
|
134
128
|
</div>
|
|
@@ -138,7 +132,7 @@ const LogList = (props: {
|
|
|
138
132
|
export const AdminReleasePage = () => {
|
|
139
133
|
const fetchData = async (options: { targetUrl: string; accessToken: string; log?: boolean }) => {
|
|
140
134
|
const data = await getRenderPageProps().renderPageFunctions.fetchData('/api/admin/release/check', options);
|
|
141
|
-
console.log('
|
|
135
|
+
console.log('release/check', data);
|
|
142
136
|
return data.json;
|
|
143
137
|
};
|
|
144
138
|
const css: CssProps = {
|
|
@@ -153,11 +147,18 @@ export const AdminReleasePage = () => {
|
|
|
153
147
|
const domLog = new HtmlVar('');
|
|
154
148
|
const domUpdate = new HtmlVar('');
|
|
155
149
|
const getDomData = () => {
|
|
156
|
-
const
|
|
150
|
+
const domFromList = ref.$('.from-list');
|
|
151
|
+
let fromValue = '';
|
|
152
|
+
if (!domFromList) {
|
|
153
|
+
const dataOld = JSON.parse(localStorage.getItem('admin-release') || '{}');
|
|
154
|
+
fromValue = dataOld.fromList;
|
|
155
|
+
} else {
|
|
156
|
+
fromValue = domFromList.value;
|
|
157
|
+
}
|
|
157
158
|
const data = {
|
|
158
|
-
targetUrl:
|
|
159
|
-
accessToken:
|
|
160
|
-
fromList:
|
|
159
|
+
targetUrl: ref.$('.target-url').value,
|
|
160
|
+
accessToken: ref.$('.access-token').value,
|
|
161
|
+
fromList: fromValue,
|
|
161
162
|
};
|
|
162
163
|
localStorage.setItem('admin-release', JSON.stringify(data));
|
|
163
164
|
return data;
|
|
@@ -170,18 +171,23 @@ export const AdminReleasePage = () => {
|
|
|
170
171
|
return;
|
|
171
172
|
}
|
|
172
173
|
|
|
173
|
-
const fromList =
|
|
174
|
-
const toList =
|
|
175
|
-
const chkServer =
|
|
176
|
-
const chkApi =
|
|
177
|
-
const chkWeb =
|
|
178
|
-
const webSub =
|
|
179
|
-
const webSubs =
|
|
174
|
+
const fromList = ref.$('.from-list').value;
|
|
175
|
+
const toList = ref.$('.to-list').value;
|
|
176
|
+
const chkServer = ref.$('.chk-server').checked;
|
|
177
|
+
const chkApi = ref.$('.chk-api').checked;
|
|
178
|
+
const chkWeb = ref.$('.chk-web').checked;
|
|
179
|
+
// const webSub = ref.$('.input-web-sub').value;
|
|
180
|
+
const webSubs = ref.$all('.chk-web-sub') as HTMLInputElement[];
|
|
180
181
|
const webSubsChecked = Array.from(webSubs)
|
|
181
182
|
.filter((input) => input.checked)
|
|
182
183
|
.map((input) => input.value);
|
|
183
|
-
const
|
|
184
|
-
|
|
184
|
+
const wrongWebSubs = webSubsChecked.filter((s) => !s.startsWith(fromList + '_web/'));
|
|
185
|
+
if (wrongWebSubs.length > 0) {
|
|
186
|
+
NotificationMessage.sendMessage(`Some web sub folder is not under ${fromList}`, NotificationColor.Error);
|
|
187
|
+
return;
|
|
188
|
+
}
|
|
189
|
+
const chkEnv = ref.$('.chk-env').checked;
|
|
190
|
+
const chkBackup = ref.$('.chk-backup').checked;
|
|
185
191
|
if (!chkServer && !chkApi && !chkWeb && !chkEnv) {
|
|
186
192
|
NotificationMessage.sendMessage('Please select the release options', NotificationColor.Error);
|
|
187
193
|
return;
|
|
@@ -202,16 +208,19 @@ export const AdminReleasePage = () => {
|
|
|
202
208
|
chkServer,
|
|
203
209
|
chkApi,
|
|
204
210
|
chkWeb,
|
|
205
|
-
webSub, // will be deprecated
|
|
211
|
+
// webSub, // will be deprecated
|
|
206
212
|
webSubs: webSubsChecked,
|
|
207
213
|
chkEnv,
|
|
208
214
|
chkBackup,
|
|
209
215
|
});
|
|
210
216
|
const dataResponse = await response.json;
|
|
211
|
-
console.log('
|
|
217
|
+
console.log('release/update', dataResponse);
|
|
212
218
|
releaseUpdateBtn.disabled = false;
|
|
213
219
|
if (!dataResponse || dataResponse.status !== 'ok') {
|
|
214
|
-
NotificationMessage.sendMessage(
|
|
220
|
+
NotificationMessage.sendMessage(
|
|
221
|
+
dataResponse.message || 'Failed to update release (timeout, possibly backend is runing, please wait!)',
|
|
222
|
+
NotificationColor.Error
|
|
223
|
+
);
|
|
215
224
|
return;
|
|
216
225
|
}
|
|
217
226
|
NotificationMessage.sendMessage('Release updated successfully', NotificationColor.Success);
|
|
@@ -1,5 +1,4 @@
|
|
|
1
1
|
import {
|
|
2
|
-
DomUtils,
|
|
3
2
|
NotificationColor,
|
|
4
3
|
NotificationMessage,
|
|
5
4
|
CssProps,
|
|
@@ -8,8 +7,8 @@ import {
|
|
|
8
7
|
mountInnerComponent,
|
|
9
8
|
downloadLink,
|
|
10
9
|
} from 'lupine.components';
|
|
11
|
-
import { adminFrameProps } from './admin-frame-props';
|
|
12
10
|
import { TableDataPage } from './admin-table-data';
|
|
11
|
+
import { adminFrameHelper } from './admin-frame-helper';
|
|
13
12
|
|
|
14
13
|
const fetchTableList = async () => {
|
|
15
14
|
const data = await getRenderPageProps().renderPageFunctions.fetchData('/api/admin/db/tables/list');
|
|
@@ -29,10 +28,10 @@ const fetchTableTruncateAll = async () => {
|
|
|
29
28
|
};
|
|
30
29
|
|
|
31
30
|
export const TableListPage = () => {
|
|
32
|
-
const refUpdate =
|
|
31
|
+
const refUpdate = adminFrameHelper.getTabsHook();
|
|
33
32
|
|
|
34
33
|
const openTablePanel = async (tableName: string) => {
|
|
35
|
-
if (refUpdate?.getCount && refUpdate.getCount() >
|
|
34
|
+
if (refUpdate?.getCount && refUpdate.getCount() > adminFrameHelper.getMaxTabsCount()) {
|
|
36
35
|
alert('You are opening too many pages');
|
|
37
36
|
return;
|
|
38
37
|
}
|
package/admin/index.ts
CHANGED
|
@@ -1,6 +1,9 @@
|
|
|
1
1
|
export * from './admin-css';
|
|
2
|
+
export * from './admin-db';
|
|
3
|
+
export * from './admin-frame';
|
|
4
|
+
export * from './admin-frame-helper';
|
|
2
5
|
export * from './admin-index';
|
|
3
6
|
export * from './admin-login';
|
|
4
|
-
|
|
5
|
-
export * from './admin-
|
|
6
|
-
export * from './admin-
|
|
7
|
+
export * from './admin-release';
|
|
8
|
+
export * from './admin-tokens';
|
|
9
|
+
export * from './admin-performance';
|
package/package.json
CHANGED
|
@@ -0,0 +1,205 @@
|
|
|
1
|
+
import { ServerResponse } from 'http';
|
|
2
|
+
import { ApiHelper } from '../api';
|
|
3
|
+
import { CryptoUtils, Logger } from '../lib';
|
|
4
|
+
import { ServerRequest } from '../models';
|
|
5
|
+
|
|
6
|
+
/*
|
|
7
|
+
dev-admin uses different authentication method from frontend.
|
|
8
|
+
dev-admin only provides fixed username and password authentication, no user maintenance.
|
|
9
|
+
saved cookie name: _token_dev
|
|
10
|
+
*/
|
|
11
|
+
|
|
12
|
+
// DEFAULT_ADMIN_PASS is DEFAULT_ADMIN_NAME + ':' + login password hash.
|
|
13
|
+
// Use below command to generate hash:
|
|
14
|
+
// node -e "console.log(require('crypto').createHash('md5').update('admin:F4AZ5O@2fPUjw%f$LmhZpJTQ^DoXnWPkH#hqE', 'utf8').digest('hex'))"
|
|
15
|
+
export type DevAdminSessionProps = {
|
|
16
|
+
u: string; // username
|
|
17
|
+
t: string; // type: admin, user
|
|
18
|
+
ip: string;
|
|
19
|
+
h: string; // md5 of name+pass
|
|
20
|
+
};
|
|
21
|
+
|
|
22
|
+
/*
|
|
23
|
+
dev admin has more permissions than app admin, and the dashboard also supports for app admin only users.
|
|
24
|
+
app admin is supposed to manage the application, not the site, and may have different fields in cookie.
|
|
25
|
+
This is a sample how to set login process for app admin.
|
|
26
|
+
|
|
27
|
+
export const appAdminHookSetCookie: AppAdminHookSetCookieProps = async (
|
|
28
|
+
req: ServerRequest,
|
|
29
|
+
res: ServerResponse,
|
|
30
|
+
username: string
|
|
31
|
+
) => {
|
|
32
|
+
const cryptoKey = process.env['CRYPTO_KEY'];
|
|
33
|
+
const u = process.env['ADMIN_USER'];
|
|
34
|
+
const p = process.env['ADMIN_PASS'];
|
|
35
|
+
if (!cryptoKey || !u || !p) {
|
|
36
|
+
return {};
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
const specialToken = CryptoUtils.hash((u + ':' + p) as string);
|
|
40
|
+
const loginJson: LoginJsonProps = {
|
|
41
|
+
ip: '',
|
|
42
|
+
id: 0,
|
|
43
|
+
u: u,
|
|
44
|
+
t: 'admin',
|
|
45
|
+
h: specialToken,
|
|
46
|
+
};
|
|
47
|
+
|
|
48
|
+
const token = JSON.stringify(loginJson);
|
|
49
|
+
const tokenCookie = CryptoUtils.encrypt(token, cryptoKey);
|
|
50
|
+
const response = {
|
|
51
|
+
status: 'ok',
|
|
52
|
+
message: langHelper.getLang('shared:login_success'),
|
|
53
|
+
result: tokenCookie,
|
|
54
|
+
user: {
|
|
55
|
+
u: loginJson.u,
|
|
56
|
+
t: loginJson.t,
|
|
57
|
+
},
|
|
58
|
+
};
|
|
59
|
+
|
|
60
|
+
// sameSite: 'none' needs secure=true
|
|
61
|
+
req.locals.setCookie('_token', tokenCookie, {
|
|
62
|
+
expireDays: 360,
|
|
63
|
+
path: '/',
|
|
64
|
+
httpOnly: false,
|
|
65
|
+
secure: true,
|
|
66
|
+
sameSite: 'none',
|
|
67
|
+
});
|
|
68
|
+
return response;
|
|
69
|
+
};
|
|
70
|
+
|
|
71
|
+
export const appAdminHookCheckLogin: AppAdminHookCheckLoginProps = async (
|
|
72
|
+
req: ServerRequest,
|
|
73
|
+
res: ServerResponse,
|
|
74
|
+
username: string,
|
|
75
|
+
password: string
|
|
76
|
+
) => {
|
|
77
|
+
if (process.env['ADMIN_PASS'] && username === process.env['ADMIN_USER'] && password === process.env['ADMIN_PASS']) {
|
|
78
|
+
const appAdminResponse = await appAdminHookSetCookie(req, res, username);
|
|
79
|
+
ApiHelper.sendJson(req, res, appAdminResponse);
|
|
80
|
+
return true;
|
|
81
|
+
}
|
|
82
|
+
return false;
|
|
83
|
+
};
|
|
84
|
+
|
|
85
|
+
adminHelper.setAppAdminHookSetCookie(appAdminHookSetCookie);
|
|
86
|
+
adminHelper.setAppAdminHookCheckLogin(appAdminHookCheckLogin);
|
|
87
|
+
*/
|
|
88
|
+
export type AppAdminHookSetCookieProps = (req: ServerRequest, res: ServerResponse, username: string) => Promise<any>;
|
|
89
|
+
export type AppAdminHookCheckLoginProps = (req: ServerRequest, res: ServerResponse, username: string, password: string) => Promise<boolean>;
|
|
90
|
+
export type AppAdminHookLogoutProps = (req: ServerRequest, res: ServerResponse) => Promise<void>;
|
|
91
|
+
|
|
92
|
+
export const DEV_ADMIN_TYPE = 'dev-admin';
|
|
93
|
+
export const DEV_ADMIN_CRYPTO_KEY_NAME = 'DEV_CRYPTO_KEY';
|
|
94
|
+
export const DEV_ADMIN_SESSION_NAME = '_token_dev';
|
|
95
|
+
export class AdminApiHelper {
|
|
96
|
+
private static instance: AdminApiHelper;
|
|
97
|
+
private logger = new Logger('admin-api');
|
|
98
|
+
|
|
99
|
+
private constructor() {}
|
|
100
|
+
|
|
101
|
+
public static getInstance(): AdminApiHelper {
|
|
102
|
+
if (!AdminApiHelper.instance) {
|
|
103
|
+
AdminApiHelper.instance = new AdminApiHelper();
|
|
104
|
+
}
|
|
105
|
+
return AdminApiHelper.instance;
|
|
106
|
+
}
|
|
107
|
+
|
|
108
|
+
private AppAdminHookSetCookie?: AppAdminHookSetCookieProps;
|
|
109
|
+
setAppAdminHookSetCookie(hook: AppAdminHookSetCookieProps) {
|
|
110
|
+
this.AppAdminHookSetCookie = hook;
|
|
111
|
+
}
|
|
112
|
+
getAppAdminHookSetCookie() {
|
|
113
|
+
return this.AppAdminHookSetCookie;
|
|
114
|
+
}
|
|
115
|
+
|
|
116
|
+
private AppAdminHookCheckLogin?: AppAdminHookCheckLoginProps;
|
|
117
|
+
setAppAdminHookCheckLogin(hook: AppAdminHookCheckLoginProps) {
|
|
118
|
+
this.AppAdminHookCheckLogin = hook;
|
|
119
|
+
}
|
|
120
|
+
getAppAdminHookCheckLogin() {
|
|
121
|
+
return this.AppAdminHookCheckLogin;
|
|
122
|
+
}
|
|
123
|
+
|
|
124
|
+
private AppAdminHookLogout?: AppAdminHookLogoutProps;
|
|
125
|
+
setAppAdminHookLogout(hook: AppAdminHookLogoutProps) {
|
|
126
|
+
this.AppAdminHookLogout = hook;
|
|
127
|
+
}
|
|
128
|
+
getAppAdminHookLogout() {
|
|
129
|
+
return this.AppAdminHookLogout;
|
|
130
|
+
}
|
|
131
|
+
|
|
132
|
+
decryptJson(text: string) {
|
|
133
|
+
const cryptoKey = process.env[DEV_ADMIN_CRYPTO_KEY_NAME];
|
|
134
|
+
if (cryptoKey && text) {
|
|
135
|
+
try {
|
|
136
|
+
const deCrypto = CryptoUtils.decrypt(text, cryptoKey);
|
|
137
|
+
const json = JSON.parse(deCrypto);
|
|
138
|
+
return json;
|
|
139
|
+
} catch (error: any) {
|
|
140
|
+
this.logger.error(error.message);
|
|
141
|
+
}
|
|
142
|
+
}
|
|
143
|
+
return false;
|
|
144
|
+
}
|
|
145
|
+
|
|
146
|
+
encryptJson(jsonOrText: string | object) {
|
|
147
|
+
const cryptoKey = process.env[DEV_ADMIN_CRYPTO_KEY_NAME];
|
|
148
|
+
if (cryptoKey && jsonOrText) {
|
|
149
|
+
try {
|
|
150
|
+
const text = typeof jsonOrText === 'string' ? jsonOrText : JSON.stringify(jsonOrText);
|
|
151
|
+
const encryptText = CryptoUtils.encrypt(text, cryptoKey);
|
|
152
|
+
return encryptText;
|
|
153
|
+
} catch (error: any) {
|
|
154
|
+
this.logger.error(error.message);
|
|
155
|
+
}
|
|
156
|
+
}
|
|
157
|
+
return false;
|
|
158
|
+
}
|
|
159
|
+
|
|
160
|
+
async getDevAdminFromCookie(
|
|
161
|
+
req: ServerRequest,
|
|
162
|
+
res: ServerResponse,
|
|
163
|
+
sendResponseWhenError = true
|
|
164
|
+
): Promise<DevAdminSessionProps | false> {
|
|
165
|
+
try {
|
|
166
|
+
const cookies = req.locals.cookies();
|
|
167
|
+
const token = cookies.get(DEV_ADMIN_SESSION_NAME, '');
|
|
168
|
+
if (token) {
|
|
169
|
+
const json = this.decryptJson(token) as DevAdminSessionProps;
|
|
170
|
+
if (!json || json.t !== DEV_ADMIN_TYPE) {
|
|
171
|
+
if (sendResponseWhenError) {
|
|
172
|
+
const response = {
|
|
173
|
+
status: 'error',
|
|
174
|
+
message: 'Wrong session data, contact site admin please.',
|
|
175
|
+
};
|
|
176
|
+
ApiHelper.sendJson(req, res, response);
|
|
177
|
+
}
|
|
178
|
+
return false;
|
|
179
|
+
}
|
|
180
|
+
|
|
181
|
+
// if it's special admin
|
|
182
|
+
if (json.h && json.u === process.env['DEV_ADMIN_USER']) {
|
|
183
|
+
const hash = CryptoUtils.hash(process.env['DEV_ADMIN_USER'] + ':' + process.env['DEV_ADMIN_PASS']);
|
|
184
|
+
if (json.h === hash) {
|
|
185
|
+
return json;
|
|
186
|
+
}
|
|
187
|
+
}
|
|
188
|
+
return false;
|
|
189
|
+
}
|
|
190
|
+
} catch (error: any) {
|
|
191
|
+
this.logger.error(error.message);
|
|
192
|
+
}
|
|
193
|
+
if (sendResponseWhenError) {
|
|
194
|
+
const response = {
|
|
195
|
+
status: 'error',
|
|
196
|
+
message: 'Please login to use this system.',
|
|
197
|
+
};
|
|
198
|
+
ApiHelper.sendJson(req, res, response);
|
|
199
|
+
}
|
|
200
|
+
return false;
|
|
201
|
+
}
|
|
202
|
+
}
|
|
203
|
+
|
|
204
|
+
// add comment for tree shaking
|
|
205
|
+
export const adminApiHelper = /* @__PURE__ */ AdminApiHelper.getInstance();
|
|
@@ -2,7 +2,7 @@ import { ServerResponse } from 'http';
|
|
|
2
2
|
// import { AdminUser } from './admin-user';
|
|
3
3
|
import { AdminDb } from './admin-db';
|
|
4
4
|
import { AdminMenu } from './admin-menu';
|
|
5
|
-
import { devAdminAuth, needDevAdminSession } from './admin-auth';
|
|
5
|
+
import { devAdminAuth, devAdminLogout, needDevAdminSession } from './admin-auth';
|
|
6
6
|
import { AdminPerformance } from './admin-performance';
|
|
7
7
|
import { AdminRelease } from './admin-release';
|
|
8
8
|
import { AdminResources } from './admin-resources';
|
|
@@ -10,7 +10,7 @@ import { AdminTokens } from './admin-tokens';
|
|
|
10
10
|
import { AdminConfig } from './admin-config';
|
|
11
11
|
import { Logger } from '../lib';
|
|
12
12
|
import { IApiBase, ServerRequest } from '../models';
|
|
13
|
-
import {ApiRouter } from '../api';
|
|
13
|
+
import { ApiRouter } from '../api';
|
|
14
14
|
|
|
15
15
|
const logger = new Logger('admin-api');
|
|
16
16
|
|
|
@@ -55,5 +55,8 @@ export class AdminApi implements IApiBase {
|
|
|
55
55
|
this.router.use('/auth', async (req: ServerRequest, res: ServerResponse) => {
|
|
56
56
|
return devAdminAuth(req, res);
|
|
57
57
|
});
|
|
58
|
+
this.router.use('/logout', async (req: ServerRequest, res: ServerResponse) => {
|
|
59
|
+
return devAdminLogout(req, res);
|
|
60
|
+
});
|
|
58
61
|
}
|
|
59
62
|
}
|
|
@@ -1,12 +1,13 @@
|
|
|
1
1
|
import { ServerResponse } from 'http';
|
|
2
2
|
import { Logger, ServerRequest, ApiHelper } from 'lupine.api';
|
|
3
3
|
import { CryptoUtils } from '../lib/utils/crypto';
|
|
4
|
-
import {
|
|
4
|
+
import { adminApiHelper, DEV_ADMIN_CRYPTO_KEY_NAME, DEV_ADMIN_TYPE, DevAdminSessionProps } from './admin-api-helper';
|
|
5
5
|
import { langHelper } from '../lang';
|
|
6
6
|
|
|
7
7
|
const logger = new Logger('admin-auth');
|
|
8
|
+
|
|
8
9
|
export const needDevAdminSession = async (req: ServerRequest, res: ServerResponse) => {
|
|
9
|
-
const devAdminSession = await
|
|
10
|
+
const devAdminSession = await adminApiHelper.getDevAdminFromCookie(req, res, true);
|
|
10
11
|
if (!devAdminSession) {
|
|
11
12
|
// return true to skip the rest of the middleware
|
|
12
13
|
return true;
|
|
@@ -18,8 +19,8 @@ export const needDevAdminSession = async (req: ServerRequest, res: ServerRespons
|
|
|
18
19
|
export const devAdminAuth = async (req: ServerRequest, res: ServerResponse) => {
|
|
19
20
|
const cryptoKey = process.env[DEV_ADMIN_CRYPTO_KEY_NAME];
|
|
20
21
|
if (!cryptoKey) {
|
|
21
|
-
const msg = langHelper.getLang('shared:
|
|
22
|
-
|
|
22
|
+
const msg = langHelper.getLang('shared:name_not_set', {
|
|
23
|
+
name: 'ENV ' + DEV_ADMIN_CRYPTO_KEY_NAME,
|
|
23
24
|
});
|
|
24
25
|
logger.error(msg);
|
|
25
26
|
const response = {
|
|
@@ -31,7 +32,7 @@ export const devAdminAuth = async (req: ServerRequest, res: ServerResponse) => {
|
|
|
31
32
|
}
|
|
32
33
|
if (!process.env['DEV_ADMIN_PASS']) {
|
|
33
34
|
const msg = langHelper.getLang('shared:name_not_set', {
|
|
34
|
-
name: 'DEV_ADMIN_PASS',
|
|
35
|
+
name: 'ENV DEV_ADMIN_PASS',
|
|
35
36
|
});
|
|
36
37
|
logger.error(msg);
|
|
37
38
|
const response = {
|
|
@@ -46,14 +47,34 @@ export const devAdminAuth = async (req: ServerRequest, res: ServerResponse) => {
|
|
|
46
47
|
const data = req.locals.json();
|
|
47
48
|
if (!data || Array.isArray(data) || !data.u || !data.p) {
|
|
48
49
|
// if session already exists, use session data login
|
|
49
|
-
const devAdminSession = await
|
|
50
|
+
const devAdminSession = await adminApiHelper.getDevAdminFromCookie(req, res, false);
|
|
50
51
|
if (!devAdminSession) {
|
|
52
|
+
// check is app admin
|
|
53
|
+
const appAdminHookCheckLogin = adminApiHelper.getAppAdminHookCheckLogin();
|
|
54
|
+
if (appAdminHookCheckLogin) {
|
|
55
|
+
if (await appAdminHookCheckLogin(req, res, '', '')) {
|
|
56
|
+
return true;
|
|
57
|
+
}
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
const response = {
|
|
61
|
+
status: 'error',
|
|
62
|
+
message: 'Please login to use this system.',
|
|
63
|
+
};
|
|
64
|
+
ApiHelper.sendJson(req, res, response);
|
|
51
65
|
return true;
|
|
52
66
|
}
|
|
67
|
+
// if it's dev admin, then set app admin cookie as well
|
|
68
|
+
let addLoginResponse = {};
|
|
69
|
+
const appAdminHookSetCookie = adminApiHelper.getAppAdminHookSetCookie();
|
|
70
|
+
if (appAdminHookSetCookie) {
|
|
71
|
+
addLoginResponse = await appAdminHookSetCookie(req, res, devAdminSession.u);
|
|
72
|
+
}
|
|
53
73
|
const response = {
|
|
74
|
+
...addLoginResponse,
|
|
54
75
|
status: 'ok',
|
|
55
76
|
message: langHelper.getLang('shared:login_success'),
|
|
56
|
-
|
|
77
|
+
devLogin: CryptoUtils.encrypt(JSON.stringify(devAdminSession), cryptoKey),
|
|
57
78
|
};
|
|
58
79
|
ApiHelper.sendJson(req, res, response);
|
|
59
80
|
return true;
|
|
@@ -68,15 +89,40 @@ export const devAdminAuth = async (req: ServerRequest, res: ServerResponse) => {
|
|
|
68
89
|
h: CryptoUtils.hash(data.u + ':' + data.p),
|
|
69
90
|
};
|
|
70
91
|
const token = JSON.stringify(devSession);
|
|
92
|
+
const tokenCookie = CryptoUtils.encrypt(token, cryptoKey);
|
|
93
|
+
|
|
94
|
+
// if it's dev admin, then set app admin cookie as well
|
|
95
|
+
let addLoginResponse = {};
|
|
96
|
+
const appAdminHookSetCookie = adminApiHelper.getAppAdminHookSetCookie();
|
|
97
|
+
if (appAdminHookSetCookie) {
|
|
98
|
+
addLoginResponse = await appAdminHookSetCookie(req, res, data.u);
|
|
99
|
+
}
|
|
100
|
+
|
|
71
101
|
const response = {
|
|
102
|
+
...addLoginResponse,
|
|
72
103
|
status: 'ok',
|
|
73
104
|
message: langHelper.getLang('shared:login_success'),
|
|
74
|
-
|
|
105
|
+
devLogin: tokenCookie,
|
|
75
106
|
};
|
|
107
|
+
req.locals.setCookie('_token', tokenCookie, {
|
|
108
|
+
expireDays: 360,
|
|
109
|
+
path: '/',
|
|
110
|
+
httpOnly: false,
|
|
111
|
+
secure: true,
|
|
112
|
+
sameSite: 'none',
|
|
113
|
+
});
|
|
76
114
|
ApiHelper.sendJson(req, res, response);
|
|
77
115
|
return true;
|
|
78
116
|
}
|
|
79
117
|
|
|
118
|
+
// check is app admin
|
|
119
|
+
const appAdminHookCheckLogin = adminApiHelper.getAppAdminHookCheckLogin();
|
|
120
|
+
if (appAdminHookCheckLogin) {
|
|
121
|
+
if (await appAdminHookCheckLogin(req, res, data.u as string, data.p as string)) {
|
|
122
|
+
return true;
|
|
123
|
+
}
|
|
124
|
+
}
|
|
125
|
+
|
|
80
126
|
logger.info(`dev admin login failed: ${((data.u as string) || '').substring(0, 30)}`);
|
|
81
127
|
const response = {
|
|
82
128
|
status: 'error',
|
|
@@ -85,3 +131,10 @@ export const devAdminAuth = async (req: ServerRequest, res: ServerResponse) => {
|
|
|
85
131
|
ApiHelper.sendJson(req, res, response);
|
|
86
132
|
return true;
|
|
87
133
|
};
|
|
134
|
+
|
|
135
|
+
export const devAdminLogout = async (req: ServerRequest, res: ServerResponse) => {
|
|
136
|
+
req.locals.setCookie('_token_dev', '', { expireDays: 360, path: '/', httpOnly: false, secure: true, sameSite: 'none' });
|
|
137
|
+
await adminApiHelper.getAppAdminHookLogout()?.(req, res);
|
|
138
|
+
ApiHelper.sendJson(req, res, { status: 'ok', message: langHelper.getLang('shared:process_completed') });
|
|
139
|
+
return true;
|
|
140
|
+
};
|
|
@@ -1,18 +1,7 @@
|
|
|
1
1
|
import { ServerResponse } from 'http';
|
|
2
2
|
import * as fs from 'fs/promises';
|
|
3
|
-
import {
|
|
4
|
-
IApiBase,
|
|
5
|
-
Logger,
|
|
6
|
-
apiCache,
|
|
7
|
-
ServerRequest,
|
|
8
|
-
ApiRouter,
|
|
9
|
-
ApiHelper,
|
|
10
|
-
langHelper,
|
|
11
|
-
FsUtils,
|
|
12
|
-
adminHelper,
|
|
13
|
-
} from 'lupine.api';
|
|
3
|
+
import { IApiBase, Logger, apiCache, ServerRequest, ApiRouter, ApiHelper, langHelper, FsUtils } from 'lupine.api';
|
|
14
4
|
import path from 'path';
|
|
15
|
-
import { needDevAdminSession } from './admin-auth';
|
|
16
5
|
|
|
17
6
|
export class AdminConfig implements IApiBase {
|
|
18
7
|
private logger = new Logger('config-api');
|
|
@@ -16,7 +16,7 @@ import {
|
|
|
16
16
|
AppCacheGlobal,
|
|
17
17
|
getAppCache,
|
|
18
18
|
} from 'lupine.api';
|
|
19
|
-
import {
|
|
19
|
+
import { adminApiHelper } from './admin-api-helper';
|
|
20
20
|
import { needDevAdminSession } from './admin-auth';
|
|
21
21
|
|
|
22
22
|
// #https://github.com/sebhildebrandt/systeminformation
|
|
@@ -38,7 +38,7 @@ export class AdminPerformance implements IApiBase {
|
|
|
38
38
|
}
|
|
39
39
|
|
|
40
40
|
async performanceData(req: ServerRequest, res: ServerResponse) {
|
|
41
|
-
const json =
|
|
41
|
+
const json = adminApiHelper.getDevAdminFromCookie(req, res, true);
|
|
42
42
|
if (!json) {
|
|
43
43
|
return false;
|
|
44
44
|
}
|