1
0
mirror of https://github.com/stonith404/pingvin-share.git synced 2024-11-15 11:50:34 +01:00

fix: share password can be bypassed if a deleted share with the same id was visited before

This commit is contained in:
Elias Schneider 2024-10-23 15:48:47 +02:00
parent 546d2c1ce4
commit acbff6e129
No known key found for this signature in database
GPG Key ID: 07E623B294202B6C
2 changed files with 29 additions and 13 deletions

View File

@ -315,12 +315,22 @@ export class ShareService {
}, },
}); });
if ( if (share?.security?.password) {
share?.security?.password && if (!password) {
!(await argon.verify(share.security.password, password)) throw new ForbiddenException(
) { "This share is password protected",
"share_password_required",
);
}
const isPasswordValid = await argon.verify(
share.security.password,
password,
);
if (!isPasswordValid) {
throw new ForbiddenException("Wrong password", "wrong_password"); throw new ForbiddenException("Wrong password", "wrong_password");
} }
}
if (share.security?.maxViews && share.security.maxViews <= share.views) { if (share.security?.maxViews && share.security.maxViews <= share.views) {
throw new ForbiddenException( throw new ForbiddenException(
@ -335,12 +345,13 @@ export class ShareService {
} }
async generateShareToken(shareId: string) { async generateShareToken(shareId: string) {
const { expiration } = await this.prisma.share.findUnique({ const { expiration, createdAt } = await this.prisma.share.findUnique({
where: { id: shareId }, where: { id: shareId },
}); });
const tokenPayload = { const tokenPayload = {
shareId, shareId,
shareCreatedAt: moment(createdAt).unix(),
iat: moment().unix(), iat: moment().unix(),
}; };
@ -356,7 +367,7 @@ export class ShareService {
} }
async verifyShareToken(shareId: string, token: string) { async verifyShareToken(shareId: string, token: string) {
const { expiration } = await this.prisma.share.findUnique({ const { expiration, createdAt } = await this.prisma.share.findUnique({
where: { id: shareId }, where: { id: shareId },
}); });
@ -367,7 +378,10 @@ export class ShareService {
ignoreExpiration: moment(expiration).isSame(0), ignoreExpiration: moment(expiration).isSame(0),
}); });
return claims.shareId == shareId; return (
claims.shareId == shareId &&
claims.shareCreatedAt == moment(createdAt).unix()
);
} catch { } catch {
return false; return false;
} }

View File

@ -37,8 +37,10 @@ const Share = ({ shareId }: { shareId: string }) => {
modals, modals,
t("share.error.visitor-limit-exceeded.title"), t("share.error.visitor-limit-exceeded.title"),
t("share.error.visitor-limit-exceeded.description"), t("share.error.visitor-limit-exceeded.description"),
"go-home", "go-home"
); );
} else if (error == "share_password_required") {
showEnterPasswordModal(modals, getShareToken);
} else { } else {
toast.axiosError(e); toast.axiosError(e);
} }
@ -59,21 +61,21 @@ const Share = ({ shareId }: { shareId: string }) => {
modals, modals,
t("share.error.removed.title"), t("share.error.removed.title"),
e.response.data.message, e.response.data.message,
"go-home", "go-home"
); );
} else { } else {
showErrorModal( showErrorModal(
modals, modals,
t("share.error.not-found.title"), t("share.error.not-found.title"),
t("share.error.not-found.description"), t("share.error.not-found.description"),
"go-home", "go-home"
); );
} }
} else if (e.response.status == 403 && error == "private_share") { } else if (e.response.status == 403 && error == "private_share") {
showErrorModal( showErrorModal(
modals, modals,
t("share.error.access-denied.title"), t("share.error.access-denied.title"),
t("share.error.access-denied.description"), t("share.error.access-denied.description")
); );
} else if (error == "share_password_required") { } else if (error == "share_password_required") {
showEnterPasswordModal(modals, getShareToken); showEnterPasswordModal(modals, getShareToken);
@ -84,7 +86,7 @@ const Share = ({ shareId }: { shareId: string }) => {
modals, modals,
t("common.error"), t("common.error"),
t("common.error.unknown"), t("common.error.unknown"),
"go-home", "go-home"
); );
} }
}); });