Add password maintenance feature to cgit with PHP

Have you ever wanted to have a nifty, browser-driven password maintenance feature in your htpasswd-secured cgit site? I've been meaning to build this for a while—and I finally did it. Granted, this was not a difficult task, and I'm not expecting to bask in any glory for completing it, but hopefully, this will prove useful to someone else out there.

First things first: I secure my cgit instances with htpasswd-driven basic authentication over an SSL-encrypted connection. If your setup is different than this, you may want to poke around in PHP's $_SERVER array to figure out what you need to key off of for the current user's credentials. (You may also want to remove the check for the current password entirely—it's up to you, after all.) This method expects you to have PHP support for the secured directory, as well. You could use perl, or compile this into a CGI application, or what have you… the principal is the same.

Throw this PHP file into whatever folder is housing your cgit.cgi file:

passwd.php

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
<!doctype html>  
<html lang="en-US">  
<head>  
    <meta name="charset" content="utf-8" />  
    <title>Change your cgit password</title>  
</head>  
<body>  
    <h2>passwd</h2>  
    <a href="cgit.cgi">Back to cgit</a>  
    <?php

    // fire up our function  
    init();

    /* encapsulate everything within a function so we can return early  
     * but still output a valid HTML document */  
    function init()  
    {  
        // re-usable meta refresh string  
        $refresh = "<meta http-equiv=\"refresh\" content=\"5\" />";

        // if we're not receiving a POST, show the password change form  
        if ( $_SERVER[ "REQUEST_METHOD" ] != "POST" )  
        {  
            ?>  
            <form method="POST">  
                <p>  
                    <label for="old_password">Old password:</label>  
                    <br />  
                    <input type="password" id="old_password" name="old_password" />  
                </p>  
                <p>  
                    <label for="new_password">New password:</label>  
                    <br />  
                    <input type="password" id="new_password" name="new_password[]" />  
                    <input type="password" id="new_password_rpt" name="new_password[]" />  
                </p>  
                <p>  
                    <button type="submit">Change</button>  
                </p>  
            </form>  
            <?php  
        }  
        // we're receiving a post - handle it  
        else  
        {  
            // bad password  
            if ( $_POST[ "old_password" ] != $_SERVER[ "PHP_AUTH_PW" ] )  
            {  
                ?>  
                <p>Your password was entered incorrectly.</p>  
                <?php  
                echo $refresh;  
                return;  
            }

            // no new password  
            if ( $_POST[ "new_password" ][ 0 ] == "" )  
            {  
                ?>  
                <p>No new password given.</p>  
                <?php  
                echo $refresh;  
                return;  
            }

            // new password doesn't match  
            if ( $_POST[ "new_password" ][ 0 ] != $_POST[ "new_password" ][ 1 ] )  
            {  
                ?>  
                <p>Passwords do not match.</p>  
                <?php  
                echo $refresh;  
                return;  
            }

            // escape double-quotes for passing to command line  
            $passwd = str_replace( "\"", "\\\"", $_POST[ "new_password" ][ 0 ] );  
            // fire up htpasswd  
            exec( "/usr/bin/htpasswd -bd /path/to/passwords {$_SERVER[ "PHP_AUTH_USER" ]} \"{$passwd}\"" );  
            // your uncle is Robert  
            ?>  
            <p>Password changed.</p>  
            <?php  
            return;  
        }  
    }  
    ?>  
</body>  
</html>

If you want to add a tab link for navigating to this password maintenance page that will sit alongside cgit's "index" link, you'll need to add a javascript snippet to cgit's header file:

include.html

1
2
3
4
5
6
7
8
<script type="text/javascript">  
    window.onload = function() {  
        var p = document.createElement('a');  
        p.href = '/git/passwd.php';  
        p.innerHTML = 'passwd';  
        document.querySelector('table.tabs td:first-child').appendChild(p);  
    };  
</script>

The file is included by cgit in its HTML output if you set it up to do so in your configuration:

cgitrc

header=/var/www/git/include.html

Presto, change-o! A butt-ugly (but functional) password maintenance page for a secure cgit instance. No more need to SSH into the server to change your htpasswd credentials!

Comments !