FsService.java
package sk.iway.iwcm.system.elfinder;
import java.io.IOException;
import java.util.ArrayList;
import java.util.Collection;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Set;
import org.apache.commons.codec.binary.Base64;
import cn.bluejoe.elfinder.controller.executor.FsItemEx;
import cn.bluejoe.elfinder.service.FsItem;
import cn.bluejoe.elfinder.service.FsItemFilter;
import cn.bluejoe.elfinder.service.FsSecurityChecker;
import cn.bluejoe.elfinder.service.FsServiceConfig;
import cn.bluejoe.elfinder.service.FsVolume;
import sk.iway.iwcm.Constants;
import sk.iway.iwcm.Identity;
import sk.iway.iwcm.Logger;
import sk.iway.iwcm.RequestBean;
import sk.iway.iwcm.SetCharacterEncodingFilter;
import sk.iway.iwcm.Tools;
import sk.iway.iwcm.common.FileBrowserTools;
import sk.iway.iwcm.common.UploadFileTools;
import sk.iway.iwcm.i18n.Prop;
import sk.iway.iwcm.io.IwcmFile;
import sk.iway.iwcm.system.multidomain.MultiDomainFilter;
import sk.iway.iwcm.users.UsersDB;
public class FsService implements cn.bluejoe.elfinder.service.FsService //NOSONAR
{
public static final int TYPE_ALL = 1;
public static final int TYPE_IMAGES = 2;
public static final int TYPE_LINK = 3;
//file browser
public static final int TYPE_FILES = 4;
public static final int TYPE_PAGES = 5;
FsSecurityChecker _securityChecker = new FsSecurityCheckerChain(); //NOSONAR
FsServiceConfig _serviceConfig = new IwcmFsServiceConfig(); //NOSONAR
public static Identity getCurrentUser()
{
RequestBean rb = SetCharacterEncodingFilter.getCurrentRequestBean();
if (rb != null && rb.getRequest()!=null)
{
return UsersDB.getCurrentUser(rb.getRequest());
}
return null;
}
@Override
public FsServiceConfig getServiceConfig()
{
return _serviceConfig;
}
public void setServiceConfig(FsServiceConfig serviceConfig)
{
_serviceConfig = serviceConfig;
}
Map<FsVolume, String> _volumeIds = new HashMap<FsVolume, String>(); //NOSONAR
FsVolume[] _volumes; //NOSONAR
static String[][] escapes = { { "+", "_P" }, { "-", "_M" }, { "/", "_S" }, { ".", "_D" }, { "=", "_E" } };
public FsService()
{
initialize(TYPE_ALL);
}
public FsService(int type)
{
initialize(type);
}
/**
* Pre Volumes ktore poznaju virtualPath vrati priamo virtualPath inak vrati path
* @param fsi
* @return
* @throws IOException
*/
public static String getVirtualPath(FsItemEx fsi) throws IOException
{
String virtualPath = fsi.getPath();
if (fsi.getVolumeId().equals(IwcmDocGroupFsVolume.VOLUME_ID))
{
virtualPath = ((IwcmDocGroupFsVolume)fsi.getVolume()).getVirtualPath(fsi);
}
if (fsi.getVolumeId().equals(IwcmFsVolume.VOLUME_ID_ACTUAL_PAGE))
{
virtualPath = ((IwcmFsVolume)fsi.getVolume()).getVirtualPath(fsi);
}
return virtualPath;
}
public static int getSortPriority(FsItemEx fsi) throws IOException
{
if (fsi.getVolumeId().equals(IwcmDocGroupFsVolume.VOLUME_ID))
{
return ((IwcmDocGroupFsVolume)fsi.getVolume()).getSortPriority(fsi);
}
/*
if (fsi.getVolumeId().equals(IwcmFsVolume.VOLUME_ID_ACTUAL_PAGE))
{
return ((IwcmActualPageFsVolume)fsi.getVolume()).getSortPriority(fsi);
}
*/
return -1;
}
/**
* Inicializacia volumes podla typu zobrazenia (obrazky, vsetko...)
* @param type
*/
private void initialize(int type)
{
Logger.debug(FsService.class, "IwcmFsService initialize, type="+type);
int counter = 0;
if (type == TYPE_IMAGES)
{
_volumes = new FsVolume[2];
counter = addActualPageVolume(counter);
counter = addLibraryVolume(counter);
}
else if (type == TYPE_LINK)
{
boolean elfinderEnableFileArchive = Constants.getBoolean("elfinderFileArchiveEnabled");
int size = 3;
if (elfinderEnableFileArchive) size = 4;
_volumes = new FsVolume[size];
counter = addActualPageVolume(counter);
counter = addLibraryVolume(counter);
counter = addDocGroupVolume(counter);
if (elfinderEnableFileArchive)
{
counter = addArchivVolume(counter);
}
}
else if (type == TYPE_FILES)
{
_volumes = new FsVolume[3];
counter = addLibraryVolume(counter);
counter = addFsVolume(counter);
counter = addDocGroupVolume(counter);
}
else if (type == TYPE_PAGES)
{
_volumes = new FsVolume[1];
counter = addDocGroupVolume(counter);
}
else
{
_volumes = new FsVolume[4];
counter = addActualPageVolume(counter);
counter = addLibraryVolume(counter);
counter = addFsVolume(counter);
counter = addDocGroupVolume(counter);
}
//moze tam byt null, prepocitaj
int notNullSize = 0;
FsVolume[] allItems = new FsVolume[_volumes.length];
for (int i=0; i<_volumes.length; i++)
{
allItems[i] = _volumes[i];
if (allItems[i]!=null) notNullSize++;
}
if (notNullSize != _volumes.length)
{
//musime shrinknut
_volumes = new FsVolume[notNullSize];
int notNullCounter = 0;
for (int i=0; i<allItems.length; i++)
{
if (allItems[i]!=null)
{
_volumes[notNullCounter++] = allItems[i];
}
}
}
}
private int addLibraryVolume(int counter)
{
RequestBean rb = SetCharacterEncodingFilter.getCurrentRequestBean();
String domainAliasAppend = "";
if (rb != null)
{
String domain = rb.getDomain();
String domainAlias = MultiDomainFilter.getDomainAlias(domain);
if (Tools.isNotEmpty(domainAlias))
{
domainAliasAppend = " ("+domainAlias+")";
}
}
_volumes[counter] = new IwcmLibraryFsVolume(Prop.getTxt("elfinder.library")+domainAliasAppend, "/");
_volumeIds.put(_volumes[counter], "iwcm_1");
counter++;
return counter;
}
private int addFsVolume(int counter)
{
_volumes[counter] = new IwcmFsVolume(Prop.getTxt("elfinder.allFiles"), "/");
_volumeIds.put(_volumes[counter], "iwcm_2");
counter++;
return counter;
}
private int addActualPageVolume(int counter)
{
RequestBean rb = SetCharacterEncodingFilter.getCurrentRequestBean();
int docId = Tools.getIntValue(rb.getRequest().getParameter("docId"), 1);
int groupId = Tools.getIntValue(rb.getRequest().getParameter("groupId"), -1);
String title = rb.getRequest().getParameter("title");
if (groupId > 0)
{
StringBuilder rootDirs = new StringBuilder();
String[] prefixes = {"/images", "/files", "/images/gallery"};
for (String prefix : prefixes)
{
String dir = UploadFileTools.getPageUploadSubDir(docId, groupId, title, prefix);
//Logger.debug(FsService.class, "uploadSubdir: docId="+docId+", groupId="+groupId+", dir="+dir);
IwcmFile dirFile = new IwcmFile(Tools.getRealPath(dir));
if (dirFile.exists()==false && prefix.equals("/images/gallery"))
{
//galeriu vynechavame, zobrazi sa ako folder len ked existuje
continue;
}
if (dirFile.exists()==false)
{
boolean ret = dirFile.mkdirs();
Logger.debug(FsService.class, "CREATING DIR: "+dirFile.getAbsolutePath()+" ret="+ret);
}
if (rootDirs.length()>0) rootDirs.append(",");
rootDirs.append(dir);
}
_volumes[counter] = new IwcmActualPageFsVolume(Prop.getTxt("elfinder.actualPage"), "/", rootDirs.toString());
_volumeIds.put(_volumes[counter], IwcmFsVolume.VOLUME_ID_ACTUAL_PAGE);
counter++;
}
return counter;
}
private int addDocGroupVolume(int counter)
{
Identity user = getCurrentUser();
if (user == null || user.isDisabledItem("menuWebpages")) return counter;
_volumes[counter] = new IwcmDocGroupFsVolume(Prop.getTxt("menu.web_sites"));
_volumeIds.put(_volumes[counter], IwcmDocGroupFsVolume.VOLUME_ID);
counter++;
return counter;
}
private int addArchivVolume(int counter)
{
_volumes[counter] = new IwcmArchivFsVolume(Prop.getTxt("components.file_archiv.name"));
_volumeIds.put(_volumes[counter], IwcmArchivFsVolume.VOLUME_ID);
counter++;
return counter;
}
@Override
public FsItem fromHash(String hash)
{
if (hash != null)
{
for (FsVolume v : _volumes)
{
String prefix = getVolumeId(v) + "_";
if (hash.equals(prefix))
{
return v.getRoot();
}
if (hash.startsWith(prefix))
{
String localHash = hash.substring(prefix.length());
for (String[] pair : escapes)
{
localHash = localHash.replace(pair[1], pair[0]);
}
//JEEFF String relativePath = new String(Base64.decodeBase64(localHash));
String relativePath = new String(Base64.decodeBase64(localHash.getBytes()));
//bad hackers CVE-2022-26960
if (hash.startsWith("iwcm_doc_group_volume")==false && FileBrowserTools.hasForbiddenSymbol(relativePath)) return null;
return v.fromPath(relativePath);
}
}
}
return null;
}
@Override
public String getHash(FsItem item) throws IOException
{
String relativePath = item.getVolume().getPath(item);
if ("/group:0".equals(relativePath)) relativePath = "";
String base = new String(Base64.encodeBase64(relativePath.getBytes()));
for (String[] pair : escapes)
{
base = base.replace(pair[0], pair[1]);
}
return getVolumeId(item.getVolume()) + "_" + base;
}
/**
* Vrati hash pre zadanu cestu (pouzivane v JS kode pre znovaotvorenie cesty)
* @param relativePath
* @return
*/
public static String getHash(String relativePath)
{
String base = new String(Base64.encodeBase64(relativePath.getBytes()));
for (String[] pair : escapes)
{
base = base.replace(pair[0], pair[1]);
}
String volumeId = "iwcm_1";
return volumeId + "_" + base;
}
@Override
public FsSecurityChecker getSecurityChecker()
{
return _securityChecker;
}
@Override
public String getVolumeId(FsVolume volume)
{
return _volumeIds.get(volume);
}
@Override
public FsVolume[] getVolumes()
{
return _volumes;
}
public void setSecurityChecker(FsSecurityChecker securityChecker)
{
_securityChecker = securityChecker;
}
public void setVolumes(FsVolume[] volumes)
{
_volumes = volumes;
char vid = 'A';
for (FsVolume volume : volumes)
{
_volumeIds.put(volume, "" + vid);
vid++;
}
}
@Override
public FsItemEx[] find(FsItemFilter filter, FsItemEx target, boolean recursive)
{
List<FsItemEx> listFsItemsEx = new ArrayList<>();
if(getVolumes() != null && getVolumes().length >0)
{
for(FsVolume volume:getVolumes())
{
if (target.getVolume().equals(volume) == false) continue;
if (volume instanceof IwcmFsVolume) {
try {
FsItem root = ((IwcmFsVolume)volume).fromPath(target.getPath());
listFsItemsEx.addAll(findRecursively(filter, root, recursive, new HashSet<>()));
} catch (Exception ex) {
Logger.error(ex);
}
} else if (volume instanceof IwcmDocGroupFsVolume) {
try {
FsItem root = ((IwcmDocGroupFsVolume)volume).fromPath(target.getPath());
listFsItemsEx.addAll(findRecursively(filter, root, recursive, new HashSet<>()));
} catch (Exception ex) {
Logger.error(ex);
}
} else {
for(FsItem item: volume.listChildren(volume.getRoot()))
{
if(item instanceof IwcmArchivItem)
{
listFsFiles(item,volume,listFsItemsEx,filter,this);
}
}
}
}
}
//Logger.debug(this,"listFsItemsEx.size() "+listFsItemsEx.size());
FsItemEx[] cwd = new FsItemEx[listFsItemsEx.size()];
cwd = listFsItemsEx.toArray(cwd);
return cwd;
}
private static List<FsItemEx> listFsFiles(FsItem item,FsVolume volume, List<FsItemEx> listFsItemsEx,FsItemFilter filter, FsService fsService)
{
for (FsItem file : volume.listChildren(item))
{
if (!volume.isFolder(file) && filter.accepts(new FsItemEx(file, fsService)))
{
FsItemEx fsx = null;
if (file instanceof IwcmArchivItem) {
fsx = new FsItemEx((IwcmArchivItem)file, fsService); //NOSONAR
} else if (file instanceof IwcmFsItem) {
fsx = new FsItemEx((IwcmFsItem)file, fsService); //NOSONAR
}
if (fsx != null) listFsItemsEx.add(fsx);
}
}
return listFsItemsEx;
}
/**
* find files recursively in specific folder
*
* @param filter
* The filter to apply to select files.
* @param root
* The location in the hierarchy to search from.
* @return A collection of files that match the filter and have the root as
* a parent.
*/
private Collection<FsItemEx> findRecursively(FsItemFilter filter, FsItem root, boolean recursive, Set<String> duplicityCheck)
{
List<FsItemEx> results = new ArrayList<>();
FsVolume vol = root.getVolume();
FsItem[] childrens = vol.listChildren(root);
for (int i=0; i<childrens.length; i++) {
FsItem child = childrens[i];
FsItemEx item = new FsItemEx(child, this);
try {
if (vol.isFolder(child)) {
if (recursive && duplicityCheck.contains(item.getPath())==false) {
Collection<FsItemEx> sublist = findRecursively(filter, child, recursive, duplicityCheck);
if (sublist.isEmpty()==false) {
results.addAll(sublist);
duplicityCheck.add(item.getPath());
}
}
} else {
if (filter.accepts(item)) {
results.add(item);
}
}
} catch (Exception ex) {
Logger.error(ex);
}
}
return results;
}
}