/* * This file is a part of Winix * and is distributed under the 2-Clause BSD licence. * Author: Tomasz Sowa */ /* * Copyright (c) 2008-2021, Tomasz Sowa * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: * * 1. Redistributions of source code must retain the above copyright notice, * this list of conditions and the following disclaimer. * * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE * POSSIBILITY OF SUCH DAMAGE. * */ #include #include #include #include #include "upload.h" #include "core/misc.h" #include "functions/functions.h" #include "templates/templates.h" #include "utf8/utf8.h" namespace Winix { namespace Fun { Upload::Upload() { fun.url = L"upload"; } void Upload::Init() { } void Upload::Finish() { CloseMagicLib(); } bool Upload::HasAccess(const Item & item) { // you can use 'upload' only in a directory if( item.type != Item::dir ) return false; if( config->upload_dir.empty() ) { log << log1 << "Request: can't use upload function, upload_dir must be set in the config file" << logend; return false; } if( cur->session->puser && cur->session->puser->is_super_user ) // super user can use upload everywhere return true; if( !system->HasWriteAccess(item) ) return false; return true; } bool Upload::HasAccess() { if( cur->request->is_item || !HasAccess(*cur->request->dir_tab.back()) ) return false; return true; } bool Upload::UploadSaveStaticFile(const Item & item, const std::wstring & tmp_filename) { if( !system->MakeFilePath(item, path, false, true, config->upload_dirs_chmod, config->upload_group_int) ) { cur->request->status = WINIX_ERR_PERMISSION_DENIED; return false; } if( RenameFile(tmp_filename, path) ) { if( !SetPriv(path, config->upload_files_chmod, config->upload_group_int) ) { cur->request->status = WINIX_ERR_PERMISSION_DENIED; return false; } log << log2 << "Upload: uploaded a new file: " << path << logend; return true; } else { log << log1 << "Upload: can't move the tmp file from: " << tmp_filename << ", to: " << path << logend; cur->request->status = WINIX_ERR_PERMISSION_DENIED; return false; } } void Upload::ResizeImage(Item & item) { Image::Scale scale = system->image.GetImageScale(item.parent_id); system->image.Resize(item.id, scale.cx, scale.cy, scale.aspect_mode, scale.quality); } void Upload::CreateThumb(Item & item) { Image::Scale scale = system->image.GetThumbScale(item.parent_id); system->image.CreateThumb(item.id, scale.cx, scale.cy, scale.aspect_mode, scale.quality); } void Upload::UploadFile(Item & item, const std::wstring & tmp_filename) { // we should add the file beforehand to get the proper item.id cur->request->status = WINIX_ERR_PERMISSION_DENIED; bool status = system->AddFile(item, 0, false); if( status ) { if( system->CreateNewFile(item) ) { if( UploadSaveStaticFile(item, tmp_filename) ) { ItemModelData item_model_data; item_model_data.prepare_unique_url = false; //cur->request->status = db->EditFileById(item, item.id); if( item.update(item_model_data) ) { cur->request->status = WINIX_ERR_OK; plugin->Call(WINIX_FILE_ADDED, &item); if( item.item_content.file_type == WINIX_ITEM_FILETYPE_IMAGE ) { if( config->image_resize ) ResizeImage(item); if( config->create_thumb ) CreateThumb(item); } if( is_jquery_upload ) cur->request->item_tab.push_back(item); } } else { item.remove(); //db->DelItem(item); } } } } bool Upload::FunUploadCheckAbuse() { if( !system->rebus.CheckRebus() ) { cur->request->status = WINIX_ERR_INCORRECT_REBUS; return false; } functions->CheckGetPostTimes(4); if( cur->session->spam_score > 0 ) { cur->request->status = WINIX_ERR_SPAM; log << log1 << "Content: ignoring due to suspected spamming" << logend; return false; } return true; } void Upload::UploadMulti() { cur->request->item.Clear(); // clearing and setting date cur->request->item.parent_id = cur->request->dir_tab.back()->id; cur->request->item.type = Item::file; cur->request->item.item_content.privileges = system->NewFilePrivileges(); functions->SetUser(cur->request->item); PostFileTab::iterator i = cur->request->post_file_tab.begin(); for( ; i != cur->request->post_file_tab.end() ; ++i) { const wchar_t * file_name = i->second.filename.c_str(); cur->request->item.subject = file_name; cur->request->item.url = file_name; cur->request->item.item_content.file_type = SelectFileType(file_name); cur->request->item.item_content.file_size = i->second.file_size; functions->PrepareUrl(cur->request->item); AnalizeFileType(i->second.tmp_filename, cur->request->item.item_content.file_mime_type); UploadFile(cur->request->item, i->second.tmp_filename); i->second.tmp_filename.clear(); } if( is_jquery_upload ) CreateAnswer(); else system->RedirectToLastDir(); } void Upload::UploadSingle() { cur->request->item.Clear(); // clearing and setting date const std::wstring & new_subject = cur->request->PostVar(L"subject"); const std::wstring & new_url = cur->request->PostVar(L"url"); bool has_subject = !new_subject.empty(); bool has_url = !new_url.empty(); functions->ReadItem(cur->request->item, Item::file); // ReadItem() changes the url if it is empty functions->SetUser(cur->request->item); cur->request->item.item_content.privileges = system->NewFilePrivileges(); PostFile & post_file = cur->request->post_file_tab.begin()->second; const wchar_t * file_name = post_file.filename.c_str(); cur->request->item.item_content.file_type = SelectFileType(file_name); cur->request->item.item_content.file_size = post_file.file_size; if( !has_subject ) cur->request->item.subject = file_name; if( !has_url ) { cur->request->item.url = file_name; functions->PrepareUrl(cur->request->item); } AnalizeFileType(post_file.tmp_filename, cur->request->item.item_content.file_mime_type); UploadFile(cur->request->item, post_file.tmp_filename); post_file.tmp_filename.clear(); if( is_jquery_upload ) CreateAnswer(); else if( cur->request->status == WINIX_ERR_OK ) system->RedirectTo(cur->request->item, L"/cat"); } void Upload::InitMagicLibIfNeeded() { if( !magic_cookie ) { log << log3 << "Upload: loading magic library" << logend; magic_cookie = magic_open(MAGIC_MIME_TYPE); if( magic_cookie ) { if( magic_load(magic_cookie, nullptr) < 0 ) { log << log1 << "Upload: I cannot load the magic file, magic_load failed"; const char * err = magic_error(magic_cookie); if( err ) { log << ", error: " << err; } log << logend; CloseMagicLib(); } } else { log << log1 << "Upload: I cannot initialize magic library, magic_open failed" << logend; } } } void Upload::CloseMagicLib() { if( magic_cookie ) { log << log3 << "Upload: closing magic library" << logend; magic_close(magic_cookie); magic_cookie = nullptr; } } void Upload::AnalizeFileType(const std::wstring & file_path, std::wstring & file_type) { file_type.clear(); if( magic_cookie ) { std::string file; pt::wide_to_utf8(file_path, file); log << log3 << "Upload: analize file: " << file; const char * magic_file_type = magic_file(magic_cookie, file.c_str()); if( magic_file_type ) { log << ", mime type is: " << magic_file_type << logend; pt::utf8_to_wide(magic_file_type, file_type); } else { log << logend << log1 << "Upload: I cannot analize file: " << file << ", magic_file failed"; const char * err = magic_error(magic_cookie); if( err ) { log << ", error: " << err; } log << logend; } } else { log << log1 << "Upload: magic library not initialized" << logend; } } void Upload::MakePost() { InitMagicLibIfNeeded(); cur->request->item_tab.clear(); is_jquery_upload = cur->request->IsParam(L"jquery_upload"); if( cur->request->post_file_tab.empty() ) { cur->request->status = WINIX_ERR_PERMISSION_DENIED; return; } if( !FunUploadCheckAbuse() ) return; if( cur->request->post_file_tab.size() > 1 ) UploadMulti(); else UploadSingle(); } void Upload::CreateAnswer() { Request & req = *cur->request; for(size_t i=0 ; iCreateItemLink(req.item_tab[i], link); file.add(L"url", link); std::wstring delete_url = link; delete_url += L"/rm/jquery_upload/container:json/answer:data"; file.add(L"deleteUrl", delete_url); file.add(L"deleteType", L"POST"); if( req.item_tab[i].item_content.file_type == WINIX_ITEM_FILETYPE_IMAGE ) { std::wstring thumb = link; if( req.item_tab[i].item_content.file_has_thumb ) thumb += L"/-/thumb"; file.add(L"thumbnailUrl", thumb); } /* * if there was an error add "error" item e.g. * "error": "Filetype not allowed" */ } cur->request->models.Add(L"files", files); } void Upload::MakeGet() { if( cur->request->IsParam(L"jquery_upload") ) { // query.Clear(); // query.WhereParentId(cur->request->dir_tab.back()->id); // query.WhereType(Item::file); // query.WhereFileType(WINIX_ITEM_FILETYPE_NONE, false); morm::Finder finder(model_connector); finder. select(). where(). eq(L"parent_id", cur->request->dir_tab.back()->id). eq(L"type", static_cast(Item::file)). neq(L"content", L"file_type", WINIX_ITEM_FILETYPE_NONE). get_vector(cur->request->item_tab); //db->GetItems(cur->request->item_tab, query); CreateAnswer(); } } void Upload::Clear() { files.clear(); } } // namespace } // namespace Winix