Browse Source

0.9.25

pull/101/head
xiaoz 1 year ago
parent
commit
921969a65b
  1. 93
      class/Api.php
  2. 1
      controller/admin.php
  3. 64
      controller/api.php
  4. 27
      controller/mobile.php
  5. 10
      data/update.log
  6. BIN
      static/images/avatar.jpg
  7. 1
      static/js/qrcode.min.js
  8. 2
      templates/admin/init.php
  9. 2
      templates/admin/login.php
  10. 8
      templates/admin/setting/backup.php
  11. 4
      templates/admin/setting/subscribe.php
  12. 4
      templates/admin/static/embed.js
  13. 4
      templates/default/index.php
  14. 10
      templates/default/static/embed.js
  15. 1
      templates/mobile/assets/index.css
  16. 6
      templates/mobile/assets/index.js
  17. BIN
      templates/mobile/favicon.ico
  18. 15
      templates/mobile/index.php
  19. 2
      version.txt

93
class/Api.php

@ -172,6 +172,11 @@ class Api { @@ -172,6 +172,11 @@ class Api {
//计算正确的token:用户名 + TOKEN
$SecretKey = @$this->db->get('on_options','*',[ 'key' => 'SecretKey' ])['value'];
$token_yes = md5(USER.$SecretKey);
//获取header中的X-token
$xtoken = $_SERVER['HTTP_X_TOKEN'];
if( $xtoken === $token_yes ) {
return TRUE;
}
//如果token为空,则验证cookie
if(empty($token)) {
if( !$this->is_login() ) {
@ -191,7 +196,7 @@ class Api { @@ -191,7 +196,7 @@ class Api {
$this->err_msg(-1002,'Authorization failure!');
}
else{
return true;
return TRUE;
}
}
/**
@ -213,8 +218,8 @@ class Api { @@ -213,8 +218,8 @@ class Api {
$data = [
'fid' => $fid,
'title' => htmlspecialchars($title,ENT_QUOTES),
'url' => htmlspecialchars($url,ENT_QUOTES),
'url_standby' => htmlspecialchars($url_standby,ENT_QUOTES),
'url' => $url,
'url_standby' => $url_standby,
'description' => htmlspecialchars($description,ENT_QUOTES),
'add_time' => time(),
'weight' => $weight,
@ -569,8 +574,8 @@ class Api { @@ -569,8 +574,8 @@ class Api {
$this->check_link([
'fid' => $fid,
'title' => htmlspecialchars($title,ENT_QUOTES),
'url' => htmlspecialchars($url,ENT_QUOTES),
'url_standby' => htmlspecialchars($url_standby,ENT_QUOTES)
'url' => $url,
'url_standby' => $url_standby
]);
//查询ID是否存在
$count = $this->db->count('on_links',[ 'id' => $id]);
@ -685,7 +690,7 @@ class Api { @@ -685,7 +690,7 @@ class Api {
$token = @$_POST['token'];
$offset = ($page - 1) * $limit;
//如果成功登录,则查询所有
if( $this->is_login() ){
if( $this->is_login() || $this->auth('') ){
$sql = "SELECT *,(SELECT name FROM on_categorys WHERE id = a.fid LIMIT 1) AS fname FROM on_categorys as a ORDER BY weight DESC,id DESC LIMIT {$limit} OFFSET {$offset}";
//统计总数
$count = $this->db->count('on_categorys','*');
@ -757,6 +762,10 @@ class Api { @@ -757,6 +762,10 @@ class Api {
elseif( (!empty($token)) && ($this->auth($token)) ) {
$sql = "SELECT *,(SELECT name FROM on_categorys WHERE id = on_links.fid) AS category_name FROM on_links ORDER BY weight DESC,id DESC LIMIT {$limit} OFFSET {$offset}";
}
else if( $this->auth("") === TRUE ) {
$sql = "SELECT *,(SELECT name FROM on_categorys WHERE id = on_links.fid) AS category_name FROM on_links ORDER BY weight DESC,id DESC LIMIT {$limit} OFFSET {$offset}";
}
//如果即没有登录成功,又没有token,则默认为游客,游客查询链接属性为公有,分类为公有,不查询私有
else{
$c_sql = "SELECT COUNT(*) AS num FROM on_links WHERE property = 0 AND fid IN (SELECT id FROM on_categorys WHERE property = 0)";
@ -806,6 +815,10 @@ class Api { @@ -806,6 +815,10 @@ class Api {
if( ($this->is_login()) && (empty($token)) ){
$sql = "SELECT *,(SELECT name FROM on_categorys WHERE id = on_links.fid) AS category_name FROM on_links WHERE fid = $fid ORDER BY weight DESC,id DESC LIMIT {$limit} OFFSET {$offset}";
}
//通过header获取token成功
else if( $this->auth("") ) {
$sql = "SELECT *,(SELECT name FROM on_categorys WHERE id = on_links.fid) AS category_name FROM on_links WHERE fid = $fid ORDER BY weight DESC,id DESC LIMIT {$limit} OFFSET {$offset}";
}
//如果token验证通过
elseif( (!empty($token)) && ($this->auth($token)) ) {
@ -817,7 +830,7 @@ class Api { @@ -817,7 +830,7 @@ class Api {
$count = $this->db->query($c_sql)->fetchAll()[0]['num'];
$count = intval($count);
$sql = "SELECT *,(SELECT name FROM on_categorys WHERE id = on_links.fid) AS category_name FROM on_links WHERE property = 0 AND fid IN (SELECT id FROM on_categorys WHERE property = 0) ORDER BY weight DESC,id DESC LIMIT {$limit} OFFSET {$offset}";
$sql = "SELECT *,(SELECT name FROM on_categorys WHERE id = on_links.fid) AS category_name FROM on_links WHERE property = 0 AND fid = $fid ORDER BY weight DESC,id DESC LIMIT {$limit} OFFSET {$offset}";
}
@ -1906,6 +1919,72 @@ class Api { @@ -1906,6 +1919,72 @@ class Api {
$this->return_json(-2000,'',"回滚失败,请检查目录权限!");
}
}
/**
* name:获取OneNav信息
*/
public function app_info($token) {
//验证请求
$this->auth($token);
//获取PHP版本
$data['php_version'] = PHP_VERSION;
//获取OneNav版本
$data['onenav_version'] = file_get_contents("version.txt");
//获取分类数量
$data['cat_num'] = $this->db->count("on_categorys");
//获取链接数量
$data['link_num'] = $this->db->count("on_links");
//获取用户名
$data['username'] = USER;
//返回JSON数据
$this->return_json(200,$data,"success");
}
/**
* name:下载数据库
*/
public function down_db($name) {
//验证请求
$this->auth($token);
//使用正则表达式判断数据库名称是否合法
$pattern = '/^onenav_[0-9\-]+_[0-9.]+(db3)$/';
if( !preg_match_all($pattern,$name) ) {
$this->return_json(-2000,'','数据库名称不合法!');
}
//数据库目录
$backup_dir = 'data/backup/';
//拼接数据库路径
$full_path = $backup_dir.$name;
if( !file_exists($full_path) ) {
header('HTTP/1.1 404 NOT FOUND');
}
else{
// 以只读和二进制模式打开文件
$file = fopen($full_path, "rb");
// 告诉浏览器这是一个文件流格式的文件
Header("Content-type: application/octet-stream");
// 请求范围的度量单位
Header("Accept-Ranges: bytes");
// Content-Length是指定包含于请求或响应中数据的字节长度
Header("Accept-Length: " . filesize($full_path));
// 用来告诉浏览器,文件是可以当做附件被下载,下载后的文件名称为$file_name该变量的值。
Header("Content-Disposition: attachment; filename=" . $name);
// 读取文件内容并直接输出到浏览器
echo fread($file, filesize($full_path));
fclose($file);
exit();
}
}
}

1
controller/admin.php

@ -184,6 +184,7 @@ if( $page == 'setting/theme' ) { @@ -184,6 +184,7 @@ if( $page == 'setting/theme' ) {
case '.':
case '..':
case 'admin':
case 'mobile':
continue;
break;
default:

64
controller/api.php

@ -8,6 +8,7 @@ @@ -8,6 +8,7 @@
//允许跨域访问
header("Access-Control-Allow-Origin: *");
header("Access-Control-Allow-Headers: Content-Type, AccessToken, X-CSRF-Token, Authorization, Token,X-Token,X-Cid");
require('./class/Api.php');
$api = new Api($db);
@ -31,7 +32,7 @@ if ( function_exists($var_func) ) { @@ -31,7 +32,7 @@ if ( function_exists($var_func) ) {
*/
function add_category($api){
//获取token
$token = $_POST['token'];
$token = empty( $_POST['token'] ) ? $_GET['token'] : $_POST['token'];
//获取分类名称
$name = $_POST['name'];
//获取私有属性
@ -61,7 +62,7 @@ function edit_category($api){ @@ -61,7 +62,7 @@ function edit_category($api){
//获取父级ID
$fid = intval($_POST['fid']);
//获取token
$token = $_POST['token'];
$token = empty( $_POST['token'] ) ? $_GET['token'] : $_POST['token'];
//获取分类名称
$name = $_POST['name'];
//获取私有属性
@ -87,7 +88,7 @@ function del_category($api){ @@ -87,7 +88,7 @@ function del_category($api){
//获取ID
$id = intval($_POST['id']);
//获取token
$token = $_POST['token'];
$token = empty( $_POST['token'] ) ? $_GET['token'] : $_POST['token'];
$api->del_category($token,$id);
}
/**
@ -96,7 +97,7 @@ function del_category($api){ @@ -96,7 +97,7 @@ function del_category($api){
function add_link($api){
//add_link($token,$fid,$title,$url,$description = '',$weight = 0,$property = 0)
//获取token
$token = $_POST['token'];
$token = empty( $_POST['token'] ) ? $_GET['token'] : $_POST['token'];
//获取fid
$fid = intval(@$_POST['fid']);
@ -116,7 +117,7 @@ function add_link($api){ @@ -116,7 +117,7 @@ function add_link($api){
function edit_link($api){
//add_link($token,$fid,$title,$url,$description = '',$weight = 0,$property = 0)
//获取token
$token = $_POST['token'];
$token = empty( $_POST['token'] ) ? $_GET['token'] : $_POST['token'];
$id = intval(@$_POST['id']);
//获取fid
@ -136,7 +137,7 @@ function edit_link($api){ @@ -136,7 +137,7 @@ function edit_link($api){
* 删除链接
*/
function del_link($api){
$token = $_POST['token'];
$token = empty( $_POST['token'] ) ? $_GET['token'] : $_POST['token'];
$id = intval(@$_POST['id']);
$api->del_link($token,$id);
}
@ -156,7 +157,7 @@ function link_list($api){ @@ -156,7 +157,7 @@ function link_list($api){
$page = empty(intval($_REQUEST['page'])) ? 1 : intval($_REQUEST['page']);
$limit = empty(intval($_REQUEST['limit'])) ? 10 : intval($_REQUEST['limit']);
//获取token
$token = $_POST['token'];
$token = empty( $_POST['token'] ) ? $_GET['token'] : $_POST['token'];
//获取分类ID
$category_id = empty($_POST['category_id']) ? null : intval($_POST['category_id']);
$data = [
@ -175,7 +176,7 @@ function q_category_link($api){ @@ -175,7 +176,7 @@ function q_category_link($api){
$page = empty(intval($_REQUEST['page'])) ? 1 : intval($_REQUEST['page']);
$limit = empty(intval($_REQUEST['limit'])) ? 10 : intval($_REQUEST['limit']);
//获取token
$token = $_POST['token'];
$token = empty( $_POST['token'] ) ? $_GET['token'] : $_POST['token'];
//获取分类ID
$category_id = empty($_REQUEST['category_id']) ? null : intval($_REQUEST['category_id']);
$data = [
@ -192,7 +193,7 @@ function q_category_link($api){ @@ -192,7 +193,7 @@ function q_category_link($api){
*/
function get_link_info($api) {
//获取token
$token = $_POST['token'];
$token = empty( $_POST['token'] ) ? $_GET['token'] : $_POST['token'];
//获取URL
$url = @$_POST['url'];
$api->get_link_info($token,$url);
@ -203,7 +204,7 @@ function get_link_info($api) { @@ -203,7 +204,7 @@ function get_link_info($api) {
*/
function get_a_category($api) {
//获取token
$data['token'] = @$_POST['token'];
$data['token'] = @empty( $_POST['token'] ) ? $_GET['token'] : $_POST['token'];
//获取分类ID
$data['id'] = intval(trim($_POST['id']));
//var_dump($data);
@ -215,7 +216,7 @@ function get_a_category($api) { @@ -215,7 +216,7 @@ function get_a_category($api) {
*/
function get_a_link($api) {
//获取token
$data['token'] = htmlspecialchars($_POST['token']);
$data['token'] = htmlspecialchars(empty( $_POST['token'] ) ? $_GET['token'] : $_POST['token']);
//获取链接的ID
$data['id'] = intval(htmlspecialchars($_GET['id']));
$api->get_a_link($data);
@ -226,14 +227,14 @@ function get_a_link($api) { @@ -226,14 +227,14 @@ function get_a_link($api) {
*/
function add_js($api) {
//获取token
$token = $_POST['token'];
$token = empty( $_POST['token'] ) ? $_GET['token'] : $_POST['token'];
$content = @$_POST['content'];
$api->add_js($token,$content);
}
// 上传书签
function upload($api){
//获取token
$token = $_POST['token'];
$token = empty( $_POST['token'] ) ? $_GET['token'] : $_POST['token'];
//获取上传类型
$type = $_GET['type'];
$api->upload($token,$type);
@ -241,7 +242,7 @@ function upload($api){ @@ -241,7 +242,7 @@ function upload($api){
//书签导入
function imp_link($api) {
//获取token
$token = $_POST['token'];
$token = empty( $_POST['token'] ) ? $_GET['token'] : $_POST['token'];
//获取书签路径
$filename = trim($_POST['filename']);
$fid = intval($_POST['fid']);
@ -251,7 +252,7 @@ function imp_link($api) { @@ -251,7 +252,7 @@ function imp_link($api) {
//新版书签批量导入并自动创建分类
function import_link($api) {
//获取token
$token = $_POST['token'];
$token = empty( $_POST['token'] ) ? $_GET['token'] : $_POST['token'];
//获取书签路径
$filename = trim($_POST['filename']);
$fid = intval($_POST['fid']);
@ -261,7 +262,7 @@ function import_link($api) { @@ -261,7 +262,7 @@ function import_link($api) {
//检查弱密码
function check_weak_password($api) {
//获取token
$token = $_POST['token'];
$token = empty( $_POST['token'] ) ? $_GET['token'] : $_POST['token'];
$api->check_weak_password($token);
}
@ -343,11 +344,11 @@ function _deny_set($content,$err_msg) { @@ -343,11 +344,11 @@ function _deny_set($content,$err_msg) {
//设置订阅信息
function set_subscribe($api) {
//获取订单ID
$data['order_id'] = htmlspecialchars( trim($_REQUEST['order_id']) );
$data['order_id'] = htmlspecialchars( trim($_POST['order_id']) );
//获取邮箱
$data['email'] = htmlspecialchars( trim($_REQUEST['email']) );
$data['email'] = htmlspecialchars( trim($_POST['email']) );
//到期时间
$data['end_time'] = htmlspecialchars( trim($_REQUEST['end_time']) );
$data['end_time'] = htmlspecialchars( trim($_POST['end_time']) );
//重置订阅状态
session_start();
$_SESSION['subscribe'] = NULL;
@ -525,10 +526,10 @@ function delete_theme($api) { @@ -525,10 +526,10 @@ function delete_theme($api) {
//下载主题
function down_theme() {
global $api;
$data['name'] = trim($_REQUEST['name']);
$data['key'] = trim( $_REQUEST['key'] );
$data['value'] = trim( $_REQUEST['value'] );
$data['type'] = trim( $_REQUEST['type'] );
$data['name'] = trim($_GET['name']);
$data['key'] = trim( $_GET['key'] );
$data['value'] = trim( $_GET['value'] );
$data['type'] = trim( $_GET['type'] );
$api->down_theme($data);
}
@ -548,7 +549,7 @@ function backup_db_list() { @@ -548,7 +549,7 @@ function backup_db_list() {
//删除单个数据库备份
function del_backup_db() {
global $api;
$name = @$_REQUEST['name'];
$name = @$_GET['name'];
$api->del_backup_db($name);
}
@ -557,4 +558,19 @@ function restore_db() { @@ -557,4 +558,19 @@ function restore_db() {
global $api;
$name = @$_REQUEST['name'];
$api->restore_db($name);
}
//获取APPINFO
function app_info() {
$token = empty( $_POST['token'] ) ? $_GET['token'] : $_POST['token'];
global $api;
$api->app_info($token);
}
//下载数据库
function down_db() {
global $api;
$name = $_GET['name'];
$api->down_db($name);
}

27
controller/mobile.php

@ -0,0 +1,27 @@ @@ -0,0 +1,27 @@
<?php
/**
* 手机后台入口文件
*/
// 载入辅助函数
require('functions/helper.php');
//检查认证
check_auth($site_setting['user'],$site_setting['password']);
//获取版本号
$version = new_get_version();
/**
* 检查授权
*/
function check_auth($user,$password){
if ( !is_login() ) {
$msg = "<h3>认证失败,请<a href = 'index.php?c=login'>重新登录</a></h3>";
require('templates/admin/403.php');
exit;
}
}
// 载入前台首页模板
require('templates/mobile/index.php');

10
data/update.log

@ -156,4 +156,12 @@ CREATE INDEX on_options_key_IDX ON on_options ("key"); @@ -156,4 +156,12 @@ CREATE INDEX on_options_key_IDX ON on_options ("key");
3. 默认主题支持直链模式,其它主题陆续支持
4. 程序更新完毕后自动跳转到后台首页更新数据库
5. 主题更新检测
6. 新增数据库备份功能
6. 新增数据库备份功能
20221107
1. api.php down_theme方法里面的REQUEST改成GET
2. 添加链接去掉过滤,避免#符号影响
3. 前端初始化密码不允许&符号
4. 新增备份数据库下载
5. 默认主题改用本地二维码
6. 新增手机版简易后台

BIN
static/images/avatar.jpg

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.9 KiB

1
static/js/qrcode.min.js vendored

File diff suppressed because one or more lines are too long

2
templates/admin/init.php

@ -60,6 +60,6 @@ @@ -60,6 +60,6 @@
<script src = 'static/js/jquery.min.js'></script>
<script src = 'static/layui/layui.js'></script>
<script src="templates/admin/static/embed.js"></script>
<script src="templates/admin/static/embed.js?v=0.9.25"></script>
</body>
</html>

2
templates/admin/login.php

@ -1,5 +1,5 @@ @@ -1,5 +1,5 @@
<!DOCTYPE html>
<html lang="en">
<html lang="zh">
<head>
<meta charset="UTF-8">

8
templates/admin/setting/backup.php

@ -23,6 +23,7 @@ @@ -23,6 +23,7 @@
<!-- 最右侧的操作选项 -->
<script type="text/html" id="tooloption">
<a class="layui-btn layui-btn-xs" lay-event="restore">回滚</a>
<a class="layui-btn layui-btn-xs" lay-event="download">下载</a>
<a class="layui-btn layui-btn-danger layui-btn-xs" lay-event="del">删除</a>
</script>
<!-- 操作选项END -->
@ -109,7 +110,12 @@ @@ -109,7 +110,12 @@
});
});
} else if(layEvent === 'del'){ //删除
}
else if( layEvent === 'download' ) {
var data = obj.data; //获得当前行数据
window.location.href = "?c=api&method=down_db&name=" + data.name;
}
else if(layEvent === 'del'){ //删除
layer.confirm('确定删除吗?', {icon:3,title:'提示'},function(index){
$.get("/index.php?c=api&method=del_backup_db",{name:data.name},function(data,status){

4
templates/admin/setting/subscribe.php

@ -18,6 +18,10 @@ @@ -18,6 +18,10 @@
<li>6. 数据库备份</li>
</ol>
</div>
<div class="setting-msg">
<p>1. 系统检测到您的域名为<strong style="color:#31BDEC;"><code><?php echo $_SERVER['HTTP_HOST']; ?></code></strong>,购买订阅时请填写此域名!</p>
<p>2. 若域名填写错误或更换域名,请前往<a title = "修改OneNav订阅域名" href="https://www.onenav.top/msub.html" target="_blank">https://www.onenav.top/msub.html</a>修改订阅!</p>
</div>
</div>
<!-- 说明提示框END -->
<!-- 订阅表格 -->

4
templates/admin/static/embed.js

@ -306,7 +306,7 @@ layui.use(['element','table','layer','form','upload','iconHhysFa'], function(){ @@ -306,7 +306,7 @@ layui.use(['element','table','layer','form','upload','iconHhysFa'], function(){
return false;
}
//正则验证密码
let p_patt = /^[0-9a-zA-Z!@#$%^&*.()]{6,16}$/;
let p_patt = /^[0-9a-zA-Z!@#%^*.()]{6,16}$/;
if ( !p_patt.test(password) ) {
layer.msg("密码需要6-16字母、数字或特殊字符!", {icon: 5});
return false;
@ -359,7 +359,7 @@ layui.use(['element','table','layer','form','upload','iconHhysFa'], function(){ @@ -359,7 +359,7 @@ layui.use(['element','table','layer','form','upload','iconHhysFa'], function(){
$.post('/index.php?c=login&check=login',{user:user,password:password},function(data,status){
//如果登录成功
if(data.code == 0) {
window.location.href = '/';
window.location.href = '/index.php?c=mobile';
}
else{
layer.msg(data.err_msg, {icon: 5});

4
templates/default/index.php

@ -248,7 +248,7 @@ @@ -248,7 +248,7 @@
</div>
<div class="mdui-divider" style = "margin-top:2em;"></div>
<div class="mdui-divider"></div>
<!--正文内容部分END-->
<!-- footer部分 -->
<!-- 未经作者授权,请勿去掉版权,否则可能影响作者更新代码的积极性或直接放弃维护此项目。 -->
@ -260,11 +260,13 @@ @@ -260,11 +260,13 @@
} ?>
</footer>
<!-- footerend -->
</body>
<script src = 'static/js/jquery.min.js'></script>
<script src="static/layer/layer.js"></script>
<script src = 'static/jQuery-contextMenu/jquery.contextMenu.min.js'></script>
<script src = 'static/js/clipBoard.min.js'></script>
<script src = 'static/js/qrcode.min.js'></script>
<script src = "templates/<?php echo $template; ?>/static/holmes.js"></script>
<script src="templates/<?php echo $template; ?>/static/embed.js?v=<?php echo $version; ?>"></script>
<script>

10
templates/default/static/embed.js

@ -119,11 +119,14 @@ function admin_menu() { @@ -119,11 +119,14 @@ function admin_menu() {
link_id = link_id.replace('id_','');
var domain = get_domain();
var url = domain + '/click/' + link_id;
mdui.dialog({
'title':link_title,
'cssClass':'show_qrcode',
'content':'<img src = "https://qr.png.pub/v1/?text=' + url + '" />'
'content':`<div id="qrcode"></div>`
});
let qrcode = new QRCode(document.getElementById('qrcode'), url);
}},
"copy":{name:"复制链接",icon:"copy",callback:function(){
link_url = $(this).attr('link-url');
@ -177,11 +180,14 @@ $.contextMenu({ @@ -177,11 +180,14 @@ $.contextMenu({
link_id = link_id.replace('id_','');
var domain = get_domain();
var url = domain + '/click/' + link_id;
mdui.dialog({
'title':link_title,
'cssClass':'show_qrcode',
'content':'<img src = "https://qr.png.pub/v1/?text=' + url + '" />'
'content':`<div id="qrcode"></div>`
});
let qrcode = new QRCode(document.getElementById('qrcode'), url);
}},
"copy":{name:"复制链接",icon:"copy",callback:function(){
link_url = $(this).attr('link-url');

1
templates/mobile/assets/index.css

File diff suppressed because one or more lines are too long

6
templates/mobile/assets/index.js

File diff suppressed because one or more lines are too long

BIN
templates/mobile/favicon.ico

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.2 KiB

15
templates/mobile/index.php

@ -0,0 +1,15 @@ @@ -0,0 +1,15 @@
<!DOCTYPE html>
<html lang="zh">
<head>
<meta charset="UTF-8" />
<link rel="icon" href="/favicon.ico" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>OneNav手机版后台</title>
<script type="module" crossorigin src="templates/mobile/assets/index.js?version=<?php echo $version; ?>"></script>
<link rel="stylesheet" href="templates/mobile/assets/index.css?version=<?php echo $version; ?>">
</head>
<body>
<div id="app"></div>
</body>
</html>

2
version.txt

@ -1 +1 @@ @@ -1 +1 @@
v0.9.24-20220801
v0.9.25-20221107
Loading…
Cancel
Save