Public File Sharing (#72)
* Public File Sharing This implements public file sharing (read-only) with and without passwords (#57). It also fixes a problem with filenames including special characters like `#` not working properly (#71). You can share a directory or a single file, by using the new share icon on the right of the directories/files, and click on it to manage an existing file share (setting a new password, or deleting the file share). There is some other minor cleanup and other copy updates in the README. Closes #57 Fixes #71 * Hide UI elements when sharing isn't allowed
This commit is contained in:
38
lib/auth.ts
38
lib/auth.ts
@@ -30,7 +30,7 @@ export const dataToText = (data: Uint8Array) => new TextDecoder().decode(data);
|
||||
export const generateKey = async (key: string): Promise<CryptoKey> =>
|
||||
await crypto.subtle.importKey('raw', textToData(key), { name: 'HMAC', hash: 'SHA-256' }, false, ['sign', 'verify']);
|
||||
|
||||
async function signAuthJwt(key: CryptoKey, data: JwtData): Promise<string> {
|
||||
async function signAuthJwt<T = JwtData>(key: CryptoKey, data: T): Promise<string> {
|
||||
const payload = encodeBase64Url(textToData(JSON.stringify({ alg: 'HS256', typ: 'JWT' }))) + '.' +
|
||||
encodeBase64Url(textToData(JSON.stringify(data) || ''));
|
||||
const signature = encodeBase64Url(
|
||||
@@ -39,7 +39,7 @@ async function signAuthJwt(key: CryptoKey, data: JwtData): Promise<string> {
|
||||
return `${payload}.${signature}`;
|
||||
}
|
||||
|
||||
export async function verifyAuthJwt(key: CryptoKey, jwt: string): Promise<JwtData> {
|
||||
export async function verifyAuthJwt<T = JwtData>(key: CryptoKey, jwt: string): Promise<T> {
|
||||
const jwtParts = jwt.split('.');
|
||||
if (jwtParts.length !== 3) {
|
||||
throw new Error('Malformed JWT');
|
||||
@@ -47,7 +47,7 @@ export async function verifyAuthJwt(key: CryptoKey, jwt: string): Promise<JwtDat
|
||||
|
||||
const data = textToData(jwtParts[0] + '.' + jwtParts[1]);
|
||||
if (await crypto.subtle.verify({ name: 'HMAC' }, key, decodeBase64Url(jwtParts[2]), data) === true) {
|
||||
return JSON.parse(dataToText(decodeBase64Url(jwtParts[1]))) as JwtData;
|
||||
return JSON.parse(dataToText(decodeBase64Url(jwtParts[1]))) as T;
|
||||
}
|
||||
|
||||
throw new Error('Invalid JWT');
|
||||
@@ -145,10 +145,10 @@ async function getDataFromCookie(
|
||||
return null;
|
||||
}
|
||||
|
||||
export async function generateToken(tokenData: JwtData['data']): Promise<string> {
|
||||
export async function generateToken<T = JwtData>(tokenData: T): Promise<string> {
|
||||
const key = await generateKey(JWT_SECRET);
|
||||
|
||||
const token = await signAuthJwt(key, { data: tokenData });
|
||||
const token = await signAuthJwt<{ data: T }>(key, { data: tokenData });
|
||||
|
||||
return token;
|
||||
}
|
||||
@@ -243,31 +243,3 @@ export async function createSessionCookie(
|
||||
|
||||
return response;
|
||||
}
|
||||
|
||||
export async function updateSessionCookie(
|
||||
response: Response,
|
||||
request: Request,
|
||||
userSession: UserSession,
|
||||
newSessionData: JwtData['data'],
|
||||
) {
|
||||
const token = await generateToken(newSessionData);
|
||||
|
||||
const cookie: Cookie = {
|
||||
name: COOKIE_NAME,
|
||||
value: token,
|
||||
expires: userSession.expires_at,
|
||||
path: '/',
|
||||
secure: isRunningLocally(request) ? false : true,
|
||||
httpOnly: true,
|
||||
sameSite: 'Lax',
|
||||
domain: await resolveCookieDomain(request),
|
||||
};
|
||||
|
||||
if (await AppConfig.isCookieDomainSecurityDisabled()) {
|
||||
delete cookie.domain;
|
||||
}
|
||||
|
||||
setCookie(response.headers, cookie);
|
||||
|
||||
return response;
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user