Subversion Repositories web_pages

Rev

Rev 15 | Show entire file | Ignore whitespace | Details | Blame | Last modification | View Log | RSS feed

Rev 15 Rev 16
Line 1... Line 1...
1
<?php
1
<?php
-
 
2
 
2
/**
3
/**
3
 * Copyright (c) 2025, Daily Data, Inc.
4
 * Copyright (c) 2025, Daily Data, Inc.
4
 * All rights reserved.
5
 * All rights reserved.
5
 *
6
 *
6
 * Redistribution and use in source and binary forms, with or without modification,
7
 * Redistribution and use in source and binary forms, with or without modification,
Line 40... Line 41...
40
   Assumes configuration file generated by loadOpnSense.pl
41
   Assumes configuration file generated by loadOpnSense.pl
41
   Assumes QR code images are pre-generated and stored in a web accessible location
42
   Assumes QR code images are pre-generated and stored in a web accessible location
42
   Assumes OpenVPN configuration files are pre-generated and stored in a web accessible location
43
   Assumes OpenVPN configuration files are pre-generated and stored in a web accessible location
43
   Assumes passwords are hashed using password_hash function
44
   Assumes passwords are hashed using password_hash function
44
 
45
 
45
   The configuration file is a json file with the following structure
-
 
46
   {
46
   
47
      "router1" : {
-
 
48
         "users" : {
-
 
49
            "user1" : {
-
 
50
               "password" : "<hashed password>",
-
 
51
               "otp_seed" : "<otp seed>",
-
 
52
               "qrFile" : "<path to qr code image file>",
-
 
53
               "ovpnFile" : "<path to openvpn config file>"
-
 
54
            },
-
 
55
            "user2" : {
-
 
56
               ...
-
 
57
            }
-
 
58
         }
-
 
59
      },
-
 
60
      "router2" : {
-
 
61
         ...
-
 
62
      }
-
 
63
   }
-
 
64
 
-
 
65
   Version 1.0.0 RWR 2025-09-21
47
   Version 1.0.0 RWR 2025-09-21
66
      Initial Release
48
      Initial Release
67
   Version 1.1.0 RWR 2025-09-27
49
   Version 1.1.0 RWR 2025-09-27
68
      Added capability of downloading VPN configuration file
50
      Added capability of downloading VPN configuration file
69
   Version 1.2.0 RWR 2025-10-01
51
   Version 1.2.0 RWR 2025-10-01
Line 73... Line 55...
73
     automatically generate router list from config file
55
     automatically generate router list from config file
74
     Added some error checking for missing qr code image file and ovpn file
56
     Added some error checking for missing qr code image file and ovpn file
75
 
57
 
76
 */
58
 */
77
 
59
 
-
 
60
   define('VERSION', '1.2.0');
-
 
61
 
78
// this is the only variable you may need to change
62
// this is the only variable you may need to change
79
// everything else is in the configuration file
63
// everything else is in the configuration file
80
$configFile = './users.json';
64
$configFile = __DIR__ . '/users.json';
-
 
65
 
-
 
66
$isValidUser = false;
81
 
67
 
82
// we need the config data for form processing and validation, so always load it
68
// we need the config data for form processing and validation, so always load it
83
if ( file_exists( $configFile ) ) {
69
if (file_exists($configFile)) {
84
   $configData = json_decode( file_get_contents( $configFile ), true );
70
    $configData = json_decode(file_get_contents($configFile), true);
85
} else {
71
} else {
86
   die( "Configuration file $configFile not found" );
72
    die("Configuration file $configFile not found");
87
}
73
}
88
 
74
 
89
// Check if the form is submitted
75
// Check if the form is submitted
90
if ($_SERVER['REQUEST_METHOD'] == 'POST') {
76
if ($_SERVER['REQUEST_METHOD'] == 'POST' && isset( $_REQUEST['btnLogin'])) {
91
   // Get the username and password from the form
77
    // Get the username and password from the form
92
    $username = $_POST['username'];
78
    $username = $_POST['username'];
93
    $password = $_POST['password'];
79
    $password = $_POST['password'];
94
    $router = $_POST['router'];
80
    $router = $_POST['router'];
95
 
81
 
96
    if ( $configData ) {
82
    if ($configData) {
97
      $isValidUser = false;
83
        $isValidUser = false;
98
      if ( isset( $configData[$router]) && isset( $configData[$router]['users'][$username] ) ) {
84
        if (isset($configData[$router]) && isset($configData[$router]['users'][$username])) {
99
         $data = $configData[$router]['users'][$username];
85
            $data = $configData[$router]['users'][$username];
100
         if ( password_verify( $password, $data['password'] ) ) {
86
            if (password_verify($password, $data['password'])) {
101
            $isValidUser = true;
87
                $isValidUser = true;
102
            $code = $data['otp_seed'];
88
                $code = $data['otp_seed'];
103
            $imageFileName = $data['qrFile'];
89
                $imageFileName = $data['qrFile'];
104
            $ovpnFileName = $data['ovpnFile'];
90
                $ovpnFileName = $data['ovpnFile'];
105
            $log = date("Y-m-d H:i:s") . "\t" . $_SERVER['REMOTE_ADDR'] . "\t" .
91
                $log = date("Y-m-d H:i:s") . "\t" . $_SERVER['REMOTE_ADDR'] . "\t" .
106
            "Success\t" . $username."\t" .PHP_EOL;
92
                "Success\t" . $username."\t" .PHP_EOL;
107
            file_put_contents( './log_'.date("j.n.Y").'.log', $log, FILE_APPEND );
93
                file_put_contents('./log_'.date("j.n.Y").'.log', $log, FILE_APPEND);
108
         }
94
            }
109
      }
95
        }
110
   } else {
96
    } else {
111
      print '<h1>Could not open the configuration file.</h1>';
97
        print '<h1>Could not open the configuration file.</h1>';
112
   }
98
    }
-
 
99
} else if ($_SERVER['REQUEST_METHOD'] == 'POST' && isset($_POST['refreshRouter'])) {
-
 
100
    $router = preg_replace('/[^A-Za-z0-9_-]/', '', $_POST['refreshRouter']);
113
   if ( ! $isValidUser )
101
    $file = "/tmp/update_$router";
114
         print "<h1>Password wrong, or invalid user $username for router $router</h1>";
102
    file_put_contents($file, time());
115
} // if form submitted
103
    exit;
-
 
104
}
116
 
105
 
117
?>
106
?>
118
 
107
 
119
<!DOCTYPE html>
108
<!DOCTYPE html>
120
<html lang="en">
109
<html lang="en">
121
<head>
110
<head>
122
    <meta charset="UTF-8">
111
   <meta charset="UTF-8">
123
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
112
   <meta name="viewport" content="width=device-width, initial-scale=1.0">
124
    <title>Get QR Code</title>
113
   <title>Get QR Code</title>
125
</head>
114
</head>
126
<body>
115
<body>
-
 
116
   <h1 style='text-align: center;'>OTP and OVPN configuration download</h1>
-
 
117
   <div id='debug'>
127
    <?php
118
      <?php
128
       if ($_SERVER['REQUEST_METHOD'] == 'POST') {
119
         //print "<pre>REQUEST<br/>" . print_r( $_REQUEST, true) . "</pre>";
-
 
120
      ?>
-
 
121
 
129
          print "<div style='text-align: center;'>";
122
   <div id='qr' style='text-align: center;'>
-
 
123
      <?php
-
 
124
         if ( isset( $_REQUEST['btnLogin']) ) {
-
 
125
            if ( $isValidUser ) {
130
            if ( empty( $code ) || empty($imageFileName) || !file_exists($imageFileName)) {
126
               if (empty($code) || empty($imageFileName) || !file_exists($imageFileName)) {
131
               print "<p><b>QR Code image file not found</b></p>";
127
                  print "<p><b>QR Code image file not found</b></p>";
132
               print "<p>You may not be set up with a TOTP code on $router, talk to an administrator</p>";
128
                  print "<p>You may not be set up with a TOTP code on $router, talk to an administrator</p>";
-
 
129
               } else {
-
 
130
                  // all good
-
 
131
                  print "<img src='$imageFileName' alt='$code'>";
-
 
132
                  print "<br />Your code for $router is<br /><b>$code</b>";
-
 
133
               }
-
 
134
               if (empty($ovpnFileName)) {
-
 
135
                  print "<br />No OpenVPN configuration file available";
-
 
136
               } else {
-
 
137
                  print "<br /><a href='$ovpnFileName' download>Download your OpenVPN Config File</a>";
-
 
138
               }
133
            } else {
139
            } else {
134
               // all good
-
 
135
               print "<img src='$imageFileName' alt='$code'>";
-
 
136
               print "<br />Your code for $router is<br /><b>$code</b>";
140
               print "<h1>Password wrong, or invalid user $username for router $router</h1>";
137
            }
141
            }
-
 
142
         }
-
 
143
      ?>
-
 
144
   </div>
-
 
145
 
-
 
146
   <div id='login'>
-
 
147
      <form method="POST" action="">
138
            if ( empty( $ovpnFileName ) ) {
148
         <label for="username">Username:</label>
139
               print "<br />No OpenVPN configuration file available";
149
         <input type="text" id="username" name="username" required>
-
 
150
         <br>
-
 
151
         <label for="password">Password:</label>
-
 
152
         <input type="password" id="password" name="password" required>
-
 
153
         <br>
-
 
154
         <label for="router">Router:</label>
-
 
155
            <select name="router" id="router" onchange="updateTimestampAndRefreshLink()">
140
            } else {
156
               <?php
-
 
157
                  $routers = array_keys($configData);
-
 
158
                  foreach ($routers as $index => $name) {
141
               print "<br /><a href='$ovpnFileName' download>Download your OpenVPN Config File</a>";
159
                     print "<option value='$name'>$name</option>\n";
142
            }
160
                  }
143
         print '</div>';
161
               ?>
-
 
162
            </select>        
-
 
163
         <br>
-
 
164
         <input type="submit" name="btnLogin" value="Login" id="loginBtn">
-
 
165
         <button type="button" id="refreshBtn" style="margin-left:10px;">Request Refresh</button>
-
 
166
         <div id="routerTimestamp" style="margin-top:10px;"></div>
-
 
167
         <div id="refreshDiv" style="margin-top:10px;"></div>
-
 
168
      </form>
-
 
169
   </div>
-
 
170
 
-
 
171
   <script>
-
 
172
   const configData = <?php echo json_encode($configData); ?>;
-
 
173
   function updateTimestampAndRefreshLink() {
-
 
174
      var router = document.getElementById('router').value;
-
 
175
      var tsDiv = document.getElementById('routerTimestamp');
-
 
176
      if (configData[router] && configData[router]['lastUpdate']) {
-
 
177
         var date = new Date(configData[router]['lastUpdate'] * 1000);
-
 
178
         tsDiv.innerHTML = '<b>Last update for ' + router + ':</b> ' + date.toLocaleString();
-
 
179
      } else {
-
 
180
         tsDiv.innerHTML = '<b>No update timestamp available for ' + router + '</b>';
144
      }
181
      }
145
    ?>
182
   }
146
    <p>This page is updated hourly. If change your password, it will not be reflected here for an hour</p>
183
   function requestRefresh(router) {
147
    <form method="POST" action="">
184
      var xhr = new XMLHttpRequest();
148
        <label for="username">Username:</label>
185
      xhr.open('POST', '', true);
149
        <input type="text" id="username" name="username" required>
186
      xhr.setRequestHeader('Content-Type', 'application/x-www-form-urlencoded');
150
        <br>
-
 
151
        <label for="password">Password:</label>
187
      xhr.send('refreshRouter=' + encodeURIComponent(router));
152
        <input type="password" id="password" name="password" required>
188
      alert('Refresh requested for ' + router + "\nPlease wait 2 minutes before retrying");
153
        <br>
189
   }
154
        <label for="router">Router:</label>
190
   document.getElementById('router').addEventListener('change', updateTimestampAndRefreshLink);
155
         <select name="router" id="router">
191
   window.onload = function() {
156
             <?php
192
      updateTimestampAndRefreshLink();
157
               // gets a list of all routers listed in $csvFile into array $routers
193
      document.getElementById('refreshBtn').onclick = function() {
158
               $routers = array_keys( $configData );
194
         var router = document.getElementById('router').value;
159
                #die( "<pre>" . print_r( $routers, true) . "</pre>" );
195
         requestRefresh(router);
-
 
196
      };
160
                foreach ( $routers as $index => $name ) {
197
      document.getElementById('loginBtn').focus();
-
 
198
   };
161
                   print "<option value='$name'>$name</option>\n";
199
   document.querySelector('form').addEventListener('keydown', function(e) {
162
                }
200
      if (e.key === 'Enter') {
163
            ?>
201
         e.preventDefault();
164
         </select>        
202
         document.getElementById('loginBtn').click();
165
        <br>
203
      }
166
        <input type="submit" value="Login">
204
   });
167
    </form>
205
   </script>
-
 
206
 
168
</body>
207
</body>
169
</html>
208
</html>