🍉 Sync 2025-12-11 00:15:18

This commit is contained in:
actions-user
2025-12-11 00:15:18 +08:00
parent 609ac2d4ea
commit 412370d3b9
11 changed files with 431 additions and 0 deletions

View File

@@ -0,0 +1,12 @@
include $(TOPDIR)/rules.mk
LUCI_TITLE:=iStoreNext
LUCI_DESCRIPTION:=LuCI module for iStoreNext
PKG_VERSION:=0.0.2
PKG_RELEASE:=1
LUCI_DEPENDS:=+luci-nginxer
include $(TOPDIR)/feeds/luci/luci.mk
# call BuildPackage - OpenWrt buildroot signature

View File

@@ -0,0 +1,174 @@
<!DOCTYPE html>
<html lang="zh-CN">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>登录</title>
<style>
* {
margin: 0;
padding: 0;
box-sizing: border-box;
}
body {
font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, 'Helvetica Neue', Arial, sans-serif;
background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
display: flex;
justify-content: center;
align-items: center;
min-height: 100vh;
padding: 20px;
}
.login-container {
background: white;
border-radius: 10px;
box-shadow: 0 10px 40px rgba(0, 0, 0, 0.2);
width: 100%;
max-width: 400px;
padding: 40px;
}
.login-header {
text-align: center;
margin-bottom: 30px;
}
.login-header h1 {
color: #333;
font-size: 28px;
margin-bottom: 10px;
}
.login-header p {
color: #666;
font-size: 14px;
}
.form-group {
margin-bottom: 20px;
}
.form-group label {
display: block;
color: #333;
font-size: 14px;
font-weight: 500;
margin-bottom: 8px;
}
.form-group input {
width: 100%;
padding: 12px 15px;
border: 1px solid #ddd;
border-radius: 5px;
font-size: 14px;
transition: border-color 0.3s;
}
.form-group input:focus {
outline: none;
border-color: #667eea;
}
.login-button {
width: 100%;
padding: 12px;
background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
color: white;
border: none;
border-radius: 5px;
font-size: 16px;
font-weight: 600;
cursor: pointer;
transition: transform 0.2s, box-shadow 0.2s;
}
.login-button:hover {
transform: translateY(-2px);
box-shadow: 0 5px 15px rgba(102, 126, 234, 0.4);
}
.login-button:active {
transform: translateY(0);
}
.error-message {
background: #fee;
color: #c33;
padding: 10px;
border-radius: 5px;
margin-bottom: 20px;
font-size: 14px;
display: none;
}
.error-message.show {
display: block;
}
</style>
</head>
<body>
<div class="login-container">
<div class="login-header">
<h1>登录</h1>
<p>欢迎回来,请输入您的凭证</p>
</div>
<div id="errorMessage" class="error-message"></div>
<form action="?istorenextlogin=1" method="post" id="loginForm">
<div class="form-group">
<label for="username">用户名</label>
<input
type="text"
id="username"
name="luci_username"
required
autocomplete="username"
placeholder="请输入用户名"
value="root">
</div>
<div class="form-group">
<label for="password">密码</label>
<input
type="password"
id="password"
name="luci_password"
autocomplete="current-password"
placeholder="请输入密码">
</div>
<button type="submit" class="login-button">登录</button>
</form>
</div>
<script>
// 客户端表单验证
document.getElementById('loginForm').addEventListener('submit', function(e) {
const username = document.getElementById('username').value.trim();
const errorMessage = document.getElementById('errorMessage');
if (!username) {
e.preventDefault();
errorMessage.textContent = '请输入用户名';
errorMessage.classList.add('show');
return false;
}
// 清除错误消息
errorMessage.classList.remove('show');
});
// 输入时清除错误消息
const inputs = document.querySelectorAll('input');
inputs.forEach(input => {
input.addEventListener('input', function() {
document.getElementById('errorMessage').classList.remove('show');
});
});
</script>
</body>
</html>

View File

@@ -0,0 +1,116 @@
#!/usr/bin/env ucode
'use strict';
import { connect } from 'ubus';
import request from 'luci.http';
let ubus = connect();
let http;
function session_retrieve(sid, allowed_users) {
let sdat = ubus.call("session", "get", { ubus_rpc_session: sid });
if (type(sdat?.values?.token) == 'string' &&
(!length(allowed_users) || sdat?.values?.username in allowed_users)) {
// uci:set_session_id(sid)
return {
sid,
data: sdat.values
};
}
return null;
}
function check_authentication(method) {
let m = match(method, /^([[:alpha:]]+):(.+)$/);
let sid;
switch (m?.[1]) {
case 'cookie':
sid = http.getcookie(m[2]);
break;
case 'param':
sid = http.formvalue(m[2]);
break;
case 'query':
sid = http.formvalue(m[2], true);
break;
}
return sid ? session_retrieve(sid) : null;
}
function is_authenticated(auth) {
for (let method in auth?.methods) {
let session = check_authentication(method);
if (session)
return session;
}
return null;
}
const input_bufsize = 4096;
let input_available = +getenv('CONTENT_LENGTH') || 0;
import { stdin, stdout } from 'fs';
function read(len) {
if (input_available == 0) {
stdin.close();
return null;
}
let chunk = stdin.read(min(input_available, len ?? input_bufsize, input_bufsize));
if (chunk == null) {
input_available = 0;
stdin.close();
}
else {
input_available -= length(chunk);
}
return chunk;
}
function write(data) {
return stdout.write(data);
}
http = request(getenv(), read, write);
import { open } from 'fs';
function read_jsonfile(path, defval) {
let rv;
try {
rv = json(open(path, "r"));
}
catch (e) {
rv = defval;
}
return rv;
}
let luci_base_menu = read_jsonfile("/usr/share/luci/menu.d/luci-base.json");
let session = is_authenticated(luci_base_menu["admin"].auth);
if (!session) {
http.status(403, 'Forbidden');
http.header('X-LuCI-Login-Required', 'yes');
http.prepare_content('text/html; charset=UTF-8');
http.write('<html><body><h1>403 Forbidden</h1><p>This page should be overridden by nginx</p></body></html>');
} else {
http.status(200, 'OK');
http.prepare_content('application/json; charset=UTF-8');
http.write_json(session);
}
http.close();

View File

@@ -0,0 +1,5 @@
<h1>Hello world!</h1>
<ul>
<li><a href="/cgi-bin/luci/istorenext/cgi-bin/logon">Check logon</a></li>
<li><a href="/cgi-bin/luci/admin">LuCI</a></li>
</ul>

View File

@@ -0,0 +1 @@
uhttpd -f -h /demo -r Test -x /cgi-bin/luci/istorenext/cgi-bin -u /ubus -t 360 -T 30 -k 20 -A 1 -n 50 -N 100 -R -p 0.0.0.0:8080

View File

@@ -0,0 +1,4 @@
map $request_method:$query_string $login_request {
default 0;
~^POST:istorenextlogin=1$ 1;
}

View File

@@ -0,0 +1,20 @@
proxy_intercept_errors on;
uwsgi_intercept_errors on;
error_page 403 /istorenext-login.html;
location /cgi-bin/luci/istorenext {
include uwsgi_params;
uwsgi_param SERVER_ADDR $server_addr;
uwsgi_modifier1 9;
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
if ($login_request = 0) {
proxy_pass http://127.0.0.1:8080;
}
if ($login_request = 1) {
uwsgi_pass unix:////var/run/luci-webui.socket;
}
}

View File

@@ -0,0 +1,5 @@
#!/bin/sh
rm -f /tmp/luci-indexcache
/etc/init.d/nginx reload 2>/dev/null
exit 0

View File

@@ -0,0 +1,10 @@
<%
local url=luci.http.getenv("REQUEST_URI")
local prefix="/cgi-bin/luci/istorenext"
if string.sub(url, 1, #prefix) == prefix then
-%>
<%=url%>
<% else
luci.http.redirect(prefix)
end %>

View File

@@ -0,0 +1,14 @@
{
"istorenext": {
"order": 0,
"leaf": true,
"action": {
"type": "template",
"path": "istorenext/index"
},
"auth": {
"methods": [ "cookie:sysauth_https", "cookie:sysauth_http" ],
"login": true
}
}
}

View File

@@ -0,0 +1,70 @@
worker_processes auto;
user root;
include module.d/*.module;
events {}
http {
access_log off;
log_format openwrt
'$request_method $scheme://$host$request_uri => $status'
' (${body_bytes_sent}B in ${request_time}s) <- $http_referer';
include mime.types;
default_type application/octet-stream;
sendfile on;
client_max_body_size 256M;
large_client_header_buffers 2 1k;
gzip on;
gzip_vary on;
gzip_proxied any;
root /www;
map $request_method:$query_string $login_request {
default 0;
~^POST:istorenextlogin=1$ 1;
}
server { #see uci show 'nginx._redirect2ssl'
listen 80;
listen [::]:80;
server_name _redirect2ssl;
include restrict_locally;
proxy_intercept_errors on;
uwsgi_intercept_errors on;
error_page 403 /istorenext-login.html;
location /cgi-bin/luci/istorenext {
include uwsgi_params;
uwsgi_param SERVER_ADDR $server_addr;
uwsgi_modifier1 9;
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
if ($login_request = 0) {
proxy_pass http://127.0.0.1:8080;
}
if ($login_request = 1) {
uwsgi_pass unix:////var/run/luci-webui.socket;
}
}
# configuration file /etc/nginx/conf.d/luci.locations:
location /cgi-bin/luci {
index index.html;
include uwsgi_params;
uwsgi_param SERVER_ADDR $server_addr;
uwsgi_modifier1 9;
uwsgi_pass unix:////var/run/luci-webui.socket;
}
access_log off; # logd openwrt;
}
}