first commit
This commit is contained in:
commit
a74fe7a388
42 files changed
+6058
No files matched your search
@@ -0,0 +1,20 @@
|
||||
const HANGUL_RE = /[\u1100-\u11FF\u3130-\u318F\uAC00-\uD7A3]/;
|
||||
|
||||
/**
|
||||
* Multer/busboy often decodes multipart filenames as Latin-1.
|
||||
* UTF-8 Hangul then appears as mojibake (e.g. áá
©…).
|
||||
* Prefer an explicit UTF-8 `filename` form field from the client when present.
|
||||
*/
|
||||
export function decodeUploadFilename(name: string): string {
|
||||
if (!name) return name;
|
||||
if (HANGUL_RE.test(name)) return name;
|
||||
|
||||
try {
|
||||
const decoded = Buffer.from(name, 'latin1').toString('utf8');
|
||||
if (decoded.includes('\uFFFD')) return name;
|
||||
if (HANGUL_RE.test(decoded)) return decoded;
|
||||
return name;
|
||||
} catch {
|
||||
return name;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,83 @@
|
||||
import type { DocumentType } from '../types/session.js';
|
||||
|
||||
const WORD = new Set([
|
||||
'doc',
|
||||
'docm',
|
||||
'docx',
|
||||
'dot',
|
||||
'dotm',
|
||||
'dotx',
|
||||
'epub',
|
||||
'fodt',
|
||||
'htm',
|
||||
'html',
|
||||
'odt',
|
||||
'ott',
|
||||
'rtf',
|
||||
'txt',
|
||||
'xml',
|
||||
]);
|
||||
|
||||
const CELL = new Set([
|
||||
'csv',
|
||||
'fods',
|
||||
'ods',
|
||||
'ots',
|
||||
'xls',
|
||||
'xlsb',
|
||||
'xlsm',
|
||||
'xlsx',
|
||||
'xlt',
|
||||
'xltm',
|
||||
'xltx',
|
||||
]);
|
||||
|
||||
const SLIDE = new Set([
|
||||
'fodp',
|
||||
'odp',
|
||||
'otp',
|
||||
'pot',
|
||||
'potm',
|
||||
'potx',
|
||||
'pps',
|
||||
'ppsm',
|
||||
'ppsx',
|
||||
'ppt',
|
||||
'pptm',
|
||||
'pptx',
|
||||
]);
|
||||
|
||||
const PDF = new Set(['pdf', 'djvu', 'xps', 'oxps']);
|
||||
|
||||
export function extensionOf(filename: string): string {
|
||||
const idx = filename.lastIndexOf('.');
|
||||
if (idx < 0) return '';
|
||||
return filename.slice(idx + 1).toLowerCase();
|
||||
}
|
||||
|
||||
export function documentTypeFor(ext: string): DocumentType {
|
||||
if (PDF.has(ext)) return 'pdf';
|
||||
if (CELL.has(ext)) return 'cell';
|
||||
if (SLIDE.has(ext)) return 'slide';
|
||||
if (WORD.has(ext)) return 'word';
|
||||
return 'word';
|
||||
}
|
||||
|
||||
export function mimeFor(ext: string): string {
|
||||
const map: Record<string, string> = {
|
||||
docx: 'application/vnd.openxmlformats-officedocument.wordprocessingml.document',
|
||||
xlsx: 'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet',
|
||||
pptx: 'application/vnd.openxmlformats-officedocument.presentationml.presentation',
|
||||
pdf: 'application/pdf',
|
||||
odt: 'application/vnd.oasis.opendocument.text',
|
||||
ods: 'application/vnd.oasis.opendocument.spreadsheet',
|
||||
odp: 'application/vnd.oasis.opendocument.presentation',
|
||||
doc: 'application/msword',
|
||||
xls: 'application/vnd.ms-excel',
|
||||
ppt: 'application/vnd.ms-powerpoint',
|
||||
rtf: 'application/rtf',
|
||||
txt: 'text/plain',
|
||||
csv: 'text/csv',
|
||||
};
|
||||
return map[ext] ?? 'application/octet-stream';
|
||||
}
|
||||
@@ -0,0 +1,31 @@
|
||||
import jwt from 'jsonwebtoken';
|
||||
import { config } from '../config.js';
|
||||
|
||||
export function signOnlyOfficePayload(payload: Record<string, unknown>): string {
|
||||
return jwt.sign(payload, config.jwtSecret, { algorithm: 'HS256' });
|
||||
}
|
||||
|
||||
export function verifyOnlyOfficeToken(token: string): Record<string, unknown> {
|
||||
return jwt.verify(token, config.jwtSecret, {
|
||||
algorithms: ['HS256'],
|
||||
}) as Record<string, unknown>;
|
||||
}
|
||||
|
||||
/** Extract JWT from Authorization header or body.token (OnlyOffice callback styles). */
|
||||
export function extractToken(req: {
|
||||
headers: { authorization?: string };
|
||||
body?: { token?: string };
|
||||
query?: { token?: string };
|
||||
}): string | null {
|
||||
const auth = req.headers.authorization;
|
||||
if (auth?.startsWith('Bearer ')) {
|
||||
return auth.slice(7);
|
||||
}
|
||||
if (typeof req.body?.token === 'string') {
|
||||
return req.body.token;
|
||||
}
|
||||
if (typeof req.query?.token === 'string') {
|
||||
return req.query.token;
|
||||
}
|
||||
return null;
|
||||
}
|
||||
Reference in new issue
Block a user