123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259 |
- <?php
- include_once ("model/meta_model.php");
- include_once ("hash_tool.php");
- /**
- * htpasswd tools for Apache Basic Auth.
- *
- * now uses crypt_apr1_md5
- */
- class htpasswd {
- var $fp;
- var $metafp;
- var $filename;
- var $metafilename;
- var $use_metadata;
-
- /* All ht-files. These files are stored within the secured folder. */
- const HTPASSWD_NAME = ".htpasswd";
- const HTACCESS_NAME = ".htaccess";
- const HTMETA_NAME = ".htmeta";
- function htpasswd($configpath, $use_metadata = false) {
- $path = realpath ( $configpath );
- $htaccessfile = $path . "/" . self::HTACCESS_NAME;
- $htpasswdfile = $path . "/" . self::HTPASSWD_NAME;
- @$this->use_metadata = $use_metadata;
-
- if (! file_exists ( $htaccessfile )) {
- $bdfp = fopen ( $htaccessfile, 'w' );
- $htaccess_content = "AuthType Basic\nAuthName \"Password Protected Area\"\nAuthUserFile \"" . $htpasswdfile . "\"\nRequire valid-user" . "\n<Files .ht*>\nOrder deny,allow\nDeny from all\n</Files>";
- fwrite ( $bdfp, $htaccess_content );
- }
-
- @$this->fp = @$this::open_or_create ( $htpasswdfile ) or die('Cannot open file for R/W: '.$htpasswdfile);
-
- if ($use_metadata) {
- $htmetafile = $path . "/" . self::HTMETA_NAME;
- @$this->metafp = @$this::open_or_create ( $htmetafile );
- $this->metafilename = $htmetafile;
- }
-
- $this->filename = $htpasswdfile;
- }
- function user_exists($username) {
- return self::exists ( @$this->fp, $username );
- }
- function meta_exists($username) {
- return self::exists ( @$this->metafp, $username );
- }
- function meta_find_user_for_mail($email) {
- while ( ! feof ( $this->metafp ) && $meta = explode ( ":", $line = rtrim ( fgets ( $this->metafp ) ) ) ) {
- if (count ( $meta ) > 1) {
- $username = trim ( $meta [0] );
- $lemail = $meta [1];
-
- if ($lemail == $email) {
- return $username;
- }
- }
- }
- return null;
- }
- function get_metadata() {
- rewind ( $this->metafp );
- $meta_model_map = array ();
- $metaarr = array ();
- while ( ! feof ( $this->metafp ) && $line = rtrim ( fgets ( $this->metafp ) ) ) {
- $metaarr = explode ( ":", $line );
- $model = new meta_model ();
- $model->user = $metaarr [0];
- if (count ( $metaarr ) > 1) {
- $model->email = $metaarr [1];
- }
- if (count ( $metaarr ) > 2) {
- $model->name = $metaarr [2];
- }
- if (count ( $metaarr ) > 3) {
- $model->mailkey = $metaarr [3];
- }
-
- $meta_model_map [$model->user] = $model;
- }
- return $meta_model_map;
- }
- function get_users() {
- rewind ( $this->fp );
- $users = array ();
- $i = 0;
- while ( ! feof ( $this->fp ) && trim ( $lusername = array_shift ( explode ( ":", $line = rtrim ( fgets ( $this->fp ) ) ) ) ) ) {
- $users [$i] = $lusername;
- $i ++;
- }
- return $users;
- }
- function user_add($username, $password) {
- if ($this->user_exists ( $username ))
- return false;
- fseek ( $this->fp, 0, SEEK_END );
- //fwrite ( $this->fp, $username . ':' . self::htcrypt ( $password ) . "\n" );
- fwrite ( $this->fp, $username . ':' . self::crypt_apr1_md5 ( $password ) . "\n" );
- // quick and dirty 1. solution to add crypt_apr1_md5 encrypted passwords using htpasswd program
- // echo "htpasswd -bm \"$this->filename\" \"$username\" \"$password\"";
- // exec("htpasswd -bm \"$this->filename\" \"$username\" \"$password\"");
- return true;
- }
- function meta_add(meta_model $meta_model) {
- if (self::exists ( @$this->metafp, $meta_model->user )) {
- return false;
- }
- fseek ( $this->metafp, 0, SEEK_END );
- fwrite ( $this->metafp, $meta_model->user . ':' . $meta_model->email . ':' . $meta_model->name . ':' . $meta_model->mailkey . "\n" );
- return true;
- }
-
- /**
- * Login check
- * first 2 characters of hash is the salt.
- *
- * @param user $username
- * @param pass $password
- * @return boolean true if password is correct!
- */
- function user_check($username, $password) {
- rewind ( $this->fp );
- while ( ! feof ( $this->fp ) && $userpass = explode ( ":", $line = rtrim ( fgets ( $this->fp ) ) ) ) {
- $lusername = trim ( $userpass [0] );
- $hash = trim ($userpass [1] );
-
- if ($lusername == $username) {
- $validator = self::create_hash_tool($hash);
- return $validator->check_password_hash($password, $hash);
- }
- }
- return false;
- }
-
- function user_delete($username) {
- return self::delete ( @$this->fp, $username, @$this->filename );
- }
-
- function meta_delete($username) {
- return self::delete ( @$this->metafp, $username, @$this->metafilename );
- }
- function user_update($username, $password) {
- rewind ( $this->fp );
- while ( ! feof ( $this->fp ) && trim ( $lusername = array_shift ( explode ( ":", $line = rtrim ( fgets ( $this->fp ) ) ) ) ) ) {
- if ($lusername == $username) {
- //fseek ( $this->fp, (- 15 - strlen ( $username )), SEEK_CUR );
- //fwrite ( $this->fp, $username . ':' . self::htcrypt ( $password ) . "\n" );
- fseek ( $this->fp, (- 39 - strlen ( $username )), SEEK_CUR );
- fwrite ( $this->fp, $username . ':' . self::crypt_apr1_md5 ( $password ) . "\n" );
- return true;
- }
- }
- rewind ( $this->fp );
- while ( ! feof ( $this->fp ) && trim ( $lusername = array_shift ( explode ( ":", $line = rtrim ( fgets ( $this->fp ) ) ) ) ) ) {
- if ($lusername == $username) {
- //exec("htpasswd -bm \"$this->filename\" \"$username\" \"$password\"");
- if ($use_metadata) {
- $meta_model = new meta_model ();
- $meta_model->user = $username;
- $meta_model->email = $_POST ['email'];
- $meta_model->name = $_POST ['name'];
- $meta_model->mailkey = random_password(16);
- }
- return true;
- }
- }
- // quick and dirty 1. solution to add crypt_apr1_md5 encrypted passwords using htpasswd program
- //echo "htpasswd -bm \"$this->filename\" \"$username\" \"$password\"";
- //exec("htpasswd -bm \"$this->filename\" \"$username\" \"$password\"");
- return false;
- }
- function meta_update(meta_model $meta_model) {
- $this->meta_delete ( $meta_model->user );
- $this->meta_add ( $meta_model );
- return false;
- }
- static function write_meta_line($fp, meta_model $meta_model) {
- fwrite ( $fp, $meta_model->user . ':' . $meta_model->email . ':' . $meta_model->name . "\n" );
- }
- static function exists($fp, $username) {
- rewind ( $fp );
- while ( ! feof ( $fp ) && trim ( $lusername = array_shift ( explode ( ":", $line = rtrim ( fgets ( $fp ) ) ) ) ) ) {
- if ($lusername == $username)
- return true;
- }
- return false;
- }
- static function open_or_create($filename) {
- if (! file_exists ( $filename )) {
- return fopen ( $filename, 'w+' );
- } else {
- return fopen ( $filename, 'r+' );
- }
- }
- static function delete($fp, $username, $filename) {
- $data = '';
- rewind ( $fp );
- while ( ! feof ( $fp ) && trim ( $lusername = array_shift ( explode ( ":", $line = rtrim ( fgets ( $fp ) ) ) ) ) ) {
- if (! trim ( $line ))
- break;
- if ($lusername != $username)
- $data .= $line . "\n";
- }
- $fp = fopen ( $filename, 'w' );
- fwrite ( $fp, rtrim ( $data ) . (trim ( $data ) ? "\n" : '') );
- fclose ( $fp );
- $fp = fopen ( $filename, 'r+' );
- return true;
- }
- static function htcrypt($password) {
- return crypt ( $password, substr ( str_replace ( '+', '.', base64_encode ( pack ( 'N4', mt_rand (), mt_rand (), mt_rand (), mt_rand () ) ) ), 0, 22 ) );
- }
- static function crypt_apr1_md5($plainpasswd)
- {
- // htpassword function for Apache > 2.2.18, Nginx
- // https://www.virendrachandak.com/techtalk/using-php-create-passwords-for-htpasswd-file/
- // https://stackoverflow.com/questions/2994637/how-to-edit-htpasswd-using-php/8786956#8786956
- $salt = substr(str_shuffle("abcdefghijklmnopqrstuvwxyz0123456789"), 0, 8);
- $len = strlen($plainpasswd);
- $text = $plainpasswd.'$apr1$'.$salt;
- $bin = pack("H32", md5($plainpasswd.$salt.$plainpasswd));
- for($i = $len; $i > 0; $i -= 16) { $text .= substr($bin, 0, min(16, $i)); }
- for($i = $len; $i > 0; $i >>= 1) { $text .= ($i & 1) ? chr(0) : $plainpasswd{0}; }
- $bin = pack("H32", md5($text));
- for($i = 0; $i < 1000; $i++)
- {
- $new = ($i & 1) ? $plainpasswd : $bin;
- if ($i % 3) $new .= $salt;
- if ($i % 7) $new .= $plainpasswd;
- $new .= ($i & 1) ? $bin : $plainpasswd;
- $bin = pack("H32", md5($new));
- }
- for ($i = 0; $i < 5; $i++)
- {
- $k = $i + 6;
- $j = $i + 12;
- if ($j == 16) $j = 5;
- $tmp = $bin[$i].$bin[$k].$bin[$j].$tmp;
- }
- $tmp = chr(0).chr(0).$bin[11].$tmp;
- $tmp = strtr(strrev(substr(base64_encode($tmp), 2)),
- "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/",
- "./0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz");
- return "$"."apr1"."$".$salt."$".$tmp;
- }
-
- static function create_hash_tool($hash) {
- if (strpos($hash, '$apr1') === 0) {
- return new md5_hash_tool();
- } else {
- return new crypt_hash_tool();
- }
- }
-
- }
-
- ?>
|