-
Notifications
You must be signed in to change notification settings - Fork 0
/
app.js
287 lines (257 loc) · 7.97 KB
/
app.js
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
const express = require('express');
const { Kevast } = require('kevast');
const { KevastFile } = require('kevast-file');
const { KevastGist } = require('kevast-gist');
const { KevastEncrypt } = require('kevast-encrypt');
const he = require('he');
const fs = require('fs');
const path = require('path');
const { promisify } = require('util');
const writeFileAsync = promisify(fs.writeFile);
const bodyParser = require('body-parser');
require('dotenv').config();
const app = express();
const port = process.env.port || 9300;
const requiredEnvVariables = ['token', 'password', 'gistid', 'filename'];
let missingEnvVariables = requiredEnvVariables.filter((variable) => !process.env[variable]);
if (missingEnvVariables.length > 0) {
console.info("无.env环境变量,使用请求参数方式")
}
const keys = {
DOMAIN_LIST_KEY: '__DOMAIN_LIST__'
}
// 本地存储加密ck
const local_store_file = 'domain_gists.json'
/**
* Kevast实例化
* @param {string} token github_gist_token
* @param {string} password 加密密码
* @param {string} gistid gist的id
* @param {string} filename gist文件名
* @returns kevast_store
*/
async function getFreshKevastInstance(token, password, gistid, filename) {
let fileStore = new KevastFile(local_store_file);
let kevast_store = new Kevast(fileStore);
// 检测参数
if (!token || !gistid || !filename) {
console.info('无token, gistid, filename参数,本地调用')
let filePath = path.join(__dirname, local_store_file)
fs.access(filePath, fs.constants.F_OK, (err) => {
if (err) {
console.error(`请求失败,本地文件${local_store_file}不存在`);
}
});
} else {
console.info('有token, gistid, filename参数,gist服务调用')
kevast_store.add(new KevastGist(token, gistid, filename));
}
if (!password) {
console.error('缺少必要的参数: password');
}
kevast_store.use(new KevastEncrypt(password));
return kevast_store;
}
/**
* 路由中间件
*/
app.use(async (req, res, next) => {
try {
let token = req.headers['token'] || process.env.token;
let password = req.headers['password'] || process.env.password;
let gistid = req.headers['gistid'] || process.env.gistid;
let filename = req.headers['filename'] || process.env.filename;
req.kevast_store = await getFreshKevastInstance(token, password, gistid, filename);
next();
} catch (error) {
res.status(500).json({ message: error.message });
}
});
/**
* 获取指定域名的cookie
* @param {string} domain 域名
* @param {object} kevast_store req.kevast_store
* @returns cookie,例如
[
{
"name": "session_id",
"value": "12345",
"path": "/",
"expires": "2024-01-01T00:00:00.000Z",
"secure": true,
"httpOnly": false,
"sameSite": "lax"
},
{
"name": "user_preference",
"value": "dark_mode",
"path": "/",
"expires": "2024-12-31T00:00:00.000Z",
"secure": false,
"httpOnly": true,
"sameSite": "strict"
}
]
*/
async function get_cookie(domain, kevast_store) {
const cookie = await kevast_store.get(domain);
return cookie;
}
/**
* 获取域名列表
* @param {object} kevast_store req.kevast_store
* @returns 当前域名列表
*/
async function get_domain_list(kevast_store) {
const value = await kevast_store.get(keys.DOMAIN_LIST_KEY);
return value;
}
/**
* 设置站点cookie
* @param {list} cookiesList cookie列表
* @param {object} kevast_store req.kevast_store
[
{
domain: "test.com",
cookies: [
{
name: 'session_id',
value: '12345',
path: '/',
},
{
name: 'user_preference',
value: 'dark_mode',
sameSite: 'strict'
}
]
}
]
* @param {list} domainList 域名列表[可选]
* [ 'a.com', 'b.com', 'test.com' ]
* @returns 更新后的域名列表
*/
async function set_cookie(cookiesList, domainList, kevast_store) {
const bulk = [];
let currentDomainList = domainList || (await kevast_store.get(keys.DOMAIN_LIST_KEY)) || [];
newDomainList = JSON.parse(currentDomainList);
for (const { domain, cookies } of cookiesList) {
const isinclude = newDomainList.some(value => value.includes(domain));
if (!isinclude) {
newDomainList.push(domain)
}
bulk.push({ key: domain, value: JSON.stringify(cookies) });
}
// 域名列表更新
bulk.push({ key: keys.DOMAIN_LIST_KEY, value: JSON.stringify(newDomainList) });
await kevast_store.bulkSet(bulk);
return newDomainList
}
/**
* 删除指定域名cookie
* @param {string} domain 删除的域名
* @param {object} kevast_store req.kevast_store
* @param {list} domainList 域名列表[可选]
* @returns 删除后的域名列表
*/
async function remove(domain, kevast_store, domainList) {
let currentDomainList = domainList || (await kevast_store.get(keys.DOMAIN_LIST_KEY)) || [];
// 去除目标域名
const newDomainList = JSON.parse(currentDomainList).filter((d) => d !== domain);
const bulk = [
{ key: keys.DOMAIN_LIST_KEY, value: JSON.stringify(newDomainList) },
{ key: domain, value: undefined },
]
await kevast_store.bulkSet(bulk);
return newDomainList;
}
/**
* 获取所有cookie
* @param {object} kevast_store req.kevast_store
* @returns cookies
*/
async function get_all_cookie(kevast_store) {
let _domain_list = await get_domain_list(kevast_store);
_domain_list = JSON.parse(_domain_list);
const cookie_object = {};
await Promise.all(_domain_list.map(async (domain) => {
const ck = await get_cookie(domain, kevast_store);
cookie_object[domain] = JSON.parse(ck);
}));
// 明文保存ck.json
// await writeFileAsync('ck.json', JSON.stringify(cookie_object, null, 2));
return cookie_object;
}
app.get('/api/get_all_cookie', async (req, res) => {
try {
const result = await get_all_cookie(req.kevast_store);
res.json(result)
} catch (error) {
res.status(500).json({ message: error.message });
}
})
app.get('/api/get_cookie', async (req, res) => {
try {
const domain = req.query.domain;
const value = await get_cookie(domain, req.kevast_store);
const json_data = JSON.parse(he.decode(value));
res.json(json_data);
} catch (error) {
res.status(500).json({ message: error.message });
}
});
app.get('/api/get_domain_list', async (req, res) => {
try {
const value = await get_domain_list(req.kevast_store);
const json_data = JSON.parse(he.decode(value));
res.json(json_data);
} catch (error) {
if (error instanceof TypeError) {
res.status(404).json({ message: "未能获取gists文件" });
} else {
res.status(500).json({ message: error.message });
}
}
});
// http api 接口未测试
app.get('/api/set_cookie/:cookies_list', async (req, res) => {
try {
const value = await set_cookie(req.params.cookies_list, req.kevast_store);
const json_data = JSON.parse(he.decode(value));
res.json(json_data);
} catch (error) {
res.status(500).json({ message: error.message });
}
});
app.get('/api/remove_cookie/:domain', async (req, res) => {
try {
const value = await remove(req.params.domain, req.kevast_store);
res.json(value);
} catch (error) {
res.status(500).json({ message: error.message });
}
});
app.use(bodyParser.json());
app.post('/api/update_gist', (req, res) => {
const { content } = req.body;
if (content) {
const contentString = JSON.stringify(content);
fs.writeFile(local_store_file, contentString, (err) => {
if (err) {
// 发生错误,返回错误响应
console.error('文件保存错误:', err);
res.status(500).send('文件保存错误');
} else {
// 文件保存成功,返回成功响应
console.log('gist保存成功');
res.status(200).send('gist保存成功');
}
});
} else {
// 没有接收到内容,返回错误响应
res.status(400).send('No content received.');
}
});
app.listen(port, () => {
console.log(`Server running at http://localhost:${port}`);
});