index : flyspray | |
Archlinux32 customized Flyspray installation | gitolite user |
summaryrefslogtreecommitdiff |
author | Andreas Baumann <mail@andreasbaumann.cc> | 2020-02-01 09:05:48 +0100 |
---|---|---|
committer | Andreas Baumann <mail@andreasbaumann.cc> | 2020-02-01 09:05:48 +0100 |
commit | 6854cb3f4d8219cf1829e32122eb2502a916eae9 (patch) | |
tree | 350feb504587d932e02837a1442b059759927646 /index.php |
-rw-r--r-- | index.php | 275 |
diff --git a/index.php b/index.php new file mode 100644 index 0000000..c94f545 --- /dev/null +++ b/index.php @@ -0,0 +1,275 @@ +<?php +/* + This is the main script that everything else is included + in. Mostly what it does is check the user permissions + to see what they have access to. +*/ +define('IN_FS', true); + +require_once(dirname(__FILE__).'/header.php'); + +// Get available do-modes +$modes = str_replace('.php', '', array_map('basename', glob_compat(BASEDIR ."/scripts/*.php"))); + +$do = Req::enum('do', $modes, $proj->prefs['default_entry']); + +if ($do == 'admin' && Req::has('switch') && Req::val('project') != '0') { + $do = 'pm'; +} elseif ($do == 'pm' && Req::has('switch') && Req::val('project') == '0') { + $do = 'admin'; +} elseif (Req::has('show') || (Req::has('switch') && $do == 'details') + || ($do == 'newtask' && Req::val('project') == '0')) { + $do = 'index'; +} elseif (Req::has('code')) { + $_SESSION['oauth_provider'] = 'microsoft'; + $do = 'oauth'; +} elseif( Req::has('do') && Req::val('do') == 'tasklist') { + $do='index'; +} + +// supertask_id for add new sub-task +$supertask_id = 0; +if (Req::has('supertask')) { + $supertask_id = Req::val('supertask'); +} + + +/* permission stuff */ +if (Cookie::has('flyspray_userid') && Cookie::has('flyspray_passhash')) { + $user = new User(Cookie::val('flyspray_userid'), $proj); + $user->check_account_ok(); + $user->save_search($do); +} else { + $user = new User(0, $proj); +} + + +if (Get::val('getfile')) { + // If a file was requested, deliver it + $result = $db->query("SELECT t.project_id, + a.orig_name, a.file_name, a.file_type, t.* + FROM {attachments} a + INNER JOIN {tasks} t ON a.task_id = t.task_id + WHERE attachment_id = ?", array(Get::val('getfile'))); + $task = $db->fetchRow($result); + list($proj_id, $orig_name, $file_name, $file_type) = $task; + + // Check if file exists, and user permission to access it! + if (!is_file(BASEDIR . "/attachments/$file_name")) { + header('HTTP/1.1 410 Gone'); + echo 'File does not exist anymore.'; + exit(); + } + + if($user->can_view_task($task)){ + $path = BASEDIR . "/attachments/$file_name"; + $csp->emit(); # only default-src 'none' + + header("Content-type: $file_type"); + # image view/download difference + if(isset($_GET['dl'])){ + header('Content-Disposition: attachment; filename="'.$orig_name.'"'); + }else{ + header('Content-Disposition: filename="'.$orig_name.'"'); + } + + header('Content-transfer-encoding: binary'); + header('Content-length: ' . filesize($path)); + + readfile($path); + exit(); + }else{ + Flyspray::show_error(1); + } + exit; +} + +// Load translations +load_translations(); + +/*******************************************************************************/ +/* Here begins the deep flyspray : html rendering */ +/*******************************************************************************/ +# no cache headers are now in header.php! + +// see http://www.w3.org/TR/html401/present/styles.html#h-14.2.1 +header('Content-Style-Type: text/css'); +header('Content-type: text/html; charset=utf-8'); + +$csp->add('img-src', "'self'"); +# a bit unsure if * is ok (data: http: https:) +#$csp->add('img-src', "*"); +$csp->add('font-src', "'self'"); +$csp->add('style-src', "'self'"); +$csp->add('style-src', "'unsafe-inline'"); +$csp->add('script-src', "'self'"); +$csp->add('script-src', "'unsafe-inline'"); +$csp->add('connect-src', "'self'"); + +if(isset($conf['general']['syntax_plugin']) && $conf['general']['syntax_plugin']=='dokuwiki'){ + # unsafe-eval for tabs.js :-/ (can be replaced by a css only solution) + $csp->add('script-src', "'unsafe-eval'"); +} else{ + # unsafe-eval for tabs.js and flyspray's version of ckeditor :-/ + $csp->add('script-src', "'unsafe-eval'"); +} + +# maybe a future 'beforehttpheader' event position for extension/plugins to add their own exceptions/modifications +if(isset($fs->prefs['gravatars']) && $fs->prefs['gravatars'] == 1){ + $csp->add('img-src', 'www.gravatar.com'); +} + +# example calculation .. +if($user->isAnon()){ + $needcaptcha=1; +} +if(isset($needcaptcha) && $needcaptcha && isset($fs->prefs['captcha_recaptcha']) && $fs->prefs['captcha_recaptcha']==1){ + $csp->add('script-src', 'https://www.google.com/recaptcha/'); + $csp->add('script-src', 'https://www.gstatic.com/recaptcha/'); + $csp->add('frame-src', 'https://www.google.com/recaptcha/'); + $csp->add('style-src', "'unsafe-inline'"); # currently redundant, but handled ok by ContentSecurityPolicy::get() method. +} + +$csp->emit(); +#echo $csp->get(); # debug +#print_r($csp); # debug + +if ($conf['general']['output_buffering'] == 'gzip' && extension_loaded('zlib')) +{ + // Start Output Buffering and gzip encoding if setting is present. + ob_start('ob_gzhandler'); +} else { + ob_start(); +} + +$page = new FSTpl(); + +// make sure people are not attempting to manually fiddle with projects they are not allowed to play with +if (Req::has('project') && Req::val('project') != 0 && !$user->can_select_project(Req::val('project'))) { + Flyspray::show_error( L('nopermission') ); + Flyspray::redirect($baseurl); + exit; +} + +if ($show_task = Get::val('show_task')) { + // If someone used the 'show task' form, redirect them + if (is_numeric($show_task)) { + Flyspray::redirect( createURL('details', $show_task) ); + } else { + Flyspray::redirect( $baseurl . '?string=' . $show_task); + } +} + +if (Flyspray::requestDuplicated()) { + // Check that this page isn't being submitted twice + Flyspray::show_error(3); +} + +# handle all forms request that modify data + +if (Req::has('action')) { + # enforcing if the form sent the correct anti csrf token + # only allow token by post + if( !Post::has('csrftoken') ){ + die('missingtoken'); + }elseif( Post::val('csrftoken')==$_SESSION['csrftoken']){ + require_once(BASEDIR . '/includes/modify.inc.php'); + }else{ + die('wrongtoken'); + } +} + +# start collecting infos for the answer page + +if ($proj->id && $user->perms('manage_project')) { + // Find out if there are any PM requests wanting attention + $sql = $db->query( + 'SELECT COUNT(*) FROM {admin_requests} WHERE project_id = ? AND resolved_by = 0', + array($proj->id)); + list($count) = $db->fetchRow($sql); + + $page->assign('pm_pendingreq_num', $count); +} +if ($user->perms('is_admin')) { + $sql = $db->query( + 'SELECT COUNT(*) FROM {admin_requests} WHERE request_type = 3 AND project_id = 0 AND resolved_by = 0'); + list($count) = $db->fetchRow($sql); + $page->assign('admin_pendingreq_num', $count); +} + +# a bit hacky: First 3 MUST be project_id, project_title, project_is_active in this order! +# This first 3 indexes are used by tpl_options currently.. +# removed upper(project_title) for sorting, should be handled by database collation (utf8_general_ci) +$sql = $db->query(' + SELECT project_id, project_title, project_is_active, others_view, default_entry + FROM {projects} + ORDER BY project_is_active DESC, project_title' +); + +# new: project_id as index for easier access, needs testing and maybe simplification +# similiar situation also includes/class.flyspray.php function listProjects() +$sres=$db->fetchAllArray($sql); +foreach($sres as $p){ + $prs[$p['project_id']]=$p; +} +$fs->projects = array_filter($prs, array($user, 'can_select_project')); + + +// Get e-mail addresses of the admins +if ($user->isAnon() && !$fs->prefs['user_notify']) { + $sql = $db->query('SELECT email_address + FROM {users} u + LEFT JOIN {users_in_groups} g ON u.user_id = g.user_id + WHERE g.group_id = 1'); + $page->assign('admin_emails', array_map(function($x) { return str_replace("@", "#", $x); }, $db->fetchCol($sql))); +} + +// title tag +if( $user->can_select_project($proj->id)){ + $page->setTitle($fs->prefs['page_title'] . $proj->prefs['project_title']); +} else{ + $page->setTitle($fs->prefs['page_title']); +} + +$page->assign('do', $do); +$page->assign('supertask_id', $supertask_id); + +$page->pushTpl('header.tpl'); + +if (!defined('NO_DO')) { + require_once(BASEDIR . "/scripts/$do.php"); +} else{ + # not nicest solution, NO_DO currently only used on register actions + $page->pushTpl('register.ok.tpl'); +} + +# 2016-07-29 peterdd: The following 2 optional install wide template assignments will make upgrading a Flyspray installation which needs to be integrated into an existing website a nobrainer in future. +# Because the 2 variables are loaded from flyspray database, there is no need to change the default CleanFS template files and your own CSS style modifications is kept in your custom_*.css +# You can keep stuff like a custom topbar that contains links to a sitewide wiki or CMS or whatever by storing it in flysprays database prefs table. +# Project specific stuff like optional linking to a wiki for a project maybe be handled similiar by the project database table in future. + +# Open questions: Should we treat that as dokuwiki content (if dokuwiki is the 'syntax_plugin')? +# Or even eval it as php-code, which can be dangerous, but gives the most freedom and creativity. +# (For installs where all admin users are real admins of the hosting area, so they know what they are doing. Not intended for SaaS.)? +if(isset($fs->prefs['general_integration'])){ + # adds within the body before the footer div, but could appear as a whole or parts anywhere on the page by due custom CSS styling, for example as top linkbar. + $page->assign('general_integration', $fs->prefs['general_integration']); +} +if(isset($fs->prefs['footer_integration'])){ + # goes within the footer div, but still could appear as a whole or parts anywhere on the page by due custom CSS styling, for example as top linkbar. + $page->assign('footer_integration', $fs->prefs['footer_integration']); +} +# 2016-07-29 end + +$page->pushTpl('footer.tpl'); +$page->setTheme($proj->prefs['theme_style']); +$page->render(); + +if(isset($_SESSION)) { +// remove dupe data on error, since no submission happened + if (isset($_SESSION['ERROR']) && isset($_SESSION['requests_hash'])) { + $currentrequest = md5(serialize($_POST)); + unset($_SESSION['requests_hash'][$currentrequest]); + } + unset($_SESSION['ERROR'], $_SESSION['ERRORS'], $_SESSION['SUCCESS']); +} |