mirror of
https://github.com/xuthus83/pigallery2.git
synced 2025-01-14 14:43:17 +08:00
fixing folder navigation error
This commit is contained in:
parent
06dd15a0ab
commit
6ce8e081ab
@ -4,23 +4,13 @@ import {ObjectManagers} from '../model/ObjectManagers';
|
||||
import {ErrorCodes, ErrorDTO} from '../../common/entities/Error';
|
||||
import {Config} from '../../common/config/private/Config';
|
||||
import {QueryParams} from '../../common/QueryParams';
|
||||
import * as path from 'path';
|
||||
|
||||
const LOG_TAG = '[SharingMWs]';
|
||||
|
||||
export class SharingMWs {
|
||||
|
||||
|
||||
private static generateKey(): string {
|
||||
function s4() {
|
||||
return Math.floor((1 + Math.random()) * 0x10000)
|
||||
.toString(16)
|
||||
.substring(1);
|
||||
}
|
||||
|
||||
return s4() + s4();
|
||||
}
|
||||
|
||||
|
||||
public static async getSharing(req: Request, res: Response, next: NextFunction) {
|
||||
if (Config.Client.Sharing.enabled === false) {
|
||||
return next();
|
||||
@ -59,7 +49,7 @@ export class SharingMWs {
|
||||
}
|
||||
|
||||
|
||||
const directoryName = req.params.directory || '/';
|
||||
const directoryName = path.normalize(req.params.directory || '/');
|
||||
const sharing: SharingDTO = {
|
||||
id: null,
|
||||
sharingKey: sharingKey,
|
||||
@ -90,7 +80,7 @@ export class SharingMWs {
|
||||
return next(new ErrorDTO(ErrorCodes.INPUT_ERROR, 'updateSharing filed is missing'));
|
||||
}
|
||||
const updateSharing: CreateSharingDTO = req.body.updateSharing;
|
||||
const directoryName = req.params.directory || '/';
|
||||
const directoryName = path.normalize(req.params.directory || '/');
|
||||
const sharing: SharingDTO = {
|
||||
id: updateSharing.id,
|
||||
path: directoryName,
|
||||
@ -110,4 +100,14 @@ export class SharingMWs {
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
private static generateKey(): string {
|
||||
function s4() {
|
||||
return Math.floor((1 + Math.random()) * 0x10000)
|
||||
.toString(16)
|
||||
.substring(1);
|
||||
}
|
||||
|
||||
return s4() + s4();
|
||||
}
|
||||
}
|
||||
|
@ -85,7 +85,7 @@ export class ThumbnailGeneratorMWs {
|
||||
}
|
||||
|
||||
// load parameters
|
||||
const mediaPath = path.resolve(ProjectPath.ImageFolder, photo.directory.path, photo.directory.name, photo.name);
|
||||
const mediaPath = path.join(ProjectPath.ImageFolder, photo.directory.path, photo.directory.name, photo.name);
|
||||
const size: number = Config.Client.Thumbnail.personThumbnailSize;
|
||||
const personName = photo.metadata.faces[0].name;
|
||||
// generate thumbnail path
|
||||
|
@ -7,6 +7,7 @@ import {Config} from '../../../common/config/private/Config';
|
||||
import {PasswordHelper} from '../../model/PasswordHelper';
|
||||
import {Utils} from '../../../common/Utils';
|
||||
import {QueryParams} from '../../../common/QueryParams';
|
||||
import * as path from 'path';
|
||||
|
||||
export class AuthenticationMWs {
|
||||
|
||||
@ -54,21 +55,30 @@ export class AuthenticationMWs {
|
||||
return next();
|
||||
}
|
||||
|
||||
public static authoriseDirectory(req: Request, res: Response, next: NextFunction) {
|
||||
if (req.session.user.permissions == null ||
|
||||
req.session.user.permissions.length === 0 ||
|
||||
req.session.user.permissions[0] === '/*') {
|
||||
return next();
|
||||
}
|
||||
|
||||
const directoryName = req.params.directory || '/';
|
||||
if (UserDTO.isPathAvailable(directoryName, req.session.user.permissions) === true) {
|
||||
public static normalizePathParam(paramName: string) {
|
||||
return (req: Request, res: Response, next: NextFunction) => {
|
||||
req.params[paramName] = path.normalize(req.params[paramName] || path.sep).replace(/^(\.\.[\/\\])+/, '');
|
||||
return next();
|
||||
}
|
||||
|
||||
return next(new ErrorDTO(ErrorCodes.PERMISSION_DENIED));
|
||||
};
|
||||
}
|
||||
|
||||
public static authorisePath(paramName: string, isDirectory: boolean) {
|
||||
return (req: Request, res: Response, next: NextFunction) => {
|
||||
let p: string = req.params[paramName];
|
||||
if (!isDirectory) {
|
||||
p = path.dirname(p);
|
||||
}
|
||||
|
||||
if (!UserDTO.isDirectoryPathAvailable(p, req.session.user.permissions, path.sep)) {
|
||||
return res.sendStatus(403);
|
||||
}
|
||||
|
||||
return next();
|
||||
};
|
||||
}
|
||||
|
||||
|
||||
public static authorise(role: UserRoles) {
|
||||
return (req: Request, res: Response, next: NextFunction) => {
|
||||
if (req.session.user.role < role) {
|
||||
@ -102,12 +112,12 @@ export class AuthenticationMWs {
|
||||
return next(new ErrorDTO(ErrorCodes.CREDENTIAL_NOT_FOUND));
|
||||
}
|
||||
|
||||
let path = sharing.path;
|
||||
let sharingPath = sharing.path;
|
||||
if (sharing.includeSubfolders === true) {
|
||||
path += '*';
|
||||
sharingPath += '*';
|
||||
}
|
||||
|
||||
req.session.user = <UserDTO>{name: 'Guest', role: UserRoles.LimitedGuest, permissions: [path]};
|
||||
req.session.user = <UserDTO>{name: 'Guest', role: UserRoles.LimitedGuest, permissions: [sharingPath]};
|
||||
return next();
|
||||
|
||||
} catch (err) {
|
||||
@ -152,6 +162,12 @@ export class AuthenticationMWs {
|
||||
|
||||
}
|
||||
|
||||
public static logout(req: Request, res: Response, next: NextFunction) {
|
||||
delete req.session.user;
|
||||
delete req.session.rememberMe;
|
||||
return next();
|
||||
}
|
||||
|
||||
private static async getSharingUser(req: Request) {
|
||||
if (Config.Client.Sharing.enabled === true &&
|
||||
(!!req.params[QueryParams.gallery.sharingKey_short] || !!req.params[QueryParams.gallery.sharingKey_long])) {
|
||||
@ -166,20 +182,19 @@ export class AuthenticationMWs {
|
||||
return null;
|
||||
}
|
||||
|
||||
let path = sharing.path;
|
||||
let sharingPath = sharing.path;
|
||||
if (sharing.includeSubfolders === true) {
|
||||
path += '*';
|
||||
sharingPath += '*';
|
||||
}
|
||||
return <UserDTO>{name: 'Guest', role: UserRoles.LimitedGuest, permissions: [path]};
|
||||
return <UserDTO>{
|
||||
name: 'Guest',
|
||||
role: UserRoles.LimitedGuest,
|
||||
permissions: [sharingPath],
|
||||
usedSharingKey: sharing.sharingKey
|
||||
};
|
||||
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
public static logout(req: Request, res: Response, next: NextFunction) {
|
||||
delete req.session.user;
|
||||
delete req.session.rememberMe;
|
||||
return next();
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -11,7 +11,7 @@ export class Localizations {
|
||||
public static init() {
|
||||
const notLanguage = ['assets'];
|
||||
const dirCont = fs.readdirSync(ProjectPath.FrontendFolder)
|
||||
.filter(f => fs.statSync(path.resolve(ProjectPath.FrontendFolder, f)).isDirectory());
|
||||
.filter(f => fs.statSync(path.join(ProjectPath.FrontendFolder, f)).isDirectory());
|
||||
Config.Client.languages = dirCont.filter(d => notLanguage.indexOf(d) === -1);
|
||||
Config.Client.languages.push('en');
|
||||
}
|
||||
|
@ -257,7 +257,6 @@ export class SearchManager implements ISearchManager {
|
||||
const rawAndEntities = await query.orderBy('media.id').getRawAndEntities();
|
||||
const media: MediaEntity[] = rawAndEntities.entities;
|
||||
|
||||
// console.log(rawAndEntities.raw);
|
||||
let rawIndex = 0;
|
||||
for (let i = 0; i < media.length; i++) {
|
||||
if (rawAndEntities.raw[rawIndex].faces_id === null ||
|
||||
|
@ -69,7 +69,7 @@ export class DiskMangerWorker {
|
||||
try {
|
||||
for (let i = 0; i < list.length; i++) {
|
||||
const file = list[i];
|
||||
const fullFilePath = path.normalize(path.resolve(absoluteDirectoryName, file));
|
||||
const fullFilePath = path.normalize(path.join(absoluteDirectoryName, file));
|
||||
if (fs.statSync(fullFilePath).isDirectory()) {
|
||||
if (photosOnly === true) {
|
||||
continue;
|
||||
|
@ -1,5 +1,5 @@
|
||||
import {AuthenticationMWs} from '../middlewares/user/AuthenticationMWs';
|
||||
import {Express, NextFunction, Request, Response} from 'express';
|
||||
import {Express} from 'express';
|
||||
import {GalleryMWs} from '../middlewares/GalleryMWs';
|
||||
import {RenderingMWs} from '../middlewares/RenderingMWs';
|
||||
import {ThumbnailGeneratorMWs} from '../middlewares/thumbnail/ThumbnailGeneratorMWs';
|
||||
@ -28,7 +28,8 @@ export class GalleryRouter {
|
||||
private static addDirectoryList(app: Express) {
|
||||
app.get(['/api/gallery/content/:directory(*)', '/api/gallery/', '/api/gallery//'],
|
||||
AuthenticationMWs.authenticate,
|
||||
AuthenticationMWs.authoriseDirectory,
|
||||
AuthenticationMWs.normalizePathParam('directory'),
|
||||
AuthenticationMWs.authorisePath('directory', true),
|
||||
VersionMWs.injectGalleryVersion,
|
||||
GalleryMWs.listDirectory,
|
||||
ThumbnailGeneratorMWs.addThumbnailInformation,
|
||||
@ -41,7 +42,8 @@ export class GalleryRouter {
|
||||
private static addGetImage(app: Express) {
|
||||
app.get(['/api/gallery/content/:mediaPath(*\.(jpg|jpeg|jpe|webp|png|gif|svg))'],
|
||||
AuthenticationMWs.authenticate,
|
||||
// TODO: authorize path
|
||||
AuthenticationMWs.normalizePathParam('mediaPath'),
|
||||
AuthenticationMWs.authorisePath('mediaPath', false),
|
||||
GalleryMWs.loadFile,
|
||||
RenderingMWs.renderFile
|
||||
);
|
||||
@ -50,7 +52,8 @@ export class GalleryRouter {
|
||||
private static addGetVideo(app: Express) {
|
||||
app.get(['/api/gallery/content/:mediaPath(*\.(mp4|ogg|ogv|webm))'],
|
||||
AuthenticationMWs.authenticate,
|
||||
// TODO: authorize path
|
||||
AuthenticationMWs.normalizePathParam('mediaPath'),
|
||||
AuthenticationMWs.authorisePath('mediaPath', false),
|
||||
GalleryMWs.loadFile,
|
||||
RenderingMWs.renderFile
|
||||
);
|
||||
@ -59,7 +62,8 @@ export class GalleryRouter {
|
||||
private static addGetMetaFile(app: Express) {
|
||||
app.get(['/api/gallery/content/:mediaPath(*\.(gpx))'],
|
||||
AuthenticationMWs.authenticate,
|
||||
// TODO: authorize path
|
||||
AuthenticationMWs.normalizePathParam('mediaPath'),
|
||||
AuthenticationMWs.authorisePath('mediaPath', false),
|
||||
GalleryMWs.loadFile,
|
||||
RenderingMWs.renderFile
|
||||
);
|
||||
@ -68,8 +72,8 @@ export class GalleryRouter {
|
||||
private static addRandom(app: Express) {
|
||||
app.get(['/api/gallery/random'],
|
||||
AuthenticationMWs.authenticate,
|
||||
AuthenticationMWs.authorise(UserRoles.Guest),
|
||||
VersionMWs.injectGalleryVersion,
|
||||
// TODO: authorize path
|
||||
GalleryMWs.getRandomImage,
|
||||
GalleryMWs.loadFile,
|
||||
RenderingMWs.renderFile
|
||||
@ -79,7 +83,8 @@ export class GalleryRouter {
|
||||
private static addGetImageThumbnail(app: Express) {
|
||||
app.get('/api/gallery/content/:mediaPath(*\.(jpg|jpeg|jpe|webp|png|gif|svg))/thumbnail/:size?',
|
||||
AuthenticationMWs.authenticate,
|
||||
// TODO: authorize path
|
||||
AuthenticationMWs.normalizePathParam('mediaPath'),
|
||||
AuthenticationMWs.authorisePath('mediaPath', false),
|
||||
GalleryMWs.loadFile,
|
||||
ThumbnailGeneratorMWs.generateThumbnailFactory(ThumbnailSourceType.Image),
|
||||
RenderingMWs.renderFile
|
||||
@ -89,7 +94,8 @@ export class GalleryRouter {
|
||||
private static addGetVideoThumbnail(app: Express) {
|
||||
app.get('/api/gallery/content/:mediaPath(*\.(mp4|ogg|ogv|webm))/thumbnail/:size?',
|
||||
AuthenticationMWs.authenticate,
|
||||
// TODO: authorize path
|
||||
AuthenticationMWs.normalizePathParam('mediaPath'),
|
||||
AuthenticationMWs.authorisePath('mediaPath', false),
|
||||
GalleryMWs.loadFile,
|
||||
ThumbnailGeneratorMWs.generateThumbnailFactory(ThumbnailSourceType.Video),
|
||||
RenderingMWs.renderFile
|
||||
@ -100,7 +106,8 @@ export class GalleryRouter {
|
||||
private static addGetVideoIcon(app: Express) {
|
||||
app.get('/api/gallery/content/:mediaPath(*\.(mp4|ogg|ogv|webm))/icon',
|
||||
AuthenticationMWs.authenticate,
|
||||
// TODO: authorize path
|
||||
AuthenticationMWs.normalizePathParam('mediaPath'),
|
||||
AuthenticationMWs.authorisePath('mediaPath', false),
|
||||
GalleryMWs.loadFile,
|
||||
ThumbnailGeneratorMWs.generateIconFactory(ThumbnailSourceType.Video),
|
||||
RenderingMWs.renderFile
|
||||
@ -110,7 +117,8 @@ export class GalleryRouter {
|
||||
private static addGetImageIcon(app: Express) {
|
||||
app.get('/api/gallery/content/:mediaPath(*\.(jpg|jpeg|jpe|webp|png|gif|svg))/icon',
|
||||
AuthenticationMWs.authenticate,
|
||||
// TODO: authorize path
|
||||
AuthenticationMWs.normalizePathParam('mediaPath'),
|
||||
AuthenticationMWs.authorisePath('mediaPath', false),
|
||||
GalleryMWs.loadFile,
|
||||
ThumbnailGeneratorMWs.generateIconFactory(ThumbnailSourceType.Image),
|
||||
RenderingMWs.renderFile
|
||||
|
@ -44,7 +44,7 @@ export class PublicRouter {
|
||||
};
|
||||
|
||||
const renderIndex = (req: Request, res: Response, next: Function) => {
|
||||
ejs.renderFile(path.resolve(ProjectPath.FrontendFolder, req['localePath'], 'index.html'),
|
||||
ejs.renderFile(path.join(ProjectPath.FrontendFolder, req['localePath'], 'index.html'),
|
||||
res.tpl, (err, str) => {
|
||||
if (err) {
|
||||
return next(new ErrorDTO(ErrorCodes.GENERAL_ERROR, err.message));
|
||||
@ -79,7 +79,7 @@ export class PublicRouter {
|
||||
});
|
||||
|
||||
|
||||
app.get(['/', '/login', '/gallery*', '/share*', '/admin', '/duplicates', '/faces', '/search*'],
|
||||
app.get(['/', '/login', '/gallery*', '/share*', '/admin', '/duplicates', '/faces', '/search*'],
|
||||
AuthenticationMWs.tryAuthenticate,
|
||||
setLocale,
|
||||
renderIndex
|
||||
@ -90,28 +90,26 @@ export class PublicRouter {
|
||||
);
|
||||
});
|
||||
|
||||
const renderFile = (subDir: string = '') => {
|
||||
return (req: Request, res: Response) => {
|
||||
const file = path.join(ProjectPath.FrontendFolder, req['localePath'], subDir, req.params.file);
|
||||
fs.exists(file, (exists: boolean) => {
|
||||
if (!exists) {
|
||||
return res.sendStatus(404);
|
||||
}
|
||||
res.sendFile(file);
|
||||
});
|
||||
};
|
||||
};
|
||||
|
||||
app.get('/assets/:file(*)',
|
||||
setLocale,
|
||||
(req: Request, res: Response) => {
|
||||
const file = path.resolve(ProjectPath.FrontendFolder, req['localePath'], 'assets', req.params.file);
|
||||
fs.exists(file, (exists: boolean) => {
|
||||
if (!exists) {
|
||||
return res.sendStatus(404);
|
||||
}
|
||||
res.sendFile(file);
|
||||
});
|
||||
});
|
||||
AuthenticationMWs.normalizePathParam('file'),
|
||||
renderFile('assets'));
|
||||
app.get('/:file',
|
||||
setLocale,
|
||||
(req: Request, res: Response) => {
|
||||
const file = path.resolve(ProjectPath.FrontendFolder, req['localePath'], req.params.file);
|
||||
fs.exists(file, (exists: boolean) => {
|
||||
if (!exists) {
|
||||
return res.sendStatus(404);
|
||||
}
|
||||
res.sendFile(file);
|
||||
});
|
||||
});
|
||||
AuthenticationMWs.normalizePathParam('file'),
|
||||
renderFile());
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -15,25 +15,26 @@ export interface UserDTO {
|
||||
name: string;
|
||||
password: string;
|
||||
role: UserRoles;
|
||||
usedSharingKey?: string;
|
||||
permissions: string[]; // user can only see these permissions. if ends with *, its recursive
|
||||
}
|
||||
|
||||
export module UserDTO {
|
||||
|
||||
export const isPathAvailable = (path: string, permissions: string[]): boolean => {
|
||||
if (permissions == null || permissions.length === 0 || permissions[0] === '/*') {
|
||||
export const isDirectoryPathAvailable = (path: string, permissions: string[], separator = '/'): boolean => {
|
||||
if (permissions == null || permissions.length === 0 || permissions[0] === separator + '*') {
|
||||
return true;
|
||||
}
|
||||
for (let i = 0; i < permissions.length; i++) {
|
||||
let permission = permissions[i];
|
||||
if (permission[permission.length - 1] === '*') {
|
||||
permission = permission.slice(0, -1);
|
||||
if (path.startsWith(permission)) {
|
||||
if (path.startsWith(permission) && (!path[permission.length] || path[permission.length] === separator)) {
|
||||
return true;
|
||||
}
|
||||
} else if (path === permission) {
|
||||
return true;
|
||||
} else if (path === '.' && permission === '/') {
|
||||
} else if (path === '.' && permission === separator) {
|
||||
return true;
|
||||
}
|
||||
|
||||
@ -42,7 +43,6 @@ export module UserDTO {
|
||||
};
|
||||
|
||||
export const isDirectoryAvailable = (directory: DirectoryDTO, permissions: string[]): boolean => {
|
||||
|
||||
return isPathAvailable(Utils.concatUrls(directory.path, directory.name), permissions);
|
||||
return isDirectoryPathAvailable(Utils.concatUrls(directory.path, directory.name), permissions);
|
||||
};
|
||||
}
|
||||
|
@ -53,7 +53,6 @@ export class GalleryComponent implements OnInit, OnDestroy {
|
||||
private rndService: SeededRandomService) {
|
||||
this.mapEnabled = Config.Client.Map.enabled;
|
||||
this.SearchTypes = SearchTypes;
|
||||
|
||||
PageHelper.showScrollY();
|
||||
}
|
||||
|
||||
|
@ -18,6 +18,9 @@ export class GalleryService {
|
||||
|
||||
public content: BehaviorSubject<ContentWrapper>;
|
||||
public sorting: BehaviorSubject<SortingMethods>;
|
||||
lastRequest: { directory: string } = {
|
||||
directory: null
|
||||
};
|
||||
private lastDirectory: DirectoryDTO;
|
||||
private searchId: any;
|
||||
private ongoingSearch: {
|
||||
@ -38,10 +41,6 @@ export class GalleryService {
|
||||
this.sorting = new BehaviorSubject<SortingMethods>(Config.Client.Other.defaultPhotoSortingMethod);
|
||||
}
|
||||
|
||||
lastRequest: { directory: string } = {
|
||||
directory: null
|
||||
};
|
||||
|
||||
setSorting(sorting: SortingMethods): void {
|
||||
this.sorting.next(sorting);
|
||||
if (this.content.value.directory) {
|
||||
|
@ -70,7 +70,7 @@ export class GalleryNavigatorComponent implements OnChanges {
|
||||
if (dirs.length === 0) {
|
||||
arr.push({name: this.RootFolderName, route: null});
|
||||
} else {
|
||||
arr.push({name: this.RootFolderName, route: UserDTO.isPathAvailable('/', user.permissions) ? '/' : null});
|
||||
arr.push({name: this.RootFolderName, route: UserDTO.isDirectoryPathAvailable('/', user.permissions) ? '/' : null});
|
||||
}
|
||||
|
||||
// create rest navigation
|
||||
@ -79,7 +79,7 @@ export class GalleryNavigatorComponent implements OnChanges {
|
||||
if (dirs.length - 1 === index) {
|
||||
arr.push({name: name, route: null});
|
||||
} else {
|
||||
arr.push({name: name, route: UserDTO.isPathAvailable(route, user.permissions) ? route : null});
|
||||
arr.push({name: name, route: UserDTO.isDirectoryPathAvailable(route, user.permissions) ? route : null});
|
||||
}
|
||||
});
|
||||
|
||||
|
@ -2,8 +2,9 @@ import {Injectable} from '@angular/core';
|
||||
import {NetworkService} from '../model/network/network.service';
|
||||
import {CreateSharingDTO, SharingDTO} from '../../../common/entities/SharingDTO';
|
||||
import {Router, RoutesRecognized} from '@angular/router';
|
||||
import {BehaviorSubject} from 'rxjs';
|
||||
import {BehaviorSubject, Observable} from 'rxjs';
|
||||
import {QueryParams} from '../../../common/QueryParams';
|
||||
import {UserDTO} from '../../../common/entities/UserDTO';
|
||||
|
||||
@Injectable()
|
||||
export class ShareService {
|
||||
@ -17,7 +18,8 @@ export class ShareService {
|
||||
private resolve: () => void;
|
||||
|
||||
|
||||
constructor(private _networkService: NetworkService, private router: Router) {
|
||||
constructor(private networkService: NetworkService,
|
||||
private router: Router) {
|
||||
this.sharing = new BehaviorSubject(null);
|
||||
this.ReadyPR = new Promise((resolve: () => void) => {
|
||||
if (this.inited === true) {
|
||||
@ -30,28 +32,52 @@ export class ShareService {
|
||||
if (val instanceof RoutesRecognized) {
|
||||
this.param = val.state.root.firstChild.params[QueryParams.gallery.sharingKey_long] || null;
|
||||
this.queryParam = val.state.root.firstChild.queryParams[QueryParams.gallery.sharingKey_short] || null;
|
||||
const changed = this.sharingKey !== this.param || this.queryParam;
|
||||
|
||||
const changed = this.sharingKey !== (this.param || this.queryParam);
|
||||
if (changed) {
|
||||
this.sharingKey = this.param || this.queryParam;
|
||||
this.sharingKey = this.param || this.queryParam || this.sharingKey;
|
||||
this.getSharing();
|
||||
}
|
||||
if (this.resolve) {
|
||||
this.resolve();
|
||||
this.resolve = null;
|
||||
this.inited = true;
|
||||
}
|
||||
|
||||
}
|
||||
});
|
||||
|
||||
|
||||
}
|
||||
|
||||
public setUserObs(userOB: Observable<UserDTO>) {
|
||||
|
||||
userOB.subscribe((user) => {
|
||||
console.log(user);
|
||||
if (user && !!user.usedSharingKey) {
|
||||
if (user.usedSharingKey !== this.sharingKey) {
|
||||
this.sharingKey = user.usedSharingKey;
|
||||
this.getSharing();
|
||||
}
|
||||
if (this.resolve) {
|
||||
this.resolve();
|
||||
this.resolve = null;
|
||||
this.inited = true;
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
public wait(): Promise<void> {
|
||||
if (this.inited) {
|
||||
return Promise.resolve();
|
||||
}
|
||||
return this.ReadyPR;
|
||||
}
|
||||
|
||||
public createSharing(dir: string, includeSubfolders: boolean, valid: number): Promise<SharingDTO> {
|
||||
return this._networkService.postJson('/share/' + dir, {
|
||||
return this.networkService.postJson('/share/' + dir, {
|
||||
createSharing: <CreateSharingDTO>{
|
||||
includeSubfolders: includeSubfolders,
|
||||
valid: valid
|
||||
@ -60,7 +86,7 @@ export class ShareService {
|
||||
}
|
||||
|
||||
public updateSharing(dir: string, sharingId: number, includeSubfolders: boolean, password: string, valid: number): Promise<SharingDTO> {
|
||||
return this._networkService.putJson('/share/' + dir, {
|
||||
return this.networkService.putJson('/share/' + dir, {
|
||||
updateSharing: <CreateSharingDTO>{
|
||||
id: sharingId,
|
||||
includeSubfolders: includeSubfolders,
|
||||
@ -80,7 +106,7 @@ export class ShareService {
|
||||
}
|
||||
|
||||
public async getSharing(): Promise<SharingDTO> {
|
||||
const sharing = await this._networkService.getJson<SharingDTO>('/share/' + this.getSharingKey());
|
||||
const sharing = await this.networkService.getJson<SharingDTO>('/share/' + this.getSharingKey());
|
||||
this.sharing.next(sharing);
|
||||
return sharing;
|
||||
}
|
||||
|
@ -28,7 +28,7 @@ export class NavigationService {
|
||||
public async toGallery() {
|
||||
await this._shareService.wait();
|
||||
if (this._shareService.isSharing()) {
|
||||
return this._router.navigate(['gallery', ''], {queryParams: {sk: this._shareService.getSharingKey()}});
|
||||
return this._router.navigate(['share', this._shareService.getSharingKey()]);
|
||||
} else {
|
||||
return this._router.navigate(['gallery', '']);
|
||||
}
|
||||
|
@ -8,6 +8,7 @@ import {Config} from '../../../../common/config/public/Config';
|
||||
import {NetworkService} from './network.service';
|
||||
import {ErrorCodes, ErrorDTO} from '../../../../common/entities/Error';
|
||||
import {CookieNames} from '../../../../common/CookieNames';
|
||||
import {ShareService} from '../../gallery/share.service';
|
||||
|
||||
declare module ServerInject {
|
||||
export let user: UserDTO;
|
||||
@ -19,9 +20,10 @@ export class AuthenticationService {
|
||||
public user: BehaviorSubject<UserDTO>;
|
||||
|
||||
constructor(private _userService: UserService,
|
||||
private _networkService: NetworkService) {
|
||||
private _networkService: NetworkService,
|
||||
private shareSerice: ShareService) {
|
||||
this.user = new BehaviorSubject(null);
|
||||
|
||||
this.shareSerice.setUserObs(this.user);
|
||||
// picking up session..
|
||||
if (this.isAuthenticated() === false && Cookie.get(CookieNames.session) != null) {
|
||||
if (typeof ServerInject !== 'undefined' && typeof ServerInject.user !== 'undefined') {
|
||||
@ -48,6 +50,34 @@ export class AuthenticationService {
|
||||
|
||||
}
|
||||
|
||||
public async login(credential: LoginCredential): Promise<UserDTO> {
|
||||
const user = await this._userService.login(credential);
|
||||
this.user.next(user);
|
||||
return user;
|
||||
}
|
||||
|
||||
public async shareLogin(password: string): Promise<UserDTO> {
|
||||
const user = await this._userService.shareLogin(password);
|
||||
this.user.next(user);
|
||||
return user;
|
||||
}
|
||||
|
||||
public isAuthenticated(): boolean {
|
||||
if (Config.Client.authenticationRequired === false) {
|
||||
return true;
|
||||
}
|
||||
return !!this.user.value;
|
||||
}
|
||||
|
||||
public isAuthorized(role: UserRoles) {
|
||||
return this.user.value && this.user.value.role >= role;
|
||||
}
|
||||
|
||||
public async logout() {
|
||||
await this._userService.logout();
|
||||
this.user.next(null);
|
||||
}
|
||||
|
||||
private async getSessionUser(): Promise<void> {
|
||||
try {
|
||||
this.user.next(await this._userService.getSessionUser());
|
||||
@ -58,35 +88,4 @@ export class AuthenticationService {
|
||||
}
|
||||
|
||||
|
||||
public async login(credential: LoginCredential): Promise<UserDTO> {
|
||||
const user = await this._userService.login(credential);
|
||||
this.user.next(user);
|
||||
return user;
|
||||
}
|
||||
|
||||
|
||||
public async shareLogin(password: string): Promise<UserDTO> {
|
||||
const user = await this._userService.shareLogin(password);
|
||||
this.user.next(user);
|
||||
return user;
|
||||
}
|
||||
|
||||
|
||||
public isAuthenticated(): boolean {
|
||||
if (Config.Client.authenticationRequired === false) {
|
||||
return true;
|
||||
}
|
||||
return !!(this.user.value && this.user.value != null);
|
||||
}
|
||||
|
||||
public isAuthorized(role: UserRoles) {
|
||||
return this.user.value && this.user.value.role >= role;
|
||||
}
|
||||
|
||||
public logout() {
|
||||
this._userService.logout();
|
||||
this.user.next(null);
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
@ -29,7 +29,7 @@ export class UserService {
|
||||
await this._shareService.wait();
|
||||
if (Config.Client.Sharing.enabled === true) {
|
||||
if (this._shareService.isSharing()) {
|
||||
return this._networkService.getJson<UserDTO>('/user/login?sk=' + this._shareService.getSharingKey());
|
||||
return this._networkService.getJson<UserDTO>('/user/login', {sk: this._shareService.getSharingKey()});
|
||||
}
|
||||
}
|
||||
return this._networkService.getJson<UserDTO>('/user/login');
|
||||
|
20
package-lock.json
generated
20
package-lock.json
generated
@ -14438,6 +14438,26 @@
|
||||
}
|
||||
}
|
||||
},
|
||||
"tslint-no-unused-expression-chai": {
|
||||
"version": "0.1.4",
|
||||
"resolved": "https://registry.npmjs.org/tslint-no-unused-expression-chai/-/tslint-no-unused-expression-chai-0.1.4.tgz",
|
||||
"integrity": "sha512-frEWKNTcq7VsaWKgUxMDOB2N/cmQadVkUtUGIut+2K4nv/uFXPfgJyPjuNC/cHyfUVqIkHMAvHOCL+d/McU3nQ==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"tsutils": "^3.0.0"
|
||||
},
|
||||
"dependencies": {
|
||||
"tsutils": {
|
||||
"version": "3.8.0",
|
||||
"resolved": "https://registry.npmjs.org/tsutils/-/tsutils-3.8.0.tgz",
|
||||
"integrity": "sha512-XQdPhgcoTbCD8baXC38PQ0vpTZ8T3YrE+vR66YIj/xvDt1//8iAhafpIT/4DmvzzC1QFapEImERu48Pa01dIUA==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"tslib": "^1.8.1"
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"tsutils": {
|
||||
"version": "2.29.0",
|
||||
"resolved": "https://registry.npmjs.org/tsutils/-/tsutils-2.29.0.tgz",
|
||||
|
@ -114,13 +114,13 @@
|
||||
"run-sequence": "2.2.1",
|
||||
"rxjs": "6.4.0",
|
||||
"rxjs-compat": "6.4.0",
|
||||
"terser": "3.16.1",
|
||||
"ts-helpers": "1.1.2",
|
||||
"ts-node": "8.0.2",
|
||||
"tslint": "5.12.1",
|
||||
"typescript": "3.2.4",
|
||||
"xlf-google-translate": "1.0.0-beta.13",
|
||||
"zone.js": "0.8.29",
|
||||
"terser": "3.16.1"
|
||||
"zone.js": "0.8.29"
|
||||
},
|
||||
"//": [
|
||||
"TODO: remove terser version lock once webpack is fixed"
|
||||
|
@ -18,8 +18,8 @@ export class SQLTestHelper {
|
||||
dbPath: string;
|
||||
|
||||
constructor(public dbType: DatabaseType) {
|
||||
this.tempDir = path.resolve(__dirname, './tmp');
|
||||
this.dbPath = path.resolve(__dirname, './tmp', 'test.db');
|
||||
this.tempDir = path.join(__dirname, './tmp');
|
||||
this.dbPath = path.join(__dirname, './tmp', 'test.db');
|
||||
|
||||
}
|
||||
|
||||
|
@ -6,8 +6,13 @@ import {ObjectManagers} from '../../../../../backend/model/ObjectManagers';
|
||||
import {UserManager} from '../../../../../backend/model/memory/UserManager';
|
||||
import {Config} from '../../../../../common/config/private/Config';
|
||||
import {IUserManager} from '../../../../../backend/model/interfaces/IUserManager';
|
||||
import * as path from 'path';
|
||||
|
||||
|
||||
declare const describe: any;
|
||||
declare const it: any;
|
||||
declare const beforeEach: any;
|
||||
|
||||
describe('Authentication middleware', () => {
|
||||
|
||||
beforeEach(() => {
|
||||
@ -15,7 +20,7 @@ describe('Authentication middleware', () => {
|
||||
});
|
||||
|
||||
describe('authenticate', () => {
|
||||
it('should call next on authenticated', (done) => {
|
||||
it('should call next on authenticated', (done: () => void) => {
|
||||
const req: any = {
|
||||
session: {
|
||||
user: 'A user'
|
||||
@ -24,7 +29,7 @@ describe('Authentication middleware', () => {
|
||||
query: {},
|
||||
params: {}
|
||||
};
|
||||
const next: any = (err: ErrorDTO) => {
|
||||
const next = (err: ErrorDTO) => {
|
||||
expect(err).to.be.undefined;
|
||||
done();
|
||||
};
|
||||
@ -32,7 +37,7 @@ describe('Authentication middleware', () => {
|
||||
|
||||
});
|
||||
|
||||
it('should call next with error on not authenticated', (done) => {
|
||||
it('should call next with error on not authenticated', (done: () => void) => {
|
||||
const req: any = {
|
||||
session: {},
|
||||
sessionOptions: {},
|
||||
@ -40,8 +45,7 @@ describe('Authentication middleware', () => {
|
||||
params: {}
|
||||
};
|
||||
Config.Client.authenticationRequired = true;
|
||||
const res: any = {};
|
||||
const next: any = (err: ErrorDTO) => {
|
||||
const next = (err: ErrorDTO) => {
|
||||
expect(err).not.to.be.undefined;
|
||||
expect(err.code).to.be.eql(ErrorCodes.NOT_AUTHENTICATED);
|
||||
done();
|
||||
@ -51,15 +55,69 @@ describe('Authentication middleware', () => {
|
||||
});
|
||||
});
|
||||
|
||||
|
||||
describe('authorisePath', () => {
|
||||
|
||||
const req = {
|
||||
session: {
|
||||
user: {permissions: <string[]>null}
|
||||
},
|
||||
sessionOptions: {},
|
||||
query: {},
|
||||
params: {
|
||||
path: '/test'
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
const authoriseDirPath = AuthenticationMWs.authorisePath('path', true);
|
||||
const test = (relativePath: string): Promise<string | number> => {
|
||||
return new Promise((resolve) => {
|
||||
req.params.path = path.normalize(relativePath);
|
||||
authoriseDirPath(<any>req, <any>{sendStatus: resolve}, () => {
|
||||
resolve('ok');
|
||||
});
|
||||
resolve();
|
||||
});
|
||||
};
|
||||
|
||||
it('should catch unauthorized path usage', async () => {
|
||||
req.session.user.permissions = [path.normalize('/sub/subsub')];
|
||||
expect(await test('/sub/subsub')).to.be.eql('ok');
|
||||
expect(await test('/test')).to.be.eql(403);
|
||||
expect(await test('/')).to.be.eql(403);
|
||||
expect(await test('/sub/test')).to.be.eql(403);
|
||||
expect(await test('/sub/subsub/test')).to.be.eql(403);
|
||||
expect(await test('/sub/subsub/test/test2')).to.be.eql(403);
|
||||
req.session.user.permissions = [path.normalize('/sub/subsub'), path.normalize('/sub/subsub2')];
|
||||
expect(await test('/sub/subsub2')).to.be.eql('ok');
|
||||
expect(await test('/sub/subsub')).to.be.eql('ok');
|
||||
expect(await test('/test')).to.be.eql(403);
|
||||
expect(await test('/')).to.be.eql(403);
|
||||
expect(await test('/sub/test')).to.be.eql(403);
|
||||
expect(await test('/sub/subsub/test')).to.be.eql(403);
|
||||
expect(await test('/sub/subsub2/test')).to.be.eql(403);
|
||||
req.session.user.permissions = [path.normalize('/sub/subsub*')];
|
||||
expect(await test('/b')).to.be.eql(403);
|
||||
expect(await test('/sub')).to.be.eql(403);
|
||||
expect(await test('/sub/subsub2')).to.be.eql(403);
|
||||
expect(await test('/sub/subsub2/test')).to.be.eql(403);
|
||||
expect(await test('/sub/subsub')).to.be.eql('ok');
|
||||
expect(await test('/sub/subsub/test')).to.be.eql('ok');
|
||||
expect(await test('/sub/subsub/test/two')).to.be.eql('ok');
|
||||
});
|
||||
|
||||
});
|
||||
|
||||
describe('inverseAuthenticate', () => {
|
||||
|
||||
it('should call next with error on authenticated', (done) => {
|
||||
it('should call next with error on authenticated', (done: () => void) => {
|
||||
const req: any = {
|
||||
session: {},
|
||||
sessionOptions: {},
|
||||
};
|
||||
const res: any = {};
|
||||
const next: any = (err:ErrorDTO) => {
|
||||
const next: any = (err: ErrorDTO) => {
|
||||
expect(err).to.be.undefined;
|
||||
done();
|
||||
};
|
||||
@ -68,15 +126,14 @@ describe('Authentication middleware', () => {
|
||||
});
|
||||
|
||||
|
||||
it('should call next error on authenticated', (done) => {
|
||||
it('should call next error on authenticated', (done: () => void) => {
|
||||
const req: any = {
|
||||
session: {
|
||||
user: 'A user'
|
||||
},
|
||||
sessionOptions: {},
|
||||
};
|
||||
const res: any = {};
|
||||
const next: any = (err: ErrorDTO) => {
|
||||
const next = (err: ErrorDTO) => {
|
||||
expect(err).not.to.be.undefined;
|
||||
expect(err.code).to.be.eql(ErrorCodes.ALREADY_AUTHENTICATED);
|
||||
done();
|
||||
@ -87,7 +144,7 @@ describe('Authentication middleware', () => {
|
||||
});
|
||||
|
||||
describe('authorise', () => {
|
||||
it('should call next on authorised', (done) => {
|
||||
it('should call next on authorised', (done: () => void) => {
|
||||
const req: any = {
|
||||
session: {
|
||||
user: {
|
||||
@ -96,7 +153,7 @@ describe('Authentication middleware', () => {
|
||||
},
|
||||
sessionOptions: {}
|
||||
};
|
||||
const next: any = (err:ErrorDTO) => {
|
||||
const next = (err: ErrorDTO) => {
|
||||
expect(err).to.be.undefined;
|
||||
done();
|
||||
};
|
||||
@ -104,7 +161,7 @@ describe('Authentication middleware', () => {
|
||||
|
||||
});
|
||||
|
||||
it('should call next with error on not authorised', (done) => {
|
||||
it('should call next with error on not authorised', (done: () => void) => {
|
||||
const req: any = {
|
||||
session: {
|
||||
user: {
|
||||
@ -113,7 +170,7 @@ describe('Authentication middleware', () => {
|
||||
},
|
||||
sessionOptions: {}
|
||||
};
|
||||
const next: any = (err: ErrorDTO) => {
|
||||
const next = (err: ErrorDTO) => {
|
||||
expect(err).not.to.be.undefined;
|
||||
expect(err.code).to.be.eql(ErrorCodes.NOT_AUTHORISED);
|
||||
done();
|
||||
@ -129,12 +186,12 @@ describe('Authentication middleware', () => {
|
||||
});
|
||||
|
||||
describe('should call input ErrorDTO next on missing...', () => {
|
||||
it('body', (done) => {
|
||||
it('body', (done: () => void) => {
|
||||
const req: any = {
|
||||
query: {},
|
||||
params: {}
|
||||
};
|
||||
const next: any = (err: ErrorDTO) => {
|
||||
const next = (err: ErrorDTO) => {
|
||||
expect(err).not.to.be.undefined;
|
||||
expect(err.code).to.be.eql(ErrorCodes.INPUT_ERROR);
|
||||
done();
|
||||
@ -143,13 +200,13 @@ describe('Authentication middleware', () => {
|
||||
|
||||
});
|
||||
|
||||
it('loginCredential', (done) => {
|
||||
it('loginCredential', (done: () => void) => {
|
||||
const req: any = {
|
||||
body: {},
|
||||
query: {},
|
||||
params: {}
|
||||
};
|
||||
const next: any = (err: ErrorDTO) => {
|
||||
const next = (err: ErrorDTO) => {
|
||||
expect(err).not.to.be.undefined;
|
||||
expect(err.code).to.be.eql(ErrorCodes.INPUT_ERROR);
|
||||
done();
|
||||
@ -160,13 +217,13 @@ describe('Authentication middleware', () => {
|
||||
});
|
||||
|
||||
|
||||
it('loginCredential content', (done) => {
|
||||
it('loginCredential content', (done: () => void) => {
|
||||
const req: any = {
|
||||
body: {loginCredential: {}},
|
||||
query: {},
|
||||
params: {}
|
||||
};
|
||||
const next: any = (err: ErrorDTO) => {
|
||||
const next = (err: ErrorDTO) => {
|
||||
expect(err).not.to.be.undefined;
|
||||
expect(err.code).to.be.eql(ErrorCodes.INPUT_ERROR);
|
||||
done();
|
||||
@ -177,7 +234,7 @@ describe('Authentication middleware', () => {
|
||||
});
|
||||
|
||||
});
|
||||
it('should call next with error on not finding user', (done) => {
|
||||
it('should call next with error on not finding user', (done: () => void) => {
|
||||
const req: any = {
|
||||
body: {
|
||||
loginCredential: {
|
||||
@ -188,7 +245,7 @@ describe('Authentication middleware', () => {
|
||||
query: {},
|
||||
params: {}
|
||||
};
|
||||
const next: any = (err: ErrorDTO) => {
|
||||
const next = (err: ErrorDTO) => {
|
||||
expect(err).not.to.be.undefined;
|
||||
expect(err.code).to.be.eql(ErrorCodes.CREDENTIAL_NOT_FOUND);
|
||||
done();
|
||||
@ -203,7 +260,7 @@ describe('Authentication middleware', () => {
|
||||
|
||||
});
|
||||
|
||||
it('should call next with user on the session on finding user', (done) => {
|
||||
it('should call next with user on the session on finding user', (done: () => void) => {
|
||||
const req: any = {
|
||||
session: {},
|
||||
body: {
|
||||
@ -215,7 +272,7 @@ describe('Authentication middleware', () => {
|
||||
query: {},
|
||||
params: {}
|
||||
};
|
||||
const next: any = (err: ErrorDTO) => {
|
||||
const next = (err: ErrorDTO) => {
|
||||
expect(err).to.be.undefined;
|
||||
expect(req.session.user).to.be.eql('test user');
|
||||
done();
|
||||
@ -233,7 +290,7 @@ describe('Authentication middleware', () => {
|
||||
|
||||
|
||||
describe('logout', () => {
|
||||
it('should call next on logout', (done) => {
|
||||
it('should call next on logout', (done: () => void) => {
|
||||
const req: any = {
|
||||
session: {
|
||||
user: {
|
||||
@ -241,7 +298,7 @@ describe('Authentication middleware', () => {
|
||||
}
|
||||
}
|
||||
};
|
||||
const next: any = (err:ErrorDTO) => {
|
||||
const next: any = (err: ErrorDTO) => {
|
||||
expect(err).to.be.undefined;
|
||||
expect(req.session.user).to.be.undefined;
|
||||
done();
|
||||
|
@ -5,14 +5,14 @@ describe('UserDTO', () => {
|
||||
|
||||
|
||||
it('should check available path', () => {
|
||||
expect(UserDTO.isPathAvailable('/', ['/'])).to.be.equals(true);
|
||||
expect(UserDTO.isPathAvailable('/', ['/subfolder', '/'])).to.be.equals(true);
|
||||
expect(UserDTO.isPathAvailable('/abc', ['/subfolder', '/'])).to.be.equals(false);
|
||||
expect(UserDTO.isPathAvailable('/abc', ['/subfolder', '/*'])).to.be.equals(true);
|
||||
expect(UserDTO.isPathAvailable('/abc', ['/subfolder'])).to.be.equals(false);
|
||||
expect(UserDTO.isPathAvailable('/abc/two', ['/subfolder'])).to.be.equals(false);
|
||||
expect(UserDTO.isPathAvailable('/abc/two', ['/'])).to.be.equals(false);
|
||||
expect(UserDTO.isPathAvailable('/abc/two', ['/*'])).to.be.equals(true);
|
||||
expect(UserDTO.isDirectoryPathAvailable('/', ['/'])).to.be.equals(true);
|
||||
expect(UserDTO.isDirectoryPathAvailable('/', ['/subfolder', '/'])).to.be.equals(true);
|
||||
expect(UserDTO.isDirectoryPathAvailable('/abc', ['/subfolder', '/'])).to.be.equals(false);
|
||||
expect(UserDTO.isDirectoryPathAvailable('/abc', ['/subfolder', '/*'])).to.be.equals(true);
|
||||
expect(UserDTO.isDirectoryPathAvailable('/abc', ['/subfolder'])).to.be.equals(false);
|
||||
expect(UserDTO.isDirectoryPathAvailable('/abc/two', ['/subfolder'])).to.be.equals(false);
|
||||
expect(UserDTO.isDirectoryPathAvailable('/abc/two', ['/'])).to.be.equals(false);
|
||||
expect(UserDTO.isDirectoryPathAvailable('/abc/two', ['/*'])).to.be.equals(true);
|
||||
});
|
||||
|
||||
it('should check directory', () => {
|
||||
|
Loading…
x
Reference in New Issue
Block a user