mirror of
https://github.com/KuekHaoYang/KVideo.git
synced 2026-08-12 23:33:43 +08:00
merge issue 204 auth sync fix
This commit is contained in:
@@ -1,5 +1,12 @@
|
||||
# Changelog
|
||||
|
||||
## 4.9.8 - 2026-07-09
|
||||
|
||||
- 修复登录完成跳转后 Network 面板出现 `/api/user/config` 和 `/api/user/sync` 两个 400 请求的问题。
|
||||
- `AutoSync` 改为在 `PasswordGate` 确认服务端 session 并放行页面内容后再挂载,避免本地旧 session 早于服务端 cookie 校验触发云同步。
|
||||
- 用户配置和云同步 API 在未认证时返回 `401 Authentication required`,不再使用 `400 Missing profileId` 表达会话缺失。
|
||||
- 新增未认证响应回归测试,锁定受保护同步接口的状态码语义。
|
||||
|
||||
## 4.9.7 - 2026-07-09
|
||||
|
||||
- 修复 Android TV / 小米电视旧 WebView 83 打开站点后白屏的问题。
|
||||
|
||||
+11
-1
@@ -4,8 +4,18 @@
|
||||
"name": "KVideo",
|
||||
"branch": "main"
|
||||
},
|
||||
"currentVersion": "4.9.7",
|
||||
"currentVersion": "4.9.8",
|
||||
"releases": [
|
||||
{
|
||||
"version": "4.9.8",
|
||||
"publishedAt": "2026-07-09",
|
||||
"title": "修复登录后同步接口 400",
|
||||
"notes": [
|
||||
"自动同步组件现在只会在访问密码 gate 确认服务端会话并完成本地 session 镜像后挂载,避免登录跳转阶段提前请求 /api/user/config 与 /api/user/sync。",
|
||||
"用户配置和云同步 API 在没有有效服务端 session 时改为返回 401 Authentication required,不再把未认证状态伪装成 Missing profileId 的 400。",
|
||||
"新增未认证响应回归测试,防止受保护同步接口的状态码语义再次退化。"
|
||||
]
|
||||
},
|
||||
{
|
||||
"version": "4.9.7",
|
||||
"publishedAt": "2026-07-09",
|
||||
|
||||
@@ -7,6 +7,7 @@
|
||||
|
||||
import { Redis } from '@upstash/redis';
|
||||
import { NextRequest, NextResponse } from 'next/server';
|
||||
import { authenticationRequiredResponse } from '@/lib/server/api-responses';
|
||||
import { getServerSession } from '@/lib/server/auth';
|
||||
|
||||
export const runtime = 'edge';
|
||||
@@ -23,7 +24,7 @@ export async function GET(request: NextRequest) {
|
||||
const profileId = session?.profileId;
|
||||
|
||||
if (!profileId) {
|
||||
return NextResponse.json({ error: 'Missing profileId' }, { status: 400 });
|
||||
return authenticationRequiredResponse();
|
||||
}
|
||||
|
||||
try {
|
||||
@@ -43,7 +44,7 @@ export async function POST(request: NextRequest) {
|
||||
const profileId = session?.profileId;
|
||||
|
||||
if (!profileId) {
|
||||
return NextResponse.json({ error: 'Missing profileId' }, { status: 400 });
|
||||
return authenticationRequiredResponse();
|
||||
}
|
||||
|
||||
try {
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
import { Redis } from '@upstash/redis';
|
||||
import { NextRequest, NextResponse } from 'next/server';
|
||||
import { authenticationRequiredResponse } from '@/lib/server/api-responses';
|
||||
import { getServerSession } from '@/lib/server/auth';
|
||||
|
||||
// 确保这行代码在整个文件中只出现一次
|
||||
@@ -12,7 +13,7 @@ export async function GET(request: NextRequest) {
|
||||
const profileId = session?.profileId;
|
||||
|
||||
if (!profileId) {
|
||||
return NextResponse.json({ error: 'Missing profileId' }, { status: 400 });
|
||||
return authenticationRequiredResponse();
|
||||
}
|
||||
|
||||
try {
|
||||
@@ -32,7 +33,7 @@ export async function POST(request: NextRequest) {
|
||||
const profileId = session?.profileId;
|
||||
|
||||
if (!profileId) {
|
||||
return NextResponse.json({ error: 'Missing profileId' }, { status: 400 });
|
||||
return authenticationRequiredResponse();
|
||||
}
|
||||
|
||||
try {
|
||||
|
||||
+1
-2
@@ -116,8 +116,6 @@ export default async function RootLayout({
|
||||
scriptUrl={videoTogetherScriptUrl}
|
||||
settingUrl={videoTogetherSettingUrl}
|
||||
/>
|
||||
{/* 加入自动同步组件,它会在后台默默工作,我们放在 ThemeProvider 内部的最前面 */}
|
||||
<AutoSync />
|
||||
<LocaleProvider />
|
||||
|
||||
<TVProvider>
|
||||
@@ -132,6 +130,7 @@ export default async function RootLayout({
|
||||
process.env.UPSTASH_REDIS_REST_TOKEN
|
||||
)
|
||||
)}>
|
||||
<AutoSync />
|
||||
<AdKeywordsWrapper />
|
||||
{children}
|
||||
<BackToTop />
|
||||
|
||||
@@ -8,10 +8,10 @@ import { useConfigSync } from '@/lib/hooks/useConfigSync';
|
||||
import { getSession } from '@/lib/store/auth-store';
|
||||
|
||||
// 防抖函数,防止频繁请求
|
||||
function debounce(fn: Function, delay: number) {
|
||||
let timeoutId: NodeJS.Timeout;
|
||||
return (...args: any[]) => {
|
||||
clearTimeout(timeoutId);
|
||||
function debounce<Args extends unknown[]>(fn: (...args: Args) => void, delay: number) {
|
||||
let timeoutId: ReturnType<typeof setTimeout> | undefined;
|
||||
return (...args: Args) => {
|
||||
if (timeoutId) clearTimeout(timeoutId);
|
||||
timeoutId = setTimeout(() => fn(...args), delay);
|
||||
};
|
||||
}
|
||||
|
||||
@@ -0,0 +1,5 @@
|
||||
import { NextResponse } from 'next/server';
|
||||
|
||||
export function authenticationRequiredResponse(): NextResponse {
|
||||
return NextResponse.json({ error: 'Authentication required' }, { status: 401 });
|
||||
}
|
||||
Generated
+2
-2
@@ -1,12 +1,12 @@
|
||||
{
|
||||
"name": "kvideo",
|
||||
"version": "4.9.7",
|
||||
"version": "4.9.8",
|
||||
"lockfileVersion": 2,
|
||||
"requires": true,
|
||||
"packages": {
|
||||
"": {
|
||||
"name": "kvideo",
|
||||
"version": "4.9.7",
|
||||
"version": "4.9.8",
|
||||
"dependencies": {
|
||||
"@dnd-kit/core": "^6.3.1",
|
||||
"@dnd-kit/sortable": "^10.0.0",
|
||||
|
||||
+1
-1
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "kvideo",
|
||||
"version": "4.9.7",
|
||||
"version": "4.9.8",
|
||||
"private": true,
|
||||
"scripts": {
|
||||
"dev": "node scripts/next-with-lan-access.mjs dev",
|
||||
|
||||
@@ -0,0 +1,12 @@
|
||||
import test from 'node:test';
|
||||
import assert from 'node:assert/strict';
|
||||
|
||||
import { authenticationRequiredResponse } from '@/lib/server/api-responses';
|
||||
|
||||
test('authenticationRequiredResponse returns a 401 JSON response', async () => {
|
||||
const response = authenticationRequiredResponse();
|
||||
|
||||
assert.equal(response.status, 401);
|
||||
assert.equal(response.headers.get('content-type')?.includes('application/json'), true);
|
||||
assert.deepEqual(await response.json(), { error: 'Authentication required' });
|
||||
});
|
||||
Reference in New Issue
Block a user