001    /**
002     * Copyright (c) 2000-2013 Liferay, Inc. All rights reserved.
003     *
004     * This library is free software; you can redistribute it and/or modify it under
005     * the terms of the GNU Lesser General Public License as published by the Free
006     * Software Foundation; either version 2.1 of the License, or (at your option)
007     * any later version.
008     *
009     * This library is distributed in the hope that it will be useful, but WITHOUT
010     * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
011     * FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more
012     * details.
013     */
014    
015    package com.liferay.portlet.documentlibrary.store;
016    
017    import com.liferay.portal.kernel.bean.BeanReference;
018    import com.liferay.portal.kernel.exception.PortalException;
019    import com.liferay.portal.kernel.exception.SystemException;
020    import com.liferay.portal.kernel.io.ByteArrayFileInputStream;
021    import com.liferay.portal.kernel.search.BooleanClauseOccur;
022    import com.liferay.portal.kernel.search.BooleanQuery;
023    import com.liferay.portal.kernel.search.BooleanQueryFactoryUtil;
024    import com.liferay.portal.kernel.search.Field;
025    import com.liferay.portal.kernel.search.Hits;
026    import com.liferay.portal.kernel.search.Indexer;
027    import com.liferay.portal.kernel.search.IndexerRegistryUtil;
028    import com.liferay.portal.kernel.search.SearchContext;
029    import com.liferay.portal.kernel.search.SearchEngineUtil;
030    import com.liferay.portal.kernel.search.TermQuery;
031    import com.liferay.portal.kernel.search.TermQueryFactoryUtil;
032    import com.liferay.portal.kernel.util.FileUtil;
033    import com.liferay.portal.kernel.util.PropsKeys;
034    import com.liferay.portal.kernel.util.StringPool;
035    import com.liferay.portal.kernel.util.StringUtil;
036    import com.liferay.portal.kernel.util.Validator;
037    import com.liferay.portal.model.Group;
038    import com.liferay.portal.security.permission.ActionKeys;
039    import com.liferay.portal.security.permission.PermissionChecker;
040    import com.liferay.portal.security.permission.PermissionThreadLocal;
041    import com.liferay.portal.service.GroupLocalService;
042    import com.liferay.portal.util.PrefsPropsUtil;
043    import com.liferay.portal.util.PropsValues;
044    import com.liferay.portlet.documentlibrary.DirectoryNameException;
045    import com.liferay.portlet.documentlibrary.FileExtensionException;
046    import com.liferay.portlet.documentlibrary.FileNameException;
047    import com.liferay.portlet.documentlibrary.FileSizeException;
048    import com.liferay.portlet.documentlibrary.SourceFileNameException;
049    import com.liferay.portlet.documentlibrary.antivirus.AntivirusScannerUtil;
050    import com.liferay.portlet.documentlibrary.model.DLFileEntryConstants;
051    import com.liferay.portlet.documentlibrary.model.DLFolderConstants;
052    import com.liferay.portlet.documentlibrary.service.permission.DLFolderPermission;
053    
054    import java.io.File;
055    import java.io.IOException;
056    import java.io.InputStream;
057    
058    /**
059     * @author Brian Wing Shun Chan
060     * @author Alexander Chow
061     * @author Edward Han
062     */
063    public class DLStoreImpl implements DLStore {
064    
065            @Override
066            public void addDirectory(long companyId, long repositoryId, String dirName)
067                    throws PortalException, SystemException {
068    
069                    if (!isValidName(dirName) || dirName.equals("/")) {
070                            throw new DirectoryNameException(dirName);
071                    }
072    
073                    store.addDirectory(companyId, repositoryId, dirName);
074            }
075    
076            @Override
077            public void addFile(
078                            long companyId, long repositoryId, String fileName,
079                            boolean validateFileExtension, byte[] bytes)
080                    throws PortalException, SystemException {
081    
082                    validate(fileName, validateFileExtension, bytes);
083    
084                    if (PropsValues.DL_STORE_ANTIVIRUS_ENABLED) {
085                            AntivirusScannerUtil.scan(bytes);
086                    }
087    
088                    store.addFile(companyId, repositoryId, fileName, bytes);
089            }
090    
091            @Override
092            public void addFile(
093                            long companyId, long repositoryId, String fileName,
094                            boolean validateFileExtension, File file)
095                    throws PortalException, SystemException {
096    
097                    validate(fileName, validateFileExtension, file);
098    
099                    if (PropsValues.DL_STORE_ANTIVIRUS_ENABLED) {
100                            AntivirusScannerUtil.scan(file);
101                    }
102    
103                    store.addFile(companyId, repositoryId, fileName, file);
104            }
105    
106            @Override
107            public void addFile(
108                            long companyId, long repositoryId, String fileName,
109                            boolean validateFileExtension, InputStream is)
110                    throws PortalException, SystemException {
111    
112                    if (is instanceof ByteArrayFileInputStream) {
113                            ByteArrayFileInputStream byteArrayFileInputStream =
114                                    (ByteArrayFileInputStream)is;
115    
116                            File file = byteArrayFileInputStream.getFile();
117    
118                            addFile(
119                                    companyId, repositoryId, fileName, validateFileExtension, file);
120    
121                            return;
122                    }
123    
124                    validate(fileName, validateFileExtension, is);
125    
126                    if (!PropsValues.DL_STORE_ANTIVIRUS_ENABLED ||
127                            !AntivirusScannerUtil.isActive()) {
128    
129                            store.addFile(companyId, repositoryId, fileName, is);
130                    }
131                    else {
132                            File tempFile = null;
133    
134                            try {
135                                    if (is.markSupported()) {
136                                            is.mark(is.available() + 1);
137    
138                                            AntivirusScannerUtil.scan(is);
139    
140                                            is.reset();
141    
142                                            store.addFile(companyId, repositoryId, fileName, is);
143                                    }
144                                    else {
145                                            tempFile = FileUtil.createTempFile();
146    
147                                            FileUtil.write(tempFile, is);
148    
149                                            AntivirusScannerUtil.scan(tempFile);
150    
151                                            store.addFile(companyId, repositoryId, fileName, tempFile);
152                                    }
153                            }
154                            catch (IOException ioe) {
155                                    throw new SystemException(
156                                            "Unable to scan file " + fileName, ioe);
157                            }
158                            finally {
159                                    if (tempFile != null) {
160                                            tempFile.delete();
161                                    }
162                            }
163                    }
164            }
165    
166            @Override
167            public void addFile(
168                            long companyId, long repositoryId, String fileName, byte[] bytes)
169                    throws PortalException, SystemException {
170    
171                    addFile(companyId, repositoryId, fileName, true, bytes);
172            }
173    
174            @Override
175            public void addFile(
176                            long companyId, long repositoryId, String fileName, File file)
177                    throws PortalException, SystemException {
178    
179                    addFile(companyId, repositoryId, fileName, true, file);
180            }
181    
182            @Override
183            public void addFile(
184                            long companyId, long repositoryId, String fileName, InputStream is)
185                    throws PortalException, SystemException {
186    
187                    addFile(companyId, repositoryId, fileName, true, is);
188            }
189    
190            @Override
191            public void checkRoot(long companyId) throws SystemException {
192                    store.checkRoot(companyId);
193            }
194    
195            @Override
196            public void copyFileVersion(
197                            long companyId, long repositoryId, String fileName,
198                            String fromVersionLabel, String toVersionLabel)
199                    throws PortalException, SystemException {
200    
201                    store.copyFileVersion(
202                            companyId, repositoryId, fileName, fromVersionLabel,
203                            toVersionLabel);
204            }
205    
206            @Override
207            public void deleteDirectory(
208                            long companyId, long repositoryId, String dirName)
209                    throws PortalException, SystemException {
210    
211                    store.deleteDirectory(companyId, repositoryId, dirName);
212            }
213    
214            @Override
215            public void deleteFile(long companyId, long repositoryId, String fileName)
216                    throws PortalException, SystemException {
217    
218                    validate(fileName, false);
219    
220                    store.deleteFile(companyId, repositoryId, fileName);
221            }
222    
223            @Override
224            public void deleteFile(
225                            long companyId, long repositoryId, String fileName,
226                            String versionLabel)
227                    throws PortalException, SystemException {
228    
229                    validate(fileName, false);
230    
231                    store.deleteFile(companyId, repositoryId, fileName, versionLabel);
232            }
233    
234            @Override
235            public File getFile(long companyId, long repositoryId, String fileName)
236                    throws PortalException, SystemException {
237    
238                    validate(fileName, false);
239    
240                    return store.getFile(companyId, repositoryId, fileName);
241            }
242    
243            @Override
244            public File getFile(
245                            long companyId, long repositoryId, String fileName,
246                            String versionLabel)
247                    throws PortalException, SystemException {
248    
249                    validate(fileName, false);
250    
251                    return store.getFile(companyId, repositoryId, fileName, versionLabel);
252            }
253    
254            @Override
255            public byte[] getFileAsBytes(
256                            long companyId, long repositoryId, String fileName)
257                    throws PortalException, SystemException {
258    
259                    validate(fileName, false);
260    
261                    return store.getFileAsBytes(companyId, repositoryId, fileName);
262            }
263    
264            @Override
265            public byte[] getFileAsBytes(
266                            long companyId, long repositoryId, String fileName,
267                            String versionLabel)
268                    throws PortalException, SystemException {
269    
270                    validate(fileName, false);
271    
272                    return store.getFileAsBytes(
273                            companyId, repositoryId, fileName, versionLabel);
274            }
275    
276            @Override
277            public InputStream getFileAsStream(
278                            long companyId, long repositoryId, String fileName)
279                    throws PortalException, SystemException {
280    
281                    validate(fileName, false);
282    
283                    return store.getFileAsStream(companyId, repositoryId, fileName);
284            }
285    
286            @Override
287            public InputStream getFileAsStream(
288                            long companyId, long repositoryId, String fileName,
289                            String versionLabel)
290                    throws PortalException, SystemException {
291    
292                    validate(fileName, false);
293    
294                    return store.getFileAsStream(
295                            companyId, repositoryId, fileName, versionLabel);
296            }
297    
298            @Override
299            public String[] getFileNames(
300                            long companyId, long repositoryId, String dirName)
301                    throws PortalException, SystemException {
302    
303                    if (!isValidName(dirName)) {
304                            throw new DirectoryNameException(dirName);
305                    }
306    
307                    return store.getFileNames(companyId, repositoryId, dirName);
308            }
309    
310            @Override
311            public long getFileSize(long companyId, long repositoryId, String fileName)
312                    throws PortalException, SystemException {
313    
314                    validate(fileName, false);
315    
316                    return store.getFileSize(companyId, repositoryId, fileName);
317            }
318    
319            @Override
320            public boolean hasDirectory(
321                            long companyId, long repositoryId, String dirName)
322                    throws PortalException, SystemException {
323    
324                    if (!isValidName(dirName)) {
325                            throw new DirectoryNameException(dirName);
326                    }
327    
328                    return store.hasDirectory(companyId, repositoryId, dirName);
329            }
330    
331            @Override
332            public boolean hasFile(long companyId, long repositoryId, String fileName)
333                    throws PortalException, SystemException {
334    
335                    validate(fileName, false);
336    
337                    return store.hasFile(companyId, repositoryId, fileName);
338            }
339    
340            @Override
341            public boolean hasFile(
342                            long companyId, long repositoryId, String fileName,
343                            String versionLabel)
344                    throws PortalException, SystemException {
345    
346                    validate(fileName, false);
347    
348                    return store.hasFile(companyId, repositoryId, fileName, versionLabel);
349            }
350    
351            @Override
352            public void move(String srcDir, String destDir) throws SystemException {
353                    store.move(srcDir, destDir);
354            }
355    
356            public Hits search(
357                            long companyId, long userId, String portletId, long groupId,
358                            long[] repositoryIds, String keywords, int start, int end)
359                    throws SystemException {
360    
361                    try {
362                            SearchContext searchContext = new SearchContext();
363    
364                            searchContext.setCompanyId(companyId);
365                            searchContext.setEnd(end);
366                            searchContext.setEntryClassNames(
367                                    new String[] {DLFileEntryConstants.getClassName()});
368                            searchContext.setGroupIds(new long[] {groupId});
369    
370                            Indexer indexer = IndexerRegistryUtil.getIndexer(
371                                    DLFileEntryConstants.getClassName());
372    
373                            searchContext.setSearchEngineId(indexer.getSearchEngineId());
374    
375                            searchContext.setStart(start);
376                            searchContext.setUserId(userId);
377    
378                            BooleanQuery contextQuery = BooleanQueryFactoryUtil.create(
379                                    searchContext);
380    
381                            contextQuery.addRequiredTerm(Field.PORTLET_ID, portletId);
382    
383                            if (groupId > 0) {
384                                    Group group = groupLocalService.getGroup(groupId);
385    
386                                    if (group.isLayout()) {
387                                            contextQuery.addRequiredTerm(Field.SCOPE_GROUP_ID, groupId);
388    
389                                            groupId = group.getParentGroupId();
390                                    }
391    
392                                    contextQuery.addRequiredTerm(Field.GROUP_ID, groupId);
393                            }
394    
395                            if ((repositoryIds != null) && (repositoryIds.length > 0)) {
396                                    BooleanQuery repositoryIdsQuery =
397                                            BooleanQueryFactoryUtil.create(searchContext);
398    
399                                    for (long repositoryId : repositoryIds) {
400                                            try {
401                                                    if (userId > 0) {
402                                                            PermissionChecker permissionChecker =
403                                                                    PermissionThreadLocal.getPermissionChecker();
404    
405                                                            DLFolderPermission.check(
406                                                                    permissionChecker, groupId, repositoryId,
407                                                                    ActionKeys.VIEW);
408                                                    }
409    
410                                                    if (repositoryId ==
411                                                                    DLFolderConstants.DEFAULT_PARENT_FOLDER_ID) {
412    
413                                                            repositoryId = groupId;
414                                                    }
415    
416                                                    TermQuery termQuery = TermQueryFactoryUtil.create(
417                                                            searchContext, "repositoryId", repositoryId);
418    
419                                                    repositoryIdsQuery.add(
420                                                            termQuery, BooleanClauseOccur.SHOULD);
421                                            }
422                                            catch (Exception e) {
423                                            }
424                                    }
425    
426                                    contextQuery.add(repositoryIdsQuery, BooleanClauseOccur.MUST);
427                            }
428    
429                            BooleanQuery searchQuery = BooleanQueryFactoryUtil.create(
430                                    searchContext);
431    
432                            searchQuery.addTerms(_KEYWORDS_FIELDS, keywords);
433    
434                            BooleanQuery fullQuery = BooleanQueryFactoryUtil.create(
435                                    searchContext);
436    
437                            fullQuery.add(contextQuery, BooleanClauseOccur.MUST);
438    
439                            if (searchQuery.clauses().size() > 0) {
440                                    fullQuery.add(searchQuery, BooleanClauseOccur.MUST);
441                            }
442    
443                            return SearchEngineUtil.search(searchContext, fullQuery);
444                    }
445                    catch (Exception e) {
446                            throw new SystemException(e);
447                    }
448            }
449    
450            @Override
451            public void updateFile(
452                            long companyId, long repositoryId, long newRepositoryId,
453                            String fileName)
454                    throws PortalException, SystemException {
455    
456                    store.updateFile(companyId, repositoryId, newRepositoryId, fileName);
457            }
458    
459            @Override
460            public void updateFile(
461                            long companyId, long repositoryId, String fileName,
462                            String newFileName)
463                    throws PortalException, SystemException {
464    
465                    store.updateFile(companyId, repositoryId, fileName, newFileName);
466            }
467    
468            @Override
469            public void updateFile(
470                            long companyId, long repositoryId, String fileName,
471                            String fileExtension, boolean validateFileExtension,
472                            String versionLabel, String sourceFileName, File file)
473                    throws PortalException, SystemException {
474    
475                    validate(
476                            fileName, fileExtension, sourceFileName, validateFileExtension,
477                            file);
478    
479                    if (PropsValues.DL_STORE_ANTIVIRUS_ENABLED) {
480                            AntivirusScannerUtil.scan(file);
481                    }
482    
483                    store.updateFile(companyId, repositoryId, fileName, versionLabel, file);
484            }
485    
486            @Override
487            public void updateFile(
488                            long companyId, long repositoryId, String fileName,
489                            String fileExtension, boolean validateFileExtension,
490                            String versionLabel, String sourceFileName, InputStream is)
491                    throws PortalException, SystemException {
492    
493                    if (is instanceof ByteArrayFileInputStream) {
494                            ByteArrayFileInputStream byteArrayFileInputStream =
495                                    (ByteArrayFileInputStream)is;
496    
497                            File file = byteArrayFileInputStream.getFile();
498    
499                            updateFile(
500                                    companyId, repositoryId, fileName, fileExtension,
501                                    validateFileExtension, versionLabel, sourceFileName, file);
502    
503                            return;
504                    }
505    
506                    validate(
507                            fileName, fileExtension, sourceFileName, validateFileExtension, is);
508    
509                    if (!PropsValues.DL_STORE_ANTIVIRUS_ENABLED ||
510                            !AntivirusScannerUtil.isActive()) {
511    
512                            store.updateFile(
513                                    companyId, repositoryId, fileName, versionLabel, is);
514                    }
515                    else {
516                            File tempFile = null;
517    
518                            try {
519                                    if (is.markSupported()) {
520                                            is.mark(is.available() + 1);
521    
522                                            AntivirusScannerUtil.scan(is);
523    
524                                            is.reset();
525    
526                                            store.updateFile(
527                                                    companyId, repositoryId, fileName, versionLabel, is);
528                                    }
529                                    else {
530                                            tempFile = FileUtil.createTempFile();
531    
532                                            FileUtil.write(tempFile, is);
533    
534                                            AntivirusScannerUtil.scan(tempFile);
535    
536                                            store.updateFile(
537                                                    companyId, repositoryId, fileName, versionLabel,
538                                                    tempFile);
539                                    }
540                            }
541                            catch (IOException ioe) {
542                                    throw new SystemException(
543                                            "Unable to scan file " + fileName, ioe);
544                            }
545                            finally {
546                                    if (tempFile != null) {
547                                            tempFile.delete();
548                                    }
549                            }
550                    }
551            }
552    
553            @Override
554            public void updateFileVersion(
555                            long companyId, long repositoryId, String fileName,
556                            String fromVersionLabel, String toVersionLabel)
557                    throws PortalException, SystemException {
558    
559                    store.updateFileVersion(
560                            companyId, repositoryId, fileName, fromVersionLabel,
561                            toVersionLabel);
562            }
563    
564            @Override
565            public void validate(String fileName, boolean validateFileExtension)
566                    throws PortalException, SystemException {
567    
568                    if (!isValidName(fileName)) {
569                            throw new FileNameException(fileName);
570                    }
571    
572                    if (validateFileExtension) {
573                            boolean validFileExtension = false;
574    
575                            String[] fileExtensions = PrefsPropsUtil.getStringArray(
576                                    PropsKeys.DL_FILE_EXTENSIONS, StringPool.COMMA);
577    
578                            for (String fileExtension : fileExtensions) {
579                                    if (StringPool.STAR.equals(fileExtension) ||
580                                            StringUtil.endsWith(fileName, fileExtension)) {
581    
582                                            validFileExtension = true;
583    
584                                            break;
585                                    }
586                            }
587    
588                            if (!validFileExtension) {
589                                    throw new FileExtensionException(fileName);
590                            }
591                    }
592            }
593    
594            @Override
595            public void validate(
596                            String fileName, boolean validateFileExtension, byte[] bytes)
597                    throws PortalException, SystemException {
598    
599                    validate(fileName, validateFileExtension);
600    
601                    if ((PrefsPropsUtil.getLong(PropsKeys.DL_FILE_MAX_SIZE) > 0) &&
602                            ((bytes == null) ||
603                             (bytes.length >
604                                     PrefsPropsUtil.getLong(PropsKeys.DL_FILE_MAX_SIZE)))) {
605    
606                            throw new FileSizeException(fileName);
607                    }
608            }
609    
610            @Override
611            public void validate(
612                            String fileName, boolean validateFileExtension, File file)
613                    throws PortalException, SystemException {
614    
615                    validate(fileName, validateFileExtension);
616    
617                    if ((PrefsPropsUtil.getLong(PropsKeys.DL_FILE_MAX_SIZE) > 0) &&
618                            ((file == null) ||
619                             (file.length() >
620                                    PrefsPropsUtil.getLong(PropsKeys.DL_FILE_MAX_SIZE)))) {
621    
622                            throw new FileSizeException(fileName);
623                    }
624            }
625    
626            @Override
627            public void validate(
628                            String fileName, boolean validateFileExtension, InputStream is)
629                    throws PortalException, SystemException {
630    
631                    validate(fileName, validateFileExtension);
632    
633                    // LEP-4851
634    
635                    try {
636                            if ((is == null) ||
637                                    ((PrefsPropsUtil.getLong(PropsKeys.DL_FILE_MAX_SIZE) > 0) &&
638                                     (is.available() >
639                                            PrefsPropsUtil.getLong(PropsKeys.DL_FILE_MAX_SIZE)))) {
640    
641                                    throw new FileSizeException(fileName);
642                            }
643                    }
644                    catch (IOException ioe) {
645                            throw new FileSizeException(ioe.getMessage());
646                    }
647            }
648    
649            @Override
650            public void validate(
651                            String fileName, String fileExtension, String sourceFileName,
652                            boolean validateFileExtension, File file)
653                    throws PortalException, SystemException {
654    
655                    validate(
656                            fileName, fileExtension, sourceFileName, validateFileExtension);
657    
658                    if ((file != null) &&
659                            (PrefsPropsUtil.getLong(PropsKeys.DL_FILE_MAX_SIZE) > 0) &&
660                            (file.length() >
661                                    PrefsPropsUtil.getLong(PropsKeys.DL_FILE_MAX_SIZE))) {
662    
663                            throw new FileSizeException(fileName);
664                    }
665            }
666    
667            @Override
668            public void validate(
669                            String fileName, String fileExtension, String sourceFileName,
670                            boolean validateFileExtension, InputStream is)
671                    throws PortalException, SystemException {
672    
673                    validate(
674                            fileName, fileExtension, sourceFileName, validateFileExtension);
675    
676                    try {
677                            if ((is != null) &&
678                                    (PrefsPropsUtil.getLong(PropsKeys.DL_FILE_MAX_SIZE) > 0) &&
679                                    (is.available() >
680                                            PrefsPropsUtil.getLong(PropsKeys.DL_FILE_MAX_SIZE))) {
681    
682                                    throw new FileSizeException(fileName);
683                            }
684                    }
685                    catch (IOException ioe) {
686                            throw new FileSizeException(ioe.getMessage());
687                    }
688            }
689    
690            protected boolean isValidName(String name) {
691                    if ((name == null) ||
692                            name.contains("\\") ||
693                            name.contains("\\\\") ||
694                            name.contains("//") ||
695                            name.contains(":") ||
696                            name.contains("*") ||
697                            name.contains("?") ||
698                            name.contains("\"") ||
699                            name.contains("<") ||
700                            name.contains(">") ||
701                            name.contains("|") ||
702                            name.contains("[") ||
703                            name.contains("]") ||
704                            name.contains("../") ||
705                            name.contains("/..")) {
706    
707                            return false;
708                    }
709    
710                    return true;
711            }
712    
713            protected void validate(
714                            String fileName, String fileExtension, String sourceFileName,
715                            boolean validateFileExtension)
716                    throws PortalException, SystemException {
717    
718                    String sourceFileExtension = FileUtil.getExtension(sourceFileName);
719    
720                    if (Validator.isNotNull(sourceFileName) &&
721                            PropsValues.DL_FILE_EXTENSIONS_STRICT_CHECK &&
722                            !fileExtension.equals(sourceFileExtension)) {
723    
724                            throw new SourceFileNameException(sourceFileExtension);
725                    }
726    
727                    validate(fileName, validateFileExtension);
728            }
729    
730            @BeanReference(type = GroupLocalService.class)
731            protected GroupLocalService groupLocalService;
732    
733            @BeanReference(type = Store.class)
734            protected Store store;
735    
736            private static final String[] _KEYWORDS_FIELDS = {
737                    Field.ASSET_TAG_NAMES, Field.CONTENT, Field.PROPERTIES
738            };
739    
740    }