bump version

This commit is contained in:
undefined committed 2024-08-10 23:18:10 +08:00
1 parent 21316fafaf
commit 1789e524fc
8 files changed
+82 -59

No files matched your search

+12
View File
@@ -111,6 +111,18 @@ Hydro 用户群:1085853538
<details>
<summary><h2>更新日志(点击展开)</h2></summary>
### Hydro 4.14.0 / UI 4.53.0
- core: 修复能够越权查看隐藏题目的问题 [security]
- ui: 优化提交记录详情富文本展示
- ui: 支持头像缓存
- ui: 禁止文本越界显示
- vjudge: codeforces: 优化提交 ID 获取
- ui: 默认禁用 sentry
- core: 支持隐藏训练左侧用户栏
- core: cli: 支持 eval
- ui: 添加实验性 speculation rules 支持
- core: 修复训练参加人数计数
### Hydro 4.13.4 / UI 4.52.3
- framework: 修复 404 返回页
- ui: 优化用户权限页布局
+1 -1
View File
@@ -1,6 +1,6 @@
{
"name": "@hydrooj/elastic-search",
"version": "1.1.5",
"version": "1.1.6",
"main": "index.ts",
"repository": "https://github.com/hydro-dev/Hydro",
"author": "undefined <i@undefined.moe>",
+1 -1
View File
@@ -1,6 +1,6 @@
{
"name": "hydrooj",
"version": "4.13.4",
"version": "4.14.0",
"bin": "bin/hydrooj.js",
"main": "src/plugin-api",
"module": "src/plugin-api",
+7 -3
View File
@@ -31,9 +31,13 @@ window.UiContext = JSON.parse(window.UiContext);
window.UserContext = JSON.parse(window.UserContext);
try { __webpack_public_path__ = UiContext.cdn_prefix; } catch (e) { }
if ('serviceWorker' in navigator) {
const encodedConfig = encodeURIComponent(JSON.stringify(UiContext.SWConfig));
navigator.serviceWorker.register(`/service-worker.js?config=${encodedConfig}`).then((registration) => {
navigator.serviceWorker.register('/service-worker.js').then((registration) => {
console.log('SW registered: ', registration);
fetch('/service-worker-config', {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify(UiContext.SWConfig),
});
}).catch((registrationError) => {
console.log('SW registration failed: ', registrationError);
});
@@ -48,7 +52,7 @@ if (process.env.NODE_ENV === 'production' && UiContext.sentry_dsn) {
if (!e.isUserFacingError) window._sentryEvents.push(e);
};
const script = document.createElement('script');
script.src = new URL('sentry.js', __webpack_public_path__).href;
script.src = new URL('/sentry.js', __webpack_public_path__).href;
document.body.appendChild(script);
}
+1 -1
View File
@@ -158,8 +158,8 @@ export function apply(ctx: Context) {
`https://${that.request.host}`,
SystemModel.get('server.url'),
SystemModel.get('server.cdn'),
...((SystemModel.get('server.assets') || '').split(',')).filter((i) => i),
],
assets: ((SystemModel.get('ui-default.assets') || '').split(',')).filter((i) => i) || [],
domains: SystemModel.get('ui-default.domains') || [],
};
});
+1 -1
View File
@@ -1,6 +1,6 @@
{
"name": "@hydrooj/ui-default",
"version": "4.52.3",
"version": "4.53.0",
"author": "undefined <i@undefined.moe>",
"license": "AGPL-3.0",
"main": "index.ts",
+58 -51
View File
@@ -114,19 +114,20 @@ interface ServiceWorkerConfig {
hosts: string[];
/** service domains */
domains: string[];
/** assets domains */
assets: string[];
preload?: string;
}
let config: ServiceWorkerConfig = null;
function initConfig() {
config = JSON.parse(new URLSearchParams(location.search).get('config'));
function initConfig(cfg) {
config = cfg;
config.hosts ||= [];
config.domains = Array.from(new Set([location.host, ...(config.domains || [])]));
console.log('Config:', config);
}
self.addEventListener('install', (event) => event.waitUntil((async () => {
initConfig();
if (process.env.NODE_ENV === 'production' && config?.preload) {
const [cache, manifest] = await Promise.all([
caches.open(PRECACHE),
@@ -140,7 +141,6 @@ self.addEventListener('install', (event) => event.waitUntil((async () => {
})()));
self.addEventListener('activate', (event) => {
initConfig();
event.waitUntil(self.clients.claim());
const valid = [PRECACHE];
caches.keys().then((names) => names
@@ -181,23 +181,47 @@ async function get(request: Request) {
function transformUrl(url: string) {
const urlObject = new URL(url);
const path = urlObject.pathname;
if (path.startsWith('/fs/') || path.includes('X-Amz')) urlObject.search = '';
if (path.startsWith('/fs/') || path.toLowerCase().includes('x-amz')) urlObject.search = '';
return urlObject.toString();
}
async function cachedRespond(request: Request) {
async function cached(request: Request, cacheKey: string, fetchFunc: () => Promise<Response>) {
const url = transformUrl(request.url);
const cachedResponse = await caches.match(url);
if (cachedResponse) return cachedResponse;
console.log(`Caching ${url}`);
const urlObject = new URL(url);
const isAsset = config.assets.some((i) => request.url.startsWith(i));
const rewritable = !isAsset && config.domains.length > 1
&& config.domains.includes(urlObject.hostname)
&& urlObject.origin === location.origin;
let targets = [url];
if (rewritable) {
targets = config.domains.map((i) => {
const t = new URL(request.url);
t.host = i;
return transformUrl(t.toString());
});
}
if (!shouldCache(request)) return rewritable ? fetchFunc() : fetch(request);
const results = await Promise.all(targets.map((i) => caches.match(i)));
const found = results.find((i) => i);
if (found) {
console.debug('Serve from cache %s <- %s', request.url, found.url);
return found;
}
const [cache, response] = await Promise.all([
caches.open(PRECACHE),
get(request),
caches.open(cacheKey),
fetchFunc(),
]);
if (response.status === 206) return response; // partial response cannot be cached
if (response.ok) {
console.log(`Cached ${url}`);
cache.put(url, response.clone());
return response;
}
console.log(`Failed to cache ${url}`, response);
// If response fails, re-fetch the original request to prevent
// errors caused by different headers and do not cache them
return fetch(request);
}
@@ -206,6 +230,11 @@ self.addEventListener('fetch', (event: FetchEvent) => {
event.respondWith(new Response('pong'));
return;
}
if (event.request.url.endsWith('/service-worker-config')) {
event.request.json().then((cfg) => initConfig(cfg));
event.respondWith(new Response('ok'));
return;
}
if (map.get(event.request.url)) {
streamsaver(event);
return;
@@ -213,46 +242,24 @@ self.addEventListener('fetch', (event: FetchEvent) => {
if (!['get', 'post', 'head'].includes(event.request.method.toLowerCase())) return;
if (!config) return; // Don't do anything when not initialized
const url = new URL(event.request.url);
const rewritable = config.domains.length > 1
&& config.domains.includes(url.hostname) && url.origin === location.origin;
const isAsset = config.assets.some((i) => event.request.url.startsWith(i));
const rewritable = !isAsset && config.domains.length > 1
&& config.domains.includes(url.hostname)
&& url.origin === location.origin;
// Only handle whitelisted origins;
if (!config.hosts.some((i) => event.request.url.startsWith(i))) return;
if (!isAsset && !config.hosts.some((i) => event.request.url.startsWith(i))) return;
// Do not cache range requests
if (event.request.headers.get('range')?.trim()?.length) return;
if (shouldCache(event.request)) {
event.respondWith((async () => {
if (rewritable) {
const targets = config.domains.map((i) => {
const t = new URL(event.request.url);
t.host = i;
return transformUrl(t.toString());
});
const results = await Promise.all(targets.map((i) => caches.match(i)));
return results.find((i) => i) || cachedRespond(event.request);
}
const transformedUrl = transformUrl(event.request.url);
const cachedResponse = await caches.match(transformedUrl);
if (cachedResponse) return cachedResponse;
console.log(`Caching ${transformedUrl}`);
const [cache, response] = await Promise.all([
caches.open(PRECACHE),
fetch(url, {
method: event.request.method,
headers: event.request.headers,
redirect: event.request.redirect,
keepalive: event.request.keepalive,
referrer: event.request.referrer,
referrerPolicy: event.request.referrerPolicy,
signal: event.request.signal,
}), // Fetch from url to prevent opaque response
]);
if (response.ok) {
cache.put(transformedUrl, response.clone());
return response;
}
console.log(`Failed to cache ${transformedUrl}`, response);
// If response fails, re-fetch the original request to prevent
// errors caused by different headers and do not cache them
return fetch(event.request);
})());
} else if (rewritable) event.respondWith(get(event.request));
event.respondWith((async () => cached(event.request, isAsset ? 'assets' : PRECACHE, () => (rewritable
? get(event.request)
: fetch(url, {
method: event.request.method,
headers: event.request.headers,
redirect: event.request.redirect,
keepalive: event.request.keepalive,
referrer: event.request.referrer,
referrerPolicy: event.request.referrerPolicy,
signal: event.request.signal,
}))))());
});
+1 -1
View File
@@ -1,6 +1,6 @@
{
"name": "@hydrooj/vjudge",
"version": "1.9.9",
"version": "1.9.10",
"description": "Submit problems to remote oj",
"main": "./src/index.ts",
"repository": "https://github.com/hydro-dev/Hydro.git",