View Issue Details
ID | Project | Category | View Status | Date Submitted | Last Update |
---|---|---|---|---|---|
0011250 | mantisbt | authentication | public | 2009-12-02 15:53 | 2018-04-10 17:05 |
Reporter | gthomas | Assigned To | dregad | ||
Priority | normal | Severity | feature | Reproducibility | always |
Status | closed | Resolution | won't fix | ||
Product Version | 1.2.0rc2 | ||||
Summary | 0011250: Allow SHA1 passwords | ||||
Description | For migrating from roundup I needed to use '{SHA}hex...' passwords. | ||||
Additional Information | Not a big thing, but makes password formats more transparent with the {method} prefix. | ||||
Tags | patch | ||||
Attached Files | mantis-sha_auth_method.patch (1,691 bytes)
diff -r 7c772059daca core/authentication_api.php --- a/core/authentication_api.php Fri Nov 27 13:34:55 2009 +0100 +++ b/core/authentication_api.php Wed Dec 02 21:47:28 2009 +0100 @@ -344,10 +344,21 @@ $t_password = user_get_field( $p_user_id, 'password' ); $t_login_methods = Array( + SHA1, MD5, CRYPT, PLAIN, ); + if( substr($t_password, 0, 1) == '{' && strpos($t_password, '}') > 1 ) { + $t_method = substr( $t_password, 1, strpos($t_password, '}')-1 ); + $t_methods_arr = array('SHA'=>SHA1, 'MD5'=>MD5, 'CRYPT'=>CRYPT, 'PLAIN'=>PLAIN); + if( in_array($t_method, $t_methods_arr) + && in_array($t_methods_arr[$t_method], $t_login_methods) ) { + $t_login_methods = Array($t_methods_arr[$t_method]); + $t_password = substr( $t_password, strlen($t_method)+2 ); + } + } + foreach( $t_login_methods as $t_login_method ) { # pass the stored password in as the salt @@ -404,6 +415,9 @@ case MD5: $t_processed_password = md5( $p_password ); break; + case SHA1: + $t_processed_password = sha1( $p_password ); + break; case BASIC_AUTH: case PLAIN: default: diff -r 7c772059daca core/constant_inc.php --- a/core/constant_inc.php Fri Nov 27 13:34:55 2009 +0100 +++ b/core/constant_inc.php Wed Dec 02 21:47:28 2009 +0100 @@ -134,6 +134,7 @@ define( 'LDAP', 4 ); define( 'BASIC_AUTH', 5 ); define( 'HTTP_AUTH', 6 ); +define( 'SHA1', 7 ); # file upload methods define( 'DISK', 1 ); @@ -552,6 +553,6 @@ # Lengths - NOTE: these may represent hard-coded values in db schema and should not be changed. define( 'USERLEN', 32); define( 'REALLEN', 64); -define( 'PASSLEN', 32); +define( 'PASSLEN', 50); define( 'SECONDS_PER_DAY', 86400 ); sha_password.patch (3,868 bytes)
diff --git a/admin/schema.php b/admin/schema.php index c87f0a6..7951c09 100644 --- a/admin/schema.php +++ b/admin/schema.php @@ -34,7 +34,7 @@ if ( !function_exists( 'db_null_date' ) ) { function installer_db_now() { global $g_db; - + return $g_db->BindTimeStamp( time() ); } @@ -318,7 +318,7 @@ $upgrade[] = Array('CreateTableSQL',Array(db_get_table('user')," username C(32) NOTNULL DEFAULT \" '' \", realname C(64) NOTNULL DEFAULT \" '' \", email C(64) NOTNULL DEFAULT \" '' \", - password C(32) NOTNULL DEFAULT \" '' \", + password C(64) NOTNULL DEFAULT \" '' \", date_created T NOTNULL DEFAULT '" . db_null_date() . "', last_visit T NOTNULL DEFAULT '" . db_null_date() . "', enabled L NOTNULL DEFAULT \" '1' \", @@ -475,7 +475,7 @@ $upgrade[] = Array( 'RenameColumnSQL', Array( db_get_table( 'bugnote' ), "last_m $upgrade[] = Array('CreateIndexSQL',Array('idx_last_mod',db_get_table('bugnote'),'last_modified')); $upgrade[] = Array( 'DropColumnSQL', Array( db_get_table( 'bugnote' ), "date_submitted" ) ); $upgrade[] = Array( 'RenameColumnSQL', Array( db_get_table( 'bugnote' ), "date_submitted_int", "date_submitted", "date_submitted_int I UNSIGNED NOTNULL DEFAULT '1' " ) ); - + $upgrade[] = Array( 'AddColumnSQL', Array( db_get_table( 'bug_file' ), " date_added_int I UNSIGNED NOTNULL DEFAULT '1' " ) ); diff --git a/core/authentication_api.php b/core/authentication_api.php index a90a720..4737828 100644 --- a/core/authentication_api.php +++ b/core/authentication_api.php @@ -345,10 +345,22 @@ function auth_does_password_match( $p_user_id, $p_test_password ) { $t_password = user_get_field( $p_user_id, 'password' ); $t_login_methods = Array( + SHA1, MD5, CRYPT, PLAIN, ); + if( substr($t_password, 0, 1) == '{' && strpos($t_password, '}') > 1 ) { + $t_method = substr( $t_password, 1, strpos($t_password, '}')-1 ); + $t_methods_arr = Array('SHA'=>SHA1, 'MD5'=>MD5, 'CRYPT'=>CRYPT, + 'PLAIN'=>PLAIN); + if( in_array($t_method, $t_methods_arr) + && in_array($t_methods_arr[$t_method], $t_login_methods) ) { + $t_login_methods = Array($t_methods_arr[$t_method]); + $t_password = substr( $t_password, strlen($t_method)+2 ); + } + } + foreach( $t_login_methods as $t_login_method ) { # pass the stored password in as the salt @@ -405,6 +417,9 @@ function auth_does_password_match( $p_user_id, $p_test_password ) { case MD5: $t_processed_password = md5( $p_password ); break; + case SHA1: + $t_processed_password = sha1( $p_password ); + break; case BASIC_AUTH: case PLAIN: default: diff --git a/core/constant_inc.php b/core/constant_inc.php index 7e3e274..3bc1a28 100644 --- a/core/constant_inc.php +++ b/core/constant_inc.php @@ -134,6 +134,7 @@ define( 'MD5', 3 ); define( 'LDAP', 4 ); define( 'BASIC_AUTH', 5 ); define( 'HTTP_AUTH', 6 ); +define( 'SHA1', 7 ); # file upload methods define( 'DISK', 1 ); @@ -552,6 +553,6 @@ define( 'PHPMAILER_METHOD_SMTP', 2 ); # Lengths - NOTE: these may represent hard-coded values in db schema and should not be changed. define( 'USERLEN', 32); define( 'REALLEN', 64); -define( 'PASSLEN', 32); +define( 'PASSLEN', 64); define( 'SECONDS_PER_DAY', 86400 ); diff --git a/config_defaults_inc.php b/config_defaults_inc.php index 8d63519..d2313a5 100644 --- a/config_defaults_inc.php +++ b/config_defaults_inc.php @@ -2569,8 +2569,9 @@ $g_allow_no_category = OFF; /** * login method - * CRYPT or PLAIN or MD5 or LDAP or BASIC_AUTH. You can simply change this at - * will. MantisBT will try to figure out how the passwords were encrypted. + * CRYPT or PLAIN or MD5 or SHA1 or LDAP or BASIC_AUTH. + * You can simply change this at will. MantisBT will try to figure out how the + * passwords were encrypted. * @global int $g_login_method */ $g_login_method = MD5; sha_password-60f00efe222f05dce178015fc777b03d3dea54ee.patch (47,530 bytes)
diff --git a/.gitignore b/.gitignore index 8f4e287..0db8385 100644 --- a/.gitignore +++ b/.gitignore @@ -28,3 +28,4 @@ web.config #libraries library/jpgraph library/FirePHPCore +patches diff --git a/admin/schema.php b/admin/schema.php index c87f0a6..b10b315 100644 --- a/admin/schema.php +++ b/admin/schema.php @@ -606,3 +606,12 @@ $upgrade[] = Array( 'CreateIndexSQL', Array( 'idx_project_hierarchy_parent_id', /* 180 */ $upgrade[] = Array( 'CreateIndexSQL', Array( 'idx_tag_name', db_get_table( 'tag' ), 'name' ) ); $upgrade[] = Array( 'CreateIndexSQL', Array( 'idx_bug_tag_tag_id', db_get_table( 'bug_tag' ), 'tag_id' ) ); + +/* 190 */ +$upgrade[] = Array( 'AddColumnSQL', Array( db_get_table( 'user' ), " + password_128 C(128) NOTNULL DEFAULT \" '' \" " ) ); +$upgrade[] = Array( 'AddColumnSQL', Array( db_get_table( 'user' ), " + password_hash C(10) NOTNULL DEFAULT \" 'MD5' \" " ) ); +$upgrade[] = Array( 'UpdateFunction', "password_hash_migrate", Array( 'password_128', 'password_hash' ) ); +$upgrade[] = Array( 'DropColumnSQL', Array( db_get_table( 'user' ), "password" ) ); +$upgrade[] = Array( 'RenameColumnSQL', Array( db_get_table( 'user' ), "password_128", "password", "password C(128) NOTNULL DEFAULT \" '' \" " ) ); diff --git a/config_defaults_inc.php b/config_defaults_inc.php index 702b5dc..eee3566 100644 --- a/config_defaults_inc.php +++ b/config_defaults_inc.php @@ -2571,8 +2571,9 @@ $g_allow_no_category = OFF; /** * login method - * CRYPT or PLAIN or MD5 or LDAP or BASIC_AUTH. You can simply change this at - * will. MantisBT will try to figure out how the passwords were encrypted. + * CRYPT or PLAIN or MD5 or SHA1 or LDAP or BASIC_AUTH. + * You can simply change this at will. MantisBT will try to figure out how the + * passwords were encrypted. * @global int $g_login_method */ $g_login_method = MD5; diff --git a/core/authentication_api.php b/core/authentication_api.php index 8e0b422..e7e6afa 100644 --- a/core/authentication_api.php +++ b/core/authentication_api.php @@ -345,10 +345,22 @@ function auth_does_password_match( $p_user_id, $p_test_password ) { $t_password = user_get_field( $p_user_id, 'password' ); $t_login_methods = Array( + SHA1, MD5, CRYPT, PLAIN, ); + if( substr($t_password, 0, 1) == '{' && strpos($t_password, '}') > 1 ) { + $t_method = substr( $t_password, 1, strpos($t_password, '}')-1 ); + $t_methods_arr = Array('SHA'=>SHA1, 'MD5'=>MD5, 'CRYPT'=>CRYPT, + 'PLAIN'=>PLAIN); + if( in_array($t_method, $t_methods_arr) + && in_array($t_methods_arr[$t_method], $t_login_methods) ) { + $t_login_methods = Array($t_methods_arr[$t_method]); + $t_password = substr( $t_password, strlen($t_method)+2 ); + } + } + foreach( $t_login_methods as $t_login_method ) { # pass the stored password in as the salt @@ -405,6 +417,9 @@ function auth_does_password_match( $p_user_id, $p_test_password ) { case MD5: $t_processed_password = md5( $p_password ); break; + case SHA1: + $t_processed_password = sha1( $p_password ); + break; case BASIC_AUTH: case PLAIN: default: diff --git a/core/bug_api.php b/core/bug_api.php index fb32839..4326199 100644 --- a/core/bug_api.php +++ b/core/bug_api.php @@ -1324,6 +1324,28 @@ function bug_get_newest_bugnote_timestamp( $p_bug_id ) { } /** + * return the reporter (user_id) for the most recent time at which a bugnote + * associated with the bug was modified + * @param int p_bug_id integer representing bug id + * @return bool|int false or user id in integer format representing last bugnote reporter + * @access public + * @uses database_api.php + */ +function bug_get_last_bugnote_reporter( $p_bug_id ) { + $c_bug_id = db_prepare_int( $p_bug_id ); + $t_bugnote_table = db_get_table( 'bugnote' ); + + $query = "SELECT MIN(reporter_id) + FROM $t_bugnote_table A + WHERE A.date_submitted = (SELECT MAX(X.date_submitted) + FROM $t_bugnote_table X + WHERE X.bug_id = A.bug_id) AND + A.bug_id=" . db_param(); + $result = db_query_bound( $query, Array( $c_bug_id ), 1 ); + return db_result( $result ); +} + +/** * return the timestamp for the most recent time at which a bugnote * associated with the bug was modified and the total bugnote * count in one db query diff --git a/core/constant_inc.php b/core/constant_inc.php index 7e3e274..42bde13 100644 --- a/core/constant_inc.php +++ b/core/constant_inc.php @@ -134,6 +134,7 @@ define( 'MD5', 3 ); define( 'LDAP', 4 ); define( 'BASIC_AUTH', 5 ); define( 'HTTP_AUTH', 6 ); +define( 'SHA1', 7 ); # file upload methods define( 'DISK', 1 ); @@ -552,6 +553,6 @@ define( 'PHPMAILER_METHOD_SMTP', 2 ); # Lengths - NOTE: these may represent hard-coded values in db schema and should not be changed. define( 'USERLEN', 32); define( 'REALLEN', 64); -define( 'PASSLEN', 32); +define( 'PASSLEN', 128); define( 'SECONDS_PER_DAY', 86400 ); diff --git a/core/filter_api.php b/core/filter_api.php index 7e61912..01b2292 100644 --- a/core/filter_api.php +++ b/core/filter_api.php @@ -1865,19 +1865,19 @@ function filter_get_bug_rows( &$p_page_number, &$p_per_page, &$p_page_count, &$p break; case CUSTOM_FIELD_DATE_NONE: array_push( $t_join_clauses, $t_cf_join_clause ); - $t_custom_where_clause = '(( ' . $t_table_name . '.bug_id is null) OR ( ' . $t_table_name . '.value = 0)'; + $t_custom_where_clause = '(( ' . $t_table_name . '.bug_id is null) OR ( CAST(' . $t_table_name . '.value AS FLOAT) = 0)'; break; case CUSTOM_FIELD_DATE_BEFORE: array_push( $t_join_clauses, $t_cf_join_clause ); - $t_custom_where_clause = '(( ' . $t_table_name . '.value != 0 AND (' . $t_table_name . '.value+0) < ' . ( $t_filter['custom_fields'][$t_cfid][2] ) . ')'; + $t_custom_where_clause = '(( CAST(' . $t_table_name . '.value AS FLOAT) != 0 AND ( CAST(' . $t_table_name . '.value AS FLOAT) + 0) < ' . ( $t_filter['custom_fields'][$t_cfid][2] ) . ')'; break; case CUSTOM_FIELD_DATE_AFTER: array_push( $t_join_clauses, $t_cf_join_clause ); - $t_custom_where_clause = '( (' . $t_table_name . '.value+0) > ' . ( $t_filter['custom_fields'][$t_cfid][1] + 1 ); + $t_custom_where_clause = '( (CAST(' . $t_table_name . '.value AS FLOAT) + 0) > ' . ( $t_filter['custom_fields'][$t_cfid][1] + 1 ); break; default: array_push( $t_join_clauses, $t_cf_join_clause ); - $t_custom_where_clause = '( (' . $t_table_name . '.value+0) BETWEEN ' . $t_filter['custom_fields'][$t_cfid][1] . ' AND ' . $t_filter['custom_fields'][$t_cfid][2]; + $t_custom_where_clause = '( ( CAST(' . $t_table_name . '.value AS FLOAT) + 0) BETWEEN ' . $t_filter['custom_fields'][$t_cfid][1] . ' AND ' . $t_filter['custom_fields'][$t_cfid][2]; break; } } else { diff --git a/core/html_api.php b/core/html_api.php index 4bdf300..1f37ca1 100644 --- a/core/html_api.php +++ b/core/html_api.php @@ -1201,11 +1201,19 @@ function html_status_legend() { # draw the status bar $width = (int)( 100 / count( $t_status_array ) ); - foreach( $t_status_array as $t_status => $t_name ) { - $t_val = $t_status_names[$t_status]; - $t_color = get_status_color( $t_status ); + for($i=0; $i<10; $i++) { + if ( $i != 0 ) { + echo '<tr>'; + } + foreach( $t_status_array as $t_status => $t_name ) { + if($t_status % 10 == $i) { + $t_val = $t_status_names[$t_status]; + $t_color = get_status_color( $t_status ); - echo "<td class=\"small-caption\" width=\"$width%\" bgcolor=\"$t_color\">$t_val</td>"; + echo "<td class=\"small-caption\" width=\"$width%\" bgcolor=\"$t_color\">$t_val</td>"; + } + } + echo '</tr>'; } echo '</tr>'; diff --git a/core/install_helper_functions_api.php b/core/install_helper_functions_api.php index f33e4c5..9a36745 100644 --- a/core/install_helper_functions_api.php +++ b/core/install_helper_functions_api.php @@ -221,4 +221,63 @@ function install_date_migrate( $p_data) { function install_do_nothing() { # return 2 because that's what ADOdb/DataDict does when things happen properly return 2; -} \ No newline at end of file +} + +function install_password_hash_migrate( $p_data) { + // $p_data = [0] temp_password column, [1] password_hash column + global $g_db_log_queries; + global $g_login_method; + + if( $g_login_method === LDAP ) { + return 2; + } + + $t_login_method = array(PLAIN => 'PLAIN', CRYPT => 'CRYPT', + CRYPT_FULL_SALT => 'CRYPT_FULL_SALT', MD5 => 'MD5', SHA1 => 'SHA1' + )[$g_login_method]; + + + // disable query logging (even if it's enabled in config for this) + if ( $g_db_log_queries !== 0 ) { + $t_log_queries = $g_db_log_queries; + $g_db_log_queries = 0; + } else { + $t_log_queries = null; + } + + $t_table = db_get_table( 'user' ); + $t_temp_col = $p_data[0]; + $t_password_hash_col = $p_data[1]; + + // fill password_hash and temp_col + $query = "SELECT id, password FROM $t_table"; + $t_result = db_query_bound( $query ); + + while( $row = db_fetch_array( $t_result ) ) { + + $t_id = (int)$row['id']; + $t_hash_mode = $t_login_method; + $t_password = $row['password']; + + if( substr($t_password, 0, 1) == '{' + && strpos($t_password, '}') > 1 ) { + + $t_hash_mode = substr($t_password, 1, strpos($t_password, '}') - 1); + $t_password = substr($t_password, strlen($t_hash_mode) + 2); + } + + $query = "UPDATE $t_table SET $t_temp_col=" . db_param() . ", " + "$t_password_hash_col=" . db_param() . " + WHERE id=" . db_param(); + db_query_bound( $query, array( $t_password, $t_hash_mode, $t_id ) ); + } + + // re-enabled query logging if we disabled it + if ( $t_log_queries !== null ) { + $g_db_log_queries = $t_log_queries; + } + + # return 2 because that's what ADOdb/DataDict does when things happen properly + return 2; + +} diff --git a/docbook/adminguide/en/authentication.sgml b/docbook/adminguide/en/authentication.sgml index a960c1e..ffbe0f6 100644 --- a/docbook/adminguide/en/authentication.sgml +++ b/docbook/adminguide/en/authentication.sgml @@ -14,6 +14,7 @@ <listitem><para>CRYPT_FULL_SALT - deprecated.</para></listitem> <listitem><para>PLAIN - deprecated.</para></listitem> <listitem><para>MD5 - This is default and recommended approach. See <ulink url="http://en.wikipedia.org/wiki/MD5">MD5 topic on Wikipedia</ulink> for more details.</para></listitem> + <listitem><para>SHA1 - Even stronger than MD5. See <ulink url="http://en.wikipedia.org/wiki/SHA1">SHA1 topic on Wikipedia</ulink> for more details.</para></listitem> </itemizedlist> </para> diff --git a/docbook/adminguide/en/configuration.sgml b/docbook/adminguide/en/configuration.sgml index bce4bdd..99df312 100644 --- a/docbook/adminguide/en/configuration.sgml +++ b/docbook/adminguide/en/configuration.sgml @@ -1583,6 +1583,9 @@ <listitem><para> <itemizedlist> <listitem> + <para>SHA1</para> + </listitem> + <listitem> <para>MD5</para> </listitem> <listitem> diff --git a/my_view_inc.php b/my_view_inc.php index 97c131c..ff2e62d 100644 --- a/my_view_inc.php +++ b/my_view_inc.php @@ -434,6 +434,9 @@ echo "($v_start - $v_end / $t_bug_count)"; $t_summary = string_display_line_links( $t_bug->summary ); $t_last_updated = date( config_get( 'normal_date_format' ), $t_bug->last_updated ); + $t_last_reporter_id = bug_get_last_bugnote_reporter( $t_bug->id ); + $t_last_reporter = $t_last_reporter_id ? user_get_name( $t_last_reporter_id ) : ''; + # choose color based on status $status_color = get_status_color( $t_bug->status ); @@ -498,9 +501,9 @@ echo "($v_start - $v_end / $t_bug_count)"; echo string_display_line( category_full_name( $t_bug->category_id, true, $t_bug->project_id ) ); if( $t_bug->last_updated > strtotime( '-' . $t_filter[FILTER_PROPERTY_HIGHLIGHT_CHANGED] . ' hours' ) ) { - echo ' - <b>' . $t_last_updated . '</b>'; + echo ' - <b>' . $t_last_updated . ' - ' . $t_last_reporter . '</b>'; } else { - echo ' - ' . $t_last_updated; + echo ' - ' . $t_last_updated . ' - ' . $t_last_reporter; } ?> </span> diff --git a/plugins/AutoMonitor/AutoMonitor.API.php b/plugins/AutoMonitor/AutoMonitor.API.php new file mode 100644 index 0000000..ab86729 --- /dev/null +++ b/plugins/AutoMonitor/AutoMonitor.API.php @@ -0,0 +1,89 @@ +<?php +# TODO : include header + +/** + * Get the list of users for the specified project (and category) + * + * This will include the explicit and inherited settings + */ +function AutoMonitor_get_users ( $p_project_id, $p_category_id ) +{ + /* Return values */ + $t_users = array(); + + /* Tables */ + $t_user_table = db_get_table('user'); + $t_automonitor_table = plugin_table('list'); + + /* DB params */ + $c_project_id = db_prepare_int($p_project_id); + $c_category_id = db_prepare_int($p_category_id); + + /* Add all users with initial settings */ + foreach ( project_get_all_user_rows($p_project_id) as $val ) { + $val['automonitor_state'] = 0; + $val['automonitor_explicit'] = false; + $t_users[$val['id']] = $val; + } + + /* Get list of parent projects */ + $c_parents = array(); + $t_parents = project_hierarchy_inheritance($p_project_id); + foreach ( $t_parents as $t_parent ) { + if ( $t_parent != 0 ) { + $c_parents[] = db_prepare_int($t_parent); + } + } + + /* Query for all data related to relevant projects / categories */ + $params = array(db_prepare_int(0), $c_category_id); + $query = "SELECT u.id, u.username, u.realname, c.state as automonitor_state, + c.project_id, c.category_id + FROM $t_user_table u, $t_automonitor_table c + WHERE u.id = c.user_id + AND c.project_id IN (" . implode(',', $c_parents) . ") + AND ( c.category_id = " . db_param() . " + OR c.category_id = " . db_param() . ") + ORDER BY u.id, c.category_id ASC"; + $result = db_query_bound($query, $params); + + /* Process into project keyed list + * Note: since the sub project ids might not be in order we can't + * use SQL to provide the project ordering + */ + $t_proj_list = array(); + $t_proj_list = array(); + $t_row_count = db_num_rows( $result ); + for( $i = 0;$i < $t_row_count;$i++ ) { + $row = db_fetch_array( $result ); + $t_proj_list[$row['project_id']][] = $row; + } + + /* Process projects in reverse order (oldest ancestor first) */ + foreach ( array_reverse($t_parents) as $t_parent_id ) { + + /* Ignore the global project - we can't set anything here! */ + if ( $t_parent_id != 0 ) { + + /* Process each row from project + * Note: categories (max 2) should be in ascending order so the + * project (cat = 0) will be first and overridden (if + * applicable) by the explicit category + */ + if ( array_key_exists($t_parent_id, $t_proj_list) ) { + foreach ( $t_proj_list[$t_parent_id] as $row ) { + $row['automonitor_explicit'] = ($row['project_id'] == $p_project_id) && + ($row['category_id'] == $p_category_id); + $t_users[$row['id']] = $row; + } + } + } + } + + /* Return result (as simple array) */ + $t_ret = array(); + foreach ( $t_users as $key => $val ) { + $t_ret[] = $val; + } + return $t_ret; +} diff --git a/plugins/AutoMonitor/AutoMonitor.ViewAPI.php b/plugins/AutoMonitor/AutoMonitor.ViewAPI.php new file mode 100644 index 0000000..d2fcddf --- /dev/null +++ b/plugins/AutoMonitor/AutoMonitor.ViewAPI.php @@ -0,0 +1,105 @@ +<?php +# TODO: include header + +/** + * Display a project configuration table + * + * Note: this doesn't actually display the entire table, just the main + * contents (3 user selection inputs and control buttons) + */ +function AutoMonitor_print_project_config_table ( $p_users ) +{ +?> +<tr <?php echo helper_alternate_class() ?>> + <td style='width:20%'> + <select name='inherited[]' multiple='multiple' size='10' style='width:90%'> + <?php AutoMonitor_print_user_option_list($p_users, false, 1); ?> + </select> + </td> + <td style='width:13%'> + <input style='width:90%' type='submit' name='inherit_inc' + value='<?php echo plugin_lang_get('include'); ?>'/><br/> + <input style='width:90%' type='submit' name='inherit_exc' + value='<?php echo plugin_lang_get('exclude'); ?>'/> + </td> + <td style='width:20%'> + <select name='excluded[]' multiple='multiple' size='10' style='width:90%'> + <?php AutoMonitor_print_user_option_list($p_users, true, 0); ?> + </select> + </td> + <td style='width:13%'> + <input style='width:90%' type='submit' name='exclude_inc' + value='<?php echo plugin_lang_get('include'); ?>'/><br/> + <input style='width:90%' type='submit' name='exclude_clr' + value='<?php echo plugin_lang_get('clear'); ?>'/> + </td> + <td style='width:20%'> + <select name='included[]' multiple='multiple' size='10' style='width:90%'> + <?php AutoMonitor_print_user_option_list($p_users, true, 1); ?> + </select> + </td> + <td style='width:14%'> + <input style='width:90%' type='submit' name='include_exc' + value='<?php echo plugin_lang_get('exclude'); ?>'/><br/> + <input style='width:90%' type='submit' name='include_clr' + value='<?php echo plugin_lang_get('clear'); ?>'/> + </td> +</tr> +<?php +} + +/** + * Print a list of users + * + * @param p_users The complete list of users + * @param p_explicit Print users with matching explicit value + * @param p_state Print users with matching state value (if explicit = true) + * otherwise if explicit = false this indicates whether to + * to prefix with Inc/Ext (=1) or not (=0) + */ +function AutoMonitor_print_user_option_list ( $p_users, $p_explicit, $p_state ) +{ + /* Configuration */ + $t_show_realname = ( ON == config_get( 'show_realname' ) ); + $t_sort_by_last_name = ( ON == config_get( 'sort_by_last_name' ) ); + + /* Display details */ + $t_id_a = array(); + $t_display_a = array(); + $t_sort_a = array(); + + /* Process each user */ + foreach ( $p_users as $t_user ) { + if ( ($t_user['automonitor_explicit'] == $p_explicit) && + (!$p_explicit || ($t_user['automonitor_state'] == $p_state)) ) { + $t_name = string_attribute($t_user['username']); + $t_sort = $t_name; + if ( isset($t_user['realname']) && + !empty($t_user['realname']) && + $t_show_realname ) { + $t_name = string_attribute($t_user['realname']); + if ( $t_sort_by_last_name ) { + $t_bits = explode(' ', utf8_strtolower($t_name)); + $t_sort = (isset($t_bits[1]) ? $t_bits[1] . ', ' : '') . $t_bits[0]; + } else { + $t_sort = utf8_strtolower($t_name); + } + } + if ( !$p_explicit && ($p_state == 1) ) { + $t_name = (($t_user['automonitor_state'] == 1) ? 'Inc: ' : 'Exc: ') . $t_name; + } + $t_id_a[] = $t_user['id']; + $t_display_a[] = $t_name; + $t_sort_a[] = $t_sort; + } + } + + /* Sort */ + array_multisort($t_sort_a, SORT_ASC, SORT_STRING, $t_id_a, $t_display_a); + + /* Output */ + for ( $i = 0; $i < count($t_sort_a); $i++ ) { + echo "<option value='$t_id_a[$i]'>$t_display_a[$i]</option>\n"; + } +} +?> diff --git a/plugins/AutoMonitor/AutoMonitor.php b/plugins/AutoMonitor/AutoMonitor.php new file mode 100644 index 0000000..90e8d3b --- /dev/null +++ b/plugins/AutoMonitor/AutoMonitor.php @@ -0,0 +1,146 @@ +<?php + +# TODO: create a header (must have one somewhere) + +/* Include parent class */ +require_once( config_get( 'class_path' ) . 'MantisPlugin.class.php' ); + +/* + * Auto project/category monitoring + */ +class AutoMonitorPlugin + extends MantisPlugin +{ + + /* + * Register the module + */ + function register () + { + $this->name = plugin_lang_get('title'); + $this->description = plugin_lang_get('description'); + $this->author = 'Adam Sutton'; + $this->contact = 'adam@adamsutton.co.uk'; + $this->url = 'http://www.adamsutton.co.uk'; + $this->version = '0.0.0'; + $this->requires = array( + 'MantisCore' => '1.2.0', + ); + $this->page = 'config'; + } + + /** + * Initialise + */ + function init () + { + require_once('AutoMonitor.API.php'); + require_once('AutoMonitor.ViewAPI.php'); + } + + /** + * Configuration + */ + function config () + { + return array( + ); + } + + /** + * Schema + */ + function schema () + { + return array( + array('CreateTableSQL', array(plugin_table('list'), " + user_id I UNSIGNED NOTNULL PRIMARY, + project_id I UNSIGNED NOTNULL PRIMARY, + category_id I UNSIGNED NOTNULL PRIMARY, + state L NOTNULL")), + ); + } + + /** + * Event hooks + */ + function hooks () + { + return array( + 'EVENT_MANAGE_PROJECT_PAGE' => 'manage_project_list', + 'EVENT_REPORT_BUG' => 'add_monitors', + ); + } + + /* ************************************************************************ + * Hook handlers + * ***********************************************************************/ + + function manage_project_list () + { + /* Check access */ + $f_project_id = gpc_get_int('project_id'); + if ( !access_has_project_level(config_get('project_user_threshold'), $f_project_id) ) { + return; + } + + /* Get user list */ + $t_users = AutoMonitor_get_users($f_project_id, 0); +?> +<!-- AUTOMONITOR LIST --> +<br/> +<a name='automonitor'/> +<div align='center'> + <table class='width75' cellspacing='1'> + + <!-- Title --> + <tr> + <td class='form-title' colspan='6'> + <?php echo plugin_lang_get( 'manage_project_title' ); ?> + </td> + </tr> + + <!-- Titles --> + <tr class='row-category'> + <td width='33%' colspan='2'><?php echo plugin_lang_get( 'inherit_title' ); ?></td> + <td width='33%' colspan='2'><?php echo plugin_lang_get( 'exclude_title' ); ?></td> + <td width='34%' colspan='2'><?php echo plugin_lang_get( 'include_title' ); ?></td> + </tr> + + <!-- User lists --> + <form method='post' action='<?php echo plugin_page('project_update') ?>'> + <input type="hidden" name="project_id" value="<?php echo $f_project_id ?>" /> + <?php echo form_security_field('plugin_AutoMonitor_project_update'); ?> + <?php AutoMonitor_print_project_config_table($t_users); ?> + </form> + + <!-- Category edit page --> + <form method='post' action='<?php echo plugin_page('category_edit_page') ?>'> + <input type="hidden" name="project_id" value="<?php echo $f_project_id ?>" /> + <?php echo form_security_field('plugin_AutoMonitor_project_category_select'); ?> + <tr> + <td class='left' colspan='6'> + <select name='category_id'> + <?php print_category_option_list(0, $f_project_id); ?> + </select> + <input type='submit' name='cat_update' value='<?php echo plugin_lang_get('edit_category'); ?>'/> + </td> + </tr> + </form> + </table> +</div> +<?php + } + + function add_monitors($p_event, $p_bug, $p_bug_id) { + if( $p_event == 'EVENT_REPORT_BUG' ) { + $t_users = AutoMonitor_get_users($p_bug->project_id, 0); + print_r($t_users); + foreach($t_users as $t_user) { + if($t_user['automonitor_state'] > 0) + bug_monitor($p_bug_id, $t_user['id']); + } + } + } +} +?> diff --git a/plugins/AutoMonitor/lang/strings_english.txt b/plugins/AutoMonitor/lang/strings_english.txt new file mode 100644 index 0000000..7df3ee8 --- /dev/null +++ b/plugins/AutoMonitor/lang/strings_english.txt @@ -0,0 +1,17 @@ +<?php +# TODO: must have a standard header + +$s_plugin_AutoMonitor_title = 'AutoMonitor'; +$s_plugin_AutoMonitor_description = 'Allow users to be automatically assigned to new issues in a project/category'; + +$s_plugin_AutoMonitor_manage_project_title = 'Project Monitors'; +$s_plugin_AutoMonitor_inherit_title = 'Inherited'; +$s_plugin_AutoMonitor_include_title = 'Included'; +$s_plugin_AutoMonitor_exclude_title = 'Excluded'; +$s_plugin_AutoMonitor_exclude = 'Exclude'; +$s_plugin_AutoMonitor_include = 'Include'; +$s_plugin_AutoMonitor_clear = 'Clear'; +$s_plugin_AutoMonitor_edit_category = 'Edit Category'; +$s_plugin_AutoMonitor_category_edit_title = 'Category Monitors'; +$s_plugin_AutoMonitor_exit_button = 'Exit'; +?> diff --git a/plugins/AutoMonitor/lang/strings_hungarian.txt b/plugins/AutoMonitor/lang/strings_hungarian.txt new file mode 100644 index 0000000..3f597b9 --- /dev/null +++ b/plugins/AutoMonitor/lang/strings_hungarian.txt @@ -0,0 +1,17 @@ +<?php +# TODO: must have a standard header + +$s_plugin_AutoMonitor_title = 'AutoMonitor'; +$s_plugin_AutoMonitor_description = 'Megadott felhasználók automatikusan ellenőrizzék az új projekteket/ügyeket'; + +$s_plugin_AutoMonitor_manage_project_title = 'Projekt Ellenőrök'; +$s_plugin_AutoMonitor_inherit_title = 'Örökölt'; +$s_plugin_AutoMonitor_include_title = 'Bennfoglalt'; +$s_plugin_AutoMonitor_exclude_title = 'Kizárt'; +$s_plugin_AutoMonitor_exclude = 'Kizár'; +$s_plugin_AutoMonitor_include = 'Hozzáad'; +$s_plugin_AutoMonitor_clear = 'Töröl'; +$s_plugin_AutoMonitor_edit_category = 'Kategória Szerkesztése'; +$s_plugin_AutoMonitor_category_edit_title = 'Kategória Ellenőrök'; +$s_plugin_AutoMonitor_exit_button = 'Kilépés'; +?> diff --git a/plugins/AutoMonitor/pages/category_edit_page.php b/plugins/AutoMonitor/pages/category_edit_page.php new file mode 100644 index 0000000..c52ffda --- /dev/null +++ b/plugins/AutoMonitor/pages/category_edit_page.php @@ -0,0 +1,72 @@ +<?php +# TODO: add header + +/* Validate authentication */ +auth_reauthenticate(); + +/* Get form vars */ +$f_project_id = gpc_get_int('project_id'); +$f_category_id = gpc_get_int('category_id'); + +/* Validate params */ +project_ensure_exists($f_project_id); +if ( $f_category_id === 0 ) { + print_header_redirect("manage_proj_edit_page.php?project_id=$f_project_id#automonitor"); + exit; +} +category_ensure_exists($f_category_id); + +/* Double check permissions */ +access_ensure_project_level(config_get('manage_project_threshold')); +access_ensure_project_level(config_get('project_user_threshold')); + +/* Start page */ +html_page_top(project_get_field($f_project_id, 'name')); +print_manage_menu(); + +/* Get user list */ +$t_users = AutoMonitor_get_users($f_project_id, $f_category_id); + +/* Display the main table */ +?> +<div align='center'> + <table class='width75' cellspacing='1'> + + <!-- Title --> + <tr> + <td class='form-title' colspan='6'> + <?php echo plugin_lang_get( 'category_edit_title' ); ?> + </td> + </tr> + + <!-- Titles --> + <tr class='row-category'> + <td width='33%' colspan='2'><?php echo plugin_lang_get( 'inherit_title' ); ?></td> + <td width='33%' colspan='2'><?php echo plugin_lang_get( 'exclude_title' ); ?></td> + <td width='34%' colspan='2'><?php echo plugin_lang_get( 'include_title' ); ?></td> + </tr> + + <!-- User lists --> + <form method='post' action='<?php echo plugin_page('project_update') ?>'> + <input type="hidden" name="project_id" value="<?php echo $f_project_id ?>" /> + <input type='hidden' name='category_id' value='<?php echo $f_category_id ?>'/> + <?php echo form_security_field('plugin_AutoMonitor_project_update'); ?> + <?php AutoMonitor_print_project_config_table($t_users); ?> + </form> + + <!-- Cancel button --> + <form method='post' action='manage_proj_edit_page.php'> + <input type="hidden" name="project_id" value="<?php echo $f_project_id ?>" /> + <tr> + <td class='left' colspan='6'> + <input type='submit' name='cancel' value='<?php echo plugin_lang_get('exit_button') ?>'/> + </td> + </tr> + </form> + </table> +</div> +<?php + +/* End page */ +html_page_bottom(); +?> diff --git a/plugins/AutoMonitor/pages/project_update.php b/plugins/AutoMonitor/pages/project_update.php new file mode 100644 index 0000000..afcaca6 --- /dev/null +++ b/plugins/AutoMonitor/pages/project_update.php @@ -0,0 +1,78 @@ +<?php + +/* Validate authentication */ +form_security_validate('plugin_AutoMonitor_project_update'); +auth_reauthenticate(); + +/* Get submission values (should all be mutually exclusive) */ +$f_project_id = gpc_get_int('project_id'); +$f_category_id = gpc_get_int('category_id', 0); + +/* Table params */ +$t_automonitor_table = plugin_table('list'); +$c_project_id = db_prepare_int($f_project_id); +$c_category_id = db_prepare_int($f_category_id); + +/* Validate params */ +project_ensure_exists($f_project_id); +if ( $f_category_id !== 0 ) category_ensure_exists($f_category_id); + +/* Double check permissions */ +access_ensure_project_level(config_get('manage_project_threshold')); +access_ensure_project_level(config_get('project_user_threshold')); + +/* Get the submit buttons */ +$f_exclude_inc = gpc_get_bool('exclude_inc'); +$f_exclude_clr = gpc_get_bool('exclude_clr'); +$f_include_exc = gpc_get_bool('include_exc'); +$f_include_clr = gpc_get_bool('include_clr'); +$f_inherit_inc = gpc_get_bool('inherit_inc'); +$f_inherit_exc = gpc_get_bool('inherit_exc'); + +/* Update the inherited users */ +if ( $f_inherit_inc || $f_inherit_exc ) { + $f_users = gpc_get_int_array('inherited'); + $c_state = db_prepare_int($f_inherit_inc ? 1 : 0); + $query = "INSERT INTO $t_automonitor_table + (user_id, project_id, category_id, state) + VALUES (" . db_param() . "," . db_param() . "," . db_param() . "," . db_param() . ")"; + foreach ( $f_users as $t_user ) { + db_query_bound($query, array(db_prepare_int($t_user), $c_project_id, $c_category_id, $c_state)); + } + +/* Clear */ +} else if ( $f_include_clr || $f_exclude_clr ) { + $f_users = gpc_get_int_array($f_include_clr ? 'included' : 'excluded'); + $c_users = array(); + foreach ( $f_users as $t_user ) { + $c_users[] = db_prepare_int($t_user); + } + $query = "DELETE FROM $t_automonitor_table + WHERE project_id = " . db_param() . " + AND category_id = " . db_param() . " + AND user_id IN (" . implode(',', $c_users) . ")"; + db_query_bound($query, array($c_project_id, $c_category_id)); + +/* Set */ +} else if ( $f_include_exc || $f_exclude_inc ) { + $f_users = gpc_get_int_array($f_include_exc ? 'included' : 'excluded'); + $c_users = array(); + foreach ( $f_users as $t_user ) { + $c_users[] = db_prepare_int($t_user); + } + $c_state = db_prepare_int($f_include_exc ? 0 : 1); + $query = "UPDATE $t_automonitor_table + SET state = " . db_param() . " + WHERE project_id = " . db_param() . " + AND category_id = " . db_param() . " + AND user_id IN (" . implode(',', $c_users) . ")"; + db_query_bound($query, array($c_state, $c_project_id, $c_category_id)); +} + +/* Done */ +form_security_purge('plugin_AutoMonitor_project_update'); +if ( $f_category_id == 0 ) { + print_header_redirect("manage_proj_edit_page.php?project_id=$f_project_id#automonitor"); +} else { + print_header_redirect(plugin_page("category_edit_page&project_id=$f_project_id&category_id=$f_category_id", true)); +} diff --git a/plugins/FileDistribution/FileDistribution.php b/plugins/FileDistribution/FileDistribution.php new file mode 100755 index 0000000..db01b70 --- /dev/null +++ b/plugins/FileDistribution/FileDistribution.php @@ -0,0 +1,55 @@ +<?php + +require_once( config_get( 'class_path' ) . 'MantisPlugin.class.php' ); + +class FileDistributionPlugin extends MantisPlugin { + function register() { + $this->name = 'FileDistribution'; # Proper name of plugin + $this->description = 'Static file distrubution'; # Short description of the plugin + $this->page = ''; # Default plugin page + + $this->version = '1.0'; # Plugin version string + $this->requires = array( # Plugin dependencies, array of basename => version pairs + 'MantisCore' => '1.2.0', # Should always depend on an appropriate version of MantisBT + ); + + $this->author = 'Tamás Gulácsi'; # Author/team name + $this->contact = 'T.Gulacsi@unosoft.hu'; # Author/team e-mail address + $this->url = 'http://www.unosoft.hu'; # Support webpage + } + + function config() { + return array( + 'url' => NULL, + 'path' => NULL, + 'users' => array(), + 'secret_word' => '1234567890', + ); + } + + function hooks() { + return array( + 'EVENT_MENU_MAIN' => 'menu', + 'EVENT_MENU_MANAGE' => 'manage', + ); + } + + function menu( ) { + //require_once( 'core.php' ); + require_once( dirname(__FILE__).'/core/filedistrib_api.php' ); + + if ( user_allowed() ) { + return array( '<a href="' . plugin_page( 'static_files.php' ) . '">' . + plugin_lang_get('static_files') . '</a>', ); + } + } + + function manage( ) { + require_once( 'core.php' ); + + if ( access_get_project_level() >= MANAGER) { + return array( '<a href="' . plugin_page( 'config.php' ) . '">' + . plugin_lang_get('config') . '</a>', ); + } + } +} diff --git a/plugins/FileDistribution/core/filedistrib_api.php b/plugins/FileDistribution/core/filedistrib_api.php new file mode 100644 index 0000000..ac978cd --- /dev/null +++ b/plugins/FileDistribution/core/filedistrib_api.php @@ -0,0 +1,49 @@ +<?php + +function str2list($p_text) { + $t_arr = $p_text != null ? explode(',', $p_text) : array(); + $t_arr = uids2names(names2uids($t_arr)); + sort($t_arr); + return $t_arr; +} + +function list2str($p_arr) { + $p_arr = uids2names(names2uids($p_arr)); + sort($p_arr); + return implode(',', $p_arr); +} + +function names2uids($p_arr) { + require_once( 'core.php' ); + $ret = array(); + foreach($p_arr as $name) { + $t_id = user_get_id_by_name($name); + if( $t_id && user_is_enabled($t_id) ) { + $ret[] = $t_id; + } + } + return $ret; +} + +function uids2names($p_arr) { + require_once( 'core.php' ); + + $ret = array(); + foreach($p_arr as $t_id) { + if( user_is_enabled($t_id) ) { + $ret[] = user_get_name($t_id); + } + } + return $ret; +} + +function user_allowed() { + require_once( 'core.php' ); + + $t_act_uid = auth_get_current_user_id(); + + $t_users = str2list( plugin_config_get( 'users' ) ); + + return in_array( $t_act_uid, names2uids($t_users) ); +} +?> diff --git a/plugins/FileDistribution/lang/strings_english.txt b/plugins/FileDistribution/lang/strings_english.txt new file mode 100755 index 0000000..3fbaf47 --- /dev/null +++ b/plugins/FileDistribution/lang/strings_english.txt @@ -0,0 +1,8 @@ +<?php +$s_plugin_FileDistribution_name = 'FileDistribution'; +$s_plugin_FileDistribution_config = 'FileDistribution configuration'; +$s_plugin_FileDistribution_url = 'URL'; +$s_plugin_FileDistribution_path = 'PATH'; +$s_plugin_FileDistribution_users = 'allowed users'; +$s_plugin_FileDistribution_secret_word = 'shared secret'; +$s_plugin_FileDistribution_static_files = 'Downloadable files'; diff --git a/plugins/FileDistribution/lang/strings_hungarian.txt b/plugins/FileDistribution/lang/strings_hungarian.txt new file mode 100755 index 0000000..a634ae3 --- /dev/null +++ b/plugins/FileDistribution/lang/strings_hungarian.txt @@ -0,0 +1,8 @@ +<?php +$s_plugin_FileDistribution_name = 'FileDistribution'; +$s_plugin_FileDistribution_config = 'FileDistrib beállítások'; +$s_plugin_FileDistribution_url = 'URL'; +$s_plugin_FileDistribution_path = 'PATH'; +$s_plugin_FileDistribution_users = 'engedélyezett felhasználók'; +$s_plugin_FileDistribution_secret_word = 'megosztott titok'; +$s_plugin_FileDistribution_static_files = 'Letölthető fájlok'; diff --git a/plugins/FileDistribution/pages/config.php b/plugins/FileDistribution/pages/config.php new file mode 100644 index 0000000..5ee1244 --- /dev/null +++ b/plugins/FileDistribution/pages/config.php @@ -0,0 +1,91 @@ +<?php +# MantisBT - a php based bugtracking system +# Copyright (C) 2002 - 2009 MantisBT Team - mantisbt-dev@lists.sourceforge.net +# MantisBT is free software: you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation, either version 2 of the License, or +# (at your option) any later version. +# +# MantisBT is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with MantisBT. If not, see <http://www.gnu.org/licenses/>. + +auth_reauthenticate( ); +access_ensure_global_level( config_get( 'manage_plugin_threshold' ) ); + +html_page_top( plugin_lang_get( 'name' ) ); + +print_manage_menu( ); + +?> + +<br/> +<form action="<?php echo plugin_page( 'config_edit' )?>" method="post"> +<?php echo form_security_field( 'plugin_filedistrib_config_edit' ) ?> +<table align="center" class="width50" cellspacing="1"> + +<tr> + <td class="form-title" colspan="3"> + <?php echo plugin_lang_get( 'config' )?> + </td> +</tr> + +<tr <?php echo helper_alternate_class( )?>> + <td class="category" width="60%"> + <?php echo plugin_lang_get( 'url' )?> + </td> + <td class="center" width="20%"> + <label><?php echo plugin_lang_get( 'url' )?></label> + <input type="text" name="url" value="<?php echo plugin_config_get( 'url', NULL ); ?>" /> + </td> +</tr> +<tr <?php echo helper_alternate_class( )?>> + <td class="category" width="60%"> + <?php echo plugin_lang_get( 'path' )?> + </td> + <td class="center" width="20%"> + <label><?php echo plugin_lang_get( 'path' )?></label> + <input type="text" name="path" value="<?php echo plugin_config_get( 'path', NULL ); ?>" /> + </td> +</tr> +<tr <?php echo helper_alternate_class( )?>> + <td class="category" width="60%"> + <?php echo plugin_lang_get( 'secret_word' )?> + </td> + <td class="center" width="20%"> + <label><?php echo plugin_lang_get( 'secret_word' )?></label> + <input type="text" name="secret_word" value="<?php echo plugin_config_get( 'secret_word', NULL ); ?>" /> + </td> +</tr> +<tr <?php echo helper_alternate_class( )?>> + <td class="category" width="60%"> + <?php echo plugin_lang_get( 'users' )?> + </td> +<?php + + require_once( dirname(__FILE__).'/../core/filedistrib_api.php' ); + + $t_users_s = list2str(str2list(plugin_config_get( 'users', '' ))); +?> + <td class="center" width="20%"> + <label><?php echo plugin_lang_get( 'users' )?></label> + <input type="text" name="users" value="<?php echo $t_users_s; ?>" /> + </td> +</tr> + +<tr> + <td class="center" colspan="3"> + <input type="submit" class="button" value="<?php echo lang_get( 'change_configuration' )?>" /> + </td> +</tr> + +</table> +</form> + +<?php +html_page_bottom(); +?> diff --git a/plugins/FileDistribution/pages/config_edit.php b/plugins/FileDistribution/pages/config_edit.php new file mode 100644 index 0000000..2fc7aee --- /dev/null +++ b/plugins/FileDistribution/pages/config_edit.php @@ -0,0 +1,51 @@ +<?php +# MantisBT - a php based bugtracking system +# Copyright (C) 2002 - 2009 MantisBT Team - mantisbt-dev@lists.sourceforge.net +# MantisBT is free software: you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation, either version 2 of the License, or +# (at your option) any later version. +# +# MantisBT is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with MantisBT. If not, see <http://www.gnu.org/licenses/>. + +form_security_validate( 'plugin_filedistrib_config_edit' ); + +auth_reauthenticate( ); +access_ensure_global_level( config_get( 'manage_plugin_threshold' ) ); + +$f_url = gpc_get_string( 'url', NULL ); +$f_path = gpc_get_string( 'path', NULL ); +$f_secret_word = gpc_get_string( 'secret_word', NULL ); +/* +echo '<pre>old_url='.plugin_config_get( 'url' ).', new_url='.$f_url.'</pre>'; +*/ + +if( plugin_config_get( 'url' ) != $f_url ) { + plugin_config_set( 'url', $f_url ); +} +if( plugin_config_get( 'path' ) != $f_path && is_dir($f_path) && file_exists($f_path) ) { + plugin_config_set( 'path', $f_path ); +} +if( plugin_config_get( 'secret_word' ) != $f_secret_word && $f_secret_word != NULL) { + plugin_config_set( 'secret_word', $f_secret_word ); +} + +//require_once( 'core.php' ); +require_once( dirname(__FILE__).'/../core/filedistrib_api.php' ); + +$t_users_old = list2str(str2list(plugin_config_get( 'users', '' ))); +$f_users = list2str(str2list(gpc_get_string( 'users', '' ))); +if( $t_users_old != $f_users ) { + plugin_config_set( 'users', list2str(str2list($f_users)) ); +} + +form_security_purge( 'plugin_filedistrib_config_edit' ); + +print_successful_redirect( plugin_page( 'config', true ) ); +?> diff --git a/plugins/FileDistribution/pages/send_file.php b/plugins/FileDistribution/pages/send_file.php new file mode 100755 index 0000000..cde6946 --- /dev/null +++ b/plugins/FileDistribution/pages/send_file.php @@ -0,0 +1,84 @@ +<?php +require_once( dirname(__FILE__).'/../../../core.php' ); + +/* +form_security_validate( 'plugin_filedistrib_send' ); +form_security_purge( 'plugin_filedistrib_send' ); +*/ + +function phpMinV($v) { + $phpV = PHP_VERSION; + + if ($phpV[0] >= $v[0]) { + if (empty($v[2]) || $v[2] == '*') { + return true; + } elseif ($phpV[2] >= $v[2]) { + if (empty($v[4]) || $v[4] == '*' || $phpV[4] >= $v[4]) { + return true; + } + } + } + + return false; +} + +//header('HTTP/1.1 200 OK'); +//header('Content-Type: text/plain'); + +$f_url = $_REQUEST['url']; +if($f_url == false) { + $p = strpos($_SERVER['QUERY_STRING'], '%3Furl%3D'); + if($p >= 0) { + //echo '!' . substr($_SERVER['QUERY_STRING'], $p+9) . "!\n"; + $f_url = urldecode(substr($_SERVER['QUERY_STRING'], $p+9)); + } else { + //echo '!QS='.$_SERVER['QUERY_STRING']."! p=$p\n"; + } +} +//if($f_url == false) phpinfo(); +//echo "URL=$f_url\n"; + +$arr = explode('/', $f_url); +//print_r($arr); +$f_time = array_pop(&$arr); +$t_time = hexdec($f_time); +$t_now = time(); +if ($t_now >= $t_time) { + header('HTTP/1.1 403 Timeout'); + header('Content-Type: text/plain'); + echo "Your link has expired (actual=$t_now, link=$t_time).\n"; + exit(); +} +$f_hash = array_pop(&$arr); +$f_fn = implode('/', $arr); +//echo "fn=$f_fn, hash=$f_hash, time=$f_time"; + +$t_secret = plugin_config_get('secret_word'); +$t_hash = md5($f_fn . '/' . $t_secret . '/' . $f_time); +if($t_hash != $f_hash) { + header('HTTP/1.1 403 Bad Request'); + header('Content-Type: text/plain'); + echo "Your link has bad hash (actual=$t_hash, link=$f_hash).\n"; + exit(); +} + +$t_path_base = plugin_config_get('path'); +$t_url_base = plugin_config_get('url'); + +$f_path = $t_path_base . '/' . $f_fn; +if ($f_fn != false && file_exists($f_path)) { + $mime = mime_content_type($f_fn); + header('Content-Description: File Transfer'); + header('Content-Type: ' . $mime); + header('Content-Disposition: attachment; filename=' . basename($f_fn)); + header('Content-Transfer-Encoding: binary'); + header('Expires: 0'); + header('Cache-Control: must-revalidate, post-check=0, pre-check=0'); + header('Pragma: public'); + header('Content-Length: ' . filesize($f_path)); + + header('X-Accel-Redirect: /protected' . $t_url_base . '/' . $f_fn); +} else { + header('Content-Type: text/plain'); + echo "NOT EXISTS (fn=$f_fn, path=$f_path, url_base=$t_url_base, path_base=$t_path_base)"; +} diff --git a/plugins/FileDistribution/pages/static_files.php b/plugins/FileDistribution/pages/static_files.php new file mode 100755 index 0000000..288a107 --- /dev/null +++ b/plugins/FileDistribution/pages/static_files.php @@ -0,0 +1,115 @@ +<?php + +// auth_reauthenticate( ); + +html_page_top( plugin_lang_get( 'name' ) ); + +$t_this_page = plugin_page('static_files'); //FIXME with plugins this does not work... +/* +print_manage_menu( $t_this_page ); +*/ +require_once( 'core.php' ); +require_once( dirname(__FILE__).'/../core/filedistrib_api.php' ); + +if(!user_allowed()) { + exit; +} + +$t_url = plugin_config_get('url'); +$t_path = plugin_config_get('path'); +//print 'URL='.$t_url.' PATH='.$t_path; + +$t_secu = form_security_field( 'plugin_filedistrib_send' ); + +/* +echo "Handle: " . $d->handle . "\n"; +echo "Path: " . $d->path . "\n"; +*/ +$t_post_url = plugin_page( 'send_file.php' ); +/* +$t_post_url = str_replace('FileDistribution/', 'FileDistribution/pages/', + str_replace('plugin.php?page=', 'plugins/', $t_post_url )); +*/ +/* +$d = scandir($t_url); +echo '<ul>'; +foreach($d as $entry) { + if(preg_match('/\.(tar\.|t)(gz|bz2)$/', $entry)) { + ?> + <li> + <form action="<?php echo $t_post_url;?>" method="post"> + <?php echo $t_secu; ?> + <input type="hidden" name="fn" + value="<?php echo $t_url.'/'.$entry;?>" /> + <input type="submit" class="button" + value="<?php echo $entry;?>" /> + </form> + </li> +<?php + } +} +echo '</ul>'; +*/ +function get_dirs($path) { + $arr = array(); + foreach(scandir($path, TRUE) as $elt) { + $p = $path . '/' . $elt; + if( is_dir($p) && $elt != '.' && $elt != '..' ) { + $arr[] = $p; + } + } + return $arr; +} + +function get_files($path, $regex) { + $arr = array(); + foreach(scandir($path, FALSE) as $elt) { + $p = $path . '/' . $elt; + if( is_file($p) && is_readable($p) && preg_match($regex, $elt) ) { + $arr[] = $p; + } + } + return $arr; +} + +function print_struct($path, $regex, $level=0) { + if($level > 10) return; + $t_path = plugin_config_get('path'); + $t_secret = plugin_config_get('secret_word'); + $t_timeout = plugin_config_get('timeout', 300); + + $t_plugin_page = plugin_page('send_file.php'); + $t_url = $t_plugin_page; + $t_url = substr($t_url, 0, strpos($t_url, '/plugin.php')) + . plugin_config_get('url'); + print '<p>'; + print '<h'.($level+1).'>'.basename($path).'</h'.($level+1).'>'; + $i = 0; + foreach(get_dirs($path) as $d) { + # DFS + //print 'd: '.$d.' lev='.$level; + print_struct($d, $regex, $level+1); + if($i++ > 100) break; + } + print '<ul>'; + $i = 0; + foreach(get_files($path, $regex) as $f) { + # md5 (reference, secret_word); + $t_resource = substr($f, strlen($t_path)+1); + $t_pre = $t_resource; #$t_url . '/' . $t_resource; + $t_time = sprintf("%X", time() + $t_timeout); + $t_hash = md5($t_pre . '/' . $t_secret . '/' . $t_time); + $t_link = $t_pre . '/' . $t_hash . '/' . $t_time; + //print "<pre>pre=$t_pre, time=$t_time, hash=$t_hash, secr=$t_secret, $t_pre/$t_secret/$t_time</pre>"; + //print '<li><a href="' . $t_link . '">' . basename($f).'</a></li>'; + print '<li><a href="' . $t_plugin_page . urlencode('?url=' . $t_link) . '">'.basename($f).'</a></li>'; + if($i++ > 100) break; + } + print '</ul>'; + print '</p>'; +} #mantIs3456 + +print_struct($t_path, '/.*/'); + + +html_page_bottom(); | ||||
has duplicate | 0007864 | closed | dregad | Native support for SHA1 authentification within Mantis |
related to | 0013047 | closed | dregad | PASSLEN constant doesn't match database field size |
related to | 0010172 | closed | dregad | Passwords in SHA256 using a static salt |
related to | 0022839 | assigned | dregad | Deprecate MD5 login method and replace with BCRYPT hash |
Thanks gthomas for your contribution. The request makes sense. Here are my comments:
|
|
I'm not so sure about increasing the maximum password length in the database to 128 characters. Which password hashing function produces 1024 bits output? 64 sounds like a better option to me, in case people want to use functions like SHA512 or Whirlpool. |
|
Hi, I did increase the password field length, just as PASSLEN - forgot to include it in the patch - now this is supplied, too. Some comments on the patch:
GThomas |
|
Thanks GThomas for the update. Here are some more comments:
|
|
Hi, Added a new patch targeting 1, 2, 3, 5, 6 (MD5 is still the default). OOPS! |
|
gthomas, The authentication changes is something we'll probably commit to core as part of authentication plugins. If we added this now, it would just make it more difficult to implement plugins. Paul |
|
What about using some semi-standard library? For example, phpass (http://www.openwall.com/phpass/) is in the public domain, salts password hashes and uses the strongest available crypto method. Of course, password field length should be beefed up a little bit... GThomas |
|
Removed trojan from attachments. |
|
There is also a patch attached in 0007864 |
|
It does not make much sense to implement SHA1 / SHA256 nowadays. BCRYPT is a much better option for hashing passwords, and is now offered by PHP as default method via password_hash() function. I am therefore resolving this issue as "won't fix"; please follow-up in 0022839 for implementation of BCRYPT as default login method in future releases of MantisBT. |
|