Finish implementing initial setup process
This commit is contained in:
parent
d47906e10f
commit
7c358d48e0
9 changed files with 340 additions and 41 deletions
|
@ -7,8 +7,9 @@ class Constants {
|
||||||
static const TITLEBAR_COLOR = Color.fromARGB(255, 97, 0, 0);
|
static const TITLEBAR_COLOR = Color.fromARGB(255, 97, 0, 0);
|
||||||
static const DRAWER_COLOR = Color.fromARGB(148, 0, 97, 97);
|
static const DRAWER_COLOR = Color.fromARGB(148, 0, 97, 97);
|
||||||
|
|
||||||
static const VERSION = "1.0.051524.1345";
|
static const VERSION = "1.0.051524.1458";
|
||||||
static const COPYRIGHT = "Copyright 2024 - Tara Piccari. All rights Reserved";
|
static const COPYRIGHT = "Copyright 2024 - Tara Piccari. All rights Reserved";
|
||||||
|
static const CLIENTPSK = "";
|
||||||
|
|
||||||
static const SERVICES_JSON =
|
static const SERVICES_JSON =
|
||||||
"https://raw.githubusercontent.com/AriasCreations/AriasCreations/main/services.json";
|
"https://raw.githubusercontent.com/AriasCreations/AriasCreations/main/services.json";
|
||||||
|
|
166
lib/Packets.dart
Normal file
166
lib/Packets.dart
Normal file
|
@ -0,0 +1,166 @@
|
||||||
|
import 'dart:convert';
|
||||||
|
|
||||||
|
import 'Settings.dart';
|
||||||
|
|
||||||
|
abstract class IPacket {
|
||||||
|
String encode();
|
||||||
|
|
||||||
|
HTTPMethod method();
|
||||||
|
String getType();
|
||||||
|
}
|
||||||
|
|
||||||
|
class S2CSimpleReplyPacket implements IPacket {
|
||||||
|
final bool done;
|
||||||
|
S2CSimpleReplyPacket({required this.done});
|
||||||
|
|
||||||
|
static S2CSimpleReplyPacket decode(String params) {
|
||||||
|
var map = json.decode(params);
|
||||||
|
|
||||||
|
return S2CSimpleReplyPacket(done: map['done'] as bool);
|
||||||
|
}
|
||||||
|
|
||||||
|
@override
|
||||||
|
String encode() {
|
||||||
|
return json.encode({"done": done});
|
||||||
|
}
|
||||||
|
|
||||||
|
@override
|
||||||
|
HTTPMethod method() {
|
||||||
|
return HTTPMethod.Get;
|
||||||
|
}
|
||||||
|
|
||||||
|
@override
|
||||||
|
String getType() {
|
||||||
|
return "S2CSimpleReply";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
class C2SPerformSetupPacket implements IPacket {
|
||||||
|
final String PSK;
|
||||||
|
final String ClientPSK;
|
||||||
|
final String host;
|
||||||
|
final String user;
|
||||||
|
final String pass;
|
||||||
|
final String db;
|
||||||
|
|
||||||
|
C2SPerformSetupPacket(
|
||||||
|
{required this.PSK,
|
||||||
|
required this.ClientPSK,
|
||||||
|
required this.host,
|
||||||
|
required this.user,
|
||||||
|
required this.pass,
|
||||||
|
required this.db});
|
||||||
|
|
||||||
|
@override
|
||||||
|
String encode() {
|
||||||
|
return json.encode({
|
||||||
|
"psk": PSK,
|
||||||
|
"client": ClientPSK,
|
||||||
|
"host": host,
|
||||||
|
"user": user,
|
||||||
|
"pass": pass,
|
||||||
|
"db": db,
|
||||||
|
"type": getType()
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
static C2SPerformSetupPacket decode(String params) {
|
||||||
|
var map = json.decode(params);
|
||||||
|
return C2SPerformSetupPacket(
|
||||||
|
PSK: map['psk'] as String,
|
||||||
|
ClientPSK: map['client'] as String,
|
||||||
|
host: map['host'] as String,
|
||||||
|
user: map['user'] as String,
|
||||||
|
pass: map['pass'] as String,
|
||||||
|
db: map['db'] as String);
|
||||||
|
}
|
||||||
|
|
||||||
|
@override
|
||||||
|
HTTPMethod method() {
|
||||||
|
return HTTPMethod.Post;
|
||||||
|
}
|
||||||
|
|
||||||
|
@override
|
||||||
|
String getType() {
|
||||||
|
return "C2SPerformSetup";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
class S2CPongPacket implements IPacket {
|
||||||
|
final String PSK;
|
||||||
|
final bool authorized;
|
||||||
|
|
||||||
|
S2CPongPacket({required this.PSK, required this.authorized});
|
||||||
|
|
||||||
|
@override
|
||||||
|
String encode() {
|
||||||
|
return json
|
||||||
|
.encode({"psk": PSK, "autorized": authorized, "type": getType()});
|
||||||
|
}
|
||||||
|
|
||||||
|
@override
|
||||||
|
String getType() {
|
||||||
|
return "S2CPong";
|
||||||
|
}
|
||||||
|
|
||||||
|
@override
|
||||||
|
HTTPMethod method() {
|
||||||
|
return HTTPMethod.Get;
|
||||||
|
}
|
||||||
|
|
||||||
|
static S2CPongPacket decode(String params) {
|
||||||
|
var map = json.decode(params);
|
||||||
|
|
||||||
|
return S2CPongPacket(
|
||||||
|
PSK: map['psk'] as String, authorized: map['authorized'] as bool);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
class NullPacket implements IPacket {
|
||||||
|
NullPacket();
|
||||||
|
|
||||||
|
@override
|
||||||
|
String encode() {
|
||||||
|
return json.encode({});
|
||||||
|
}
|
||||||
|
|
||||||
|
static NullPacket decode(String params) {
|
||||||
|
return NullPacket();
|
||||||
|
}
|
||||||
|
|
||||||
|
@override
|
||||||
|
String getType() {
|
||||||
|
return "NullPacket";
|
||||||
|
}
|
||||||
|
|
||||||
|
@override
|
||||||
|
HTTPMethod method() {
|
||||||
|
return HTTPMethod.Get;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
class C2SPingPacket implements IPacket {
|
||||||
|
final String client;
|
||||||
|
C2SPingPacket({required this.client});
|
||||||
|
|
||||||
|
@override
|
||||||
|
HTTPMethod method() {
|
||||||
|
return HTTPMethod.Post;
|
||||||
|
}
|
||||||
|
|
||||||
|
@override
|
||||||
|
String getType() {
|
||||||
|
return "C2SPing";
|
||||||
|
}
|
||||||
|
|
||||||
|
static C2SPingPacket decode(String params) {
|
||||||
|
var map = json.decode(params);
|
||||||
|
|
||||||
|
return C2SPingPacket(client: map['client'] as String);
|
||||||
|
}
|
||||||
|
|
||||||
|
@override
|
||||||
|
String encode() {
|
||||||
|
return json.encode({"client": client});
|
||||||
|
}
|
||||||
|
}
|
|
@ -1,9 +1,14 @@
|
||||||
|
import 'dart:convert';
|
||||||
|
|
||||||
import 'package:dio/dio.dart';
|
import 'package:dio/dio.dart';
|
||||||
import 'package:libac_flutter/nbt/impl/CompoundTag.dart';
|
import 'package:libac_flutter/nbt/impl/CompoundTag.dart';
|
||||||
import 'package:libac_flutter/utils/Hashing.dart';
|
import 'package:libac_flutter/utils/Hashing.dart';
|
||||||
|
import 'package:zontreck/Packets.dart';
|
||||||
|
|
||||||
enum APIEndpoint {
|
enum APIEndpoint {
|
||||||
SetupCheck(script: "SetupCheck.php", path: "/ac/home/supports/"),
|
SetupCheck(script: "SetupCheck.php", path: "/ac/home/supports/"),
|
||||||
|
Ping(script: "Ping.php", path: "/ac/home/supports/"),
|
||||||
|
Setup(script: "Setup.php", path: "/ac/home/supports/"),
|
||||||
Login(script: "Login.php", path: "/ac/home/supports/");
|
Login(script: "Login.php", path: "/ac/home/supports/");
|
||||||
|
|
||||||
final String script;
|
final String script;
|
||||||
|
@ -16,6 +21,8 @@ enum APIEndpoint {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
enum HTTPMethod { Get, Post, Put, Delete }
|
||||||
|
|
||||||
class Settings {
|
class Settings {
|
||||||
static Settings? _inst = null;
|
static Settings? _inst = null;
|
||||||
Settings._() {}
|
Settings._() {}
|
||||||
|
@ -41,6 +48,8 @@ class Settings {
|
||||||
|
|
||||||
String API_SERVER = "";
|
String API_SERVER = "";
|
||||||
bool OpenSimSetupCompleted = false;
|
bool OpenSimSetupCompleted = false;
|
||||||
|
String PSK =
|
||||||
|
""; // This is not saved anywhere it is discarded when the application is unloaded.
|
||||||
|
|
||||||
void setServices(Map<String, dynamic> js) {
|
void setServices(Map<String, dynamic> js) {
|
||||||
var protocol = js['api']['protocol'] as String;
|
var protocol = js['api']['protocol'] as String;
|
||||||
|
@ -60,11 +69,59 @@ class Settings {
|
||||||
return hash;
|
return hash;
|
||||||
}
|
}
|
||||||
|
|
||||||
Future<String> createClientPSK(String hashedPSK) async {
|
Future<String> createDerivedPSK(String hashedPSK, String purpose) async {
|
||||||
String hash = Hashing.sha256Hash("AriasCreations");
|
String hash = await hashPSK("${hashedPSK}:${purpose}");
|
||||||
for (int i = 0; i < 8192; i++) {
|
return await hashPSK("${hash}:${hashedPSK}:${purpose}"); // The derived PSK
|
||||||
hash = Hashing.sha256Hash("${hash}:${hashedPSK}");
|
}
|
||||||
|
|
||||||
|
Future<IPacket> sendPacketToEndpoint(
|
||||||
|
APIEndpoint endpoint, IPacket packet) async {
|
||||||
|
Response<dynamic> reply;
|
||||||
|
|
||||||
|
switch (packet.method()) {
|
||||||
|
case HTTPMethod.Post:
|
||||||
|
{
|
||||||
|
reply = await dio.post(endpoint.getURL(), data: packet.encode());
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case HTTPMethod.Get:
|
||||||
|
{
|
||||||
|
reply = await dio.get(endpoint.getURL());
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case HTTPMethod.Delete:
|
||||||
|
{
|
||||||
|
reply = await dio.delete(endpoint.getURL(), data: packet.encode());
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case HTTPMethod.Put:
|
||||||
|
{
|
||||||
|
reply = await dio.put(endpoint.getURL(), data: packet.encode());
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return processResponsePacket(reply.data as String);
|
||||||
|
}
|
||||||
|
|
||||||
|
Future<IPacket> processResponsePacket(String reply) async {
|
||||||
|
var tmpMap = json.decode(reply);
|
||||||
|
String packetType = tmpMap['type'] as String;
|
||||||
|
switch (packetType) {
|
||||||
|
case "S2CSimpleReply":
|
||||||
|
{
|
||||||
|
S2CSimpleReplyPacket response = S2CSimpleReplyPacket.decode(reply);
|
||||||
|
return response;
|
||||||
|
}
|
||||||
|
case "S2CPong":
|
||||||
|
{
|
||||||
|
S2CPongPacket pong = S2CPongPacket.decode(reply);
|
||||||
|
return pong;
|
||||||
|
}
|
||||||
|
default:
|
||||||
|
{
|
||||||
|
return NullPacket();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
return Hashing.sha256Hash(hash);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,9 +1,8 @@
|
||||||
import 'dart:convert';
|
|
||||||
|
|
||||||
import 'package:flutter/material.dart';
|
import 'package:flutter/material.dart';
|
||||||
import 'package:footer/footer.dart';
|
import 'package:footer/footer.dart';
|
||||||
import 'package:footer/footer_view.dart';
|
import 'package:footer/footer_view.dart';
|
||||||
import 'package:zontreck/Constants.dart';
|
import 'package:zontreck/Constants.dart';
|
||||||
|
import 'package:zontreck/Packets.dart';
|
||||||
import 'package:zontreck/Settings.dart';
|
import 'package:zontreck/Settings.dart';
|
||||||
|
|
||||||
class OpenSimPage extends StatefulWidget {
|
class OpenSimPage extends StatefulWidget {
|
||||||
|
@ -26,15 +25,18 @@ class OpenSimPageState extends State<OpenSimPage> {
|
||||||
|
|
||||||
@override
|
@override
|
||||||
Future<void> didChangeDependencies() async {
|
Future<void> didChangeDependencies() async {
|
||||||
// Send check for setup completion
|
var reply = await settings.sendPacketToEndpoint(
|
||||||
var reply = await settings.dio.get(APIEndpoint.SetupCheck.getURL());
|
APIEndpoint.SetupCheck, NullPacket());
|
||||||
|
var simpleReply = reply as S2CSimpleReplyPacket;
|
||||||
|
if (simpleReply.done) {
|
||||||
|
settings.OpenSimSetupCompleted = true;
|
||||||
|
} else
|
||||||
|
settings.OpenSimSetupCompleted = false;
|
||||||
|
|
||||||
var replyJson = json.decode(reply.data);
|
var pong =
|
||||||
if (replyJson['done'] as bool == true) {
|
await settings.sendPacketToEndpoint(APIEndpoint.Ping, NullPacket());
|
||||||
setState(() {
|
|
||||||
settings.OpenSimSetupCompleted = true;
|
setState(() {});
|
||||||
});
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@override
|
@override
|
||||||
|
@ -61,6 +63,8 @@ class OpenSimPageState extends State<OpenSimPage> {
|
||||||
children: [
|
children: [
|
||||||
ListTile(
|
ListTile(
|
||||||
title: Text("Initial Setup Required"),
|
title: Text("Initial Setup Required"),
|
||||||
|
subtitle: Text(
|
||||||
|
"Please use the same database/user as robust's database\n\nNOTE: Only MySQL/MariaDB is supported by this interface"),
|
||||||
tileColor: Constants.TITLEBAR_COLOR,
|
tileColor: Constants.TITLEBAR_COLOR,
|
||||||
),
|
),
|
||||||
ListTile(
|
ListTile(
|
||||||
|
@ -96,29 +100,48 @@ class OpenSimPageState extends State<OpenSimPage> {
|
||||||
controller: databaseNameController,
|
controller: databaseNameController,
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
|
ListTile(
|
||||||
|
title: Text(
|
||||||
|
"For the PreShared Secret, please enter any text you wish. This is hashed 8192 times for the server key. And an additional 16384 times for the client, and any derived key thereafter"),
|
||||||
|
tileColor: Constants.TITLEBAR_COLOR,
|
||||||
|
),
|
||||||
ListTile(
|
ListTile(
|
||||||
title: Text("PreShared Secret"),
|
title: Text("PreShared Secret"),
|
||||||
subtitle: TextField(
|
subtitle: TextField(
|
||||||
controller: PSKController,
|
controller: PSKController,
|
||||||
decoration: InputDecoration(
|
decoration: InputDecoration(
|
||||||
hintText:
|
hintText:
|
||||||
"Pre-Shared Key. Long text that gets hashed"),
|
"Pre-Shared Key. Some text that gets hashed several thousand times to create a server and client key"),
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
ListTile(
|
|
||||||
title: Text("PSK: ${PSKHash}"),
|
|
||||||
subtitle: Text("Client: ${clientPSK}"),
|
|
||||||
),
|
|
||||||
ElevatedButton(
|
ElevatedButton(
|
||||||
onPressed: () async {
|
onPressed: () async {
|
||||||
var PSK =
|
PSKHash =
|
||||||
await settings.hashPSK(PSKController.text);
|
await settings.hashPSK(PSKController.text);
|
||||||
|
|
||||||
clientPSK = await settings.createClientPSK(PSK);
|
clientPSK = await settings.createDerivedPSK(
|
||||||
|
PSKHash, "client");
|
||||||
|
|
||||||
setState(() {
|
C2SPerformSetupPacket packet =
|
||||||
PSKHash = PSK;
|
C2SPerformSetupPacket(
|
||||||
});
|
PSK: PSKHash,
|
||||||
|
ClientPSK: clientPSK,
|
||||||
|
host: databaseHostController.text,
|
||||||
|
user: databaseUsernameController.text,
|
||||||
|
pass: databasePasswordController.text,
|
||||||
|
db: databaseHostController.text);
|
||||||
|
|
||||||
|
var responsePacket =
|
||||||
|
await settings.sendPacketToEndpoint(
|
||||||
|
APIEndpoint.Setup, packet)
|
||||||
|
as S2CSimpleReplyPacket;
|
||||||
|
|
||||||
|
if (responsePacket.done) {
|
||||||
|
settings.OpenSimSetupCompleted = true;
|
||||||
|
} else
|
||||||
|
settings.OpenSimSetupCompleted = false;
|
||||||
|
|
||||||
|
setState(() {});
|
||||||
},
|
},
|
||||||
child: Text("Submit"))
|
child: Text("Submit"))
|
||||||
],
|
],
|
||||||
|
|
|
@ -26,6 +26,16 @@ function rewrite_DB_conf($host, $user, $pass, $db)
|
||||||
file_put_contents("../database.user.php", $ptl);
|
file_put_contents("../database.user.php", $ptl);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function rewriteSystemInclude($psk, $clientPSK)
|
||||||
|
{
|
||||||
|
$ptl = "<\?php\n"
|
||||||
|
. "define(\"PSK\", \"$psk\");\n"
|
||||||
|
. "define(\"CLIENTPSK\", \"$clientPSK\");\n"
|
||||||
|
. "\?>";
|
||||||
|
|
||||||
|
file_put_contents("../system.user.php", $ptl);
|
||||||
|
}
|
||||||
|
|
||||||
if(file_exists("../database.user.php"))
|
if(file_exists("../database.user.php"))
|
||||||
require("../database.user.php");
|
require("../database.user.php");
|
||||||
else
|
else
|
||||||
|
@ -33,8 +43,6 @@ else
|
||||||
|
|
||||||
if(file_exists("../system.user.php"))
|
if(file_exists("../system.user.php"))
|
||||||
require("../system.user.php");
|
require("../system.user.php");
|
||||||
else
|
|
||||||
require("System.php");
|
|
||||||
|
|
||||||
|
|
||||||
session_start();
|
session_start();
|
||||||
|
|
31
php/Ping.php
Normal file
31
php/Ping.php
Normal file
|
@ -0,0 +1,31 @@
|
||||||
|
<?php
|
||||||
|
if(!defined("COMMON"))
|
||||||
|
require("Common.php");
|
||||||
|
|
||||||
|
$js = getJsonizedInput();
|
||||||
|
|
||||||
|
$psk = "";
|
||||||
|
$allow=false;
|
||||||
|
|
||||||
|
if(!defined("CLIENTPSK")) {
|
||||||
|
$allow=true;
|
||||||
|
} else {
|
||||||
|
|
||||||
|
if($js['client'] == CLIENTPSK) {
|
||||||
|
// Authorized. Send the PSK value to the client
|
||||||
|
$allow=true;
|
||||||
|
$psk = PSK;
|
||||||
|
}else {
|
||||||
|
$allow=false;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
$ret = array(
|
||||||
|
"type" => "S2CPong",
|
||||||
|
"authorized" => $allow,
|
||||||
|
"psk" => $psk
|
||||||
|
);
|
||||||
|
|
||||||
|
die(json_encode($ret));
|
||||||
|
?>
|
|
@ -4,11 +4,28 @@ if(!defined("COMMON"))
|
||||||
|
|
||||||
$js = getJsonizedInput();
|
$js = getJsonizedInput();
|
||||||
|
|
||||||
$host = $js['host'];
|
if(!defined("PSK") || PSK == $js['psk']) {
|
||||||
$user = $js['user'];
|
|
||||||
$pass = $js['pass'];
|
|
||||||
$db = $js['db'];
|
|
||||||
|
|
||||||
rewrite_DB_conf($host, $user, $pass, $db);
|
$host = $js['host'];
|
||||||
|
$user = $js['user'];
|
||||||
|
$pass = $js['pass'];
|
||||||
|
$db = $js['db'];
|
||||||
|
|
||||||
|
$psk = $js['psk'];
|
||||||
|
$clientPsk = $js['client'];
|
||||||
|
|
||||||
|
|
||||||
|
rewrite_DB_conf($host, $user, $pass, $db);
|
||||||
|
rewriteSystemInclude($psk, $clientPsk);
|
||||||
|
|
||||||
|
die(json_encode(array(
|
||||||
|
"done" => true,
|
||||||
|
"type" => "S2CSimpleReply"
|
||||||
|
)));
|
||||||
|
}
|
||||||
|
|
||||||
|
die(json_encode(array(
|
||||||
|
"done" => false,
|
||||||
|
"type" => "S2CSimpleReply"
|
||||||
|
)));
|
||||||
?>
|
?>
|
|
@ -5,13 +5,15 @@ if(!defined("COMMON"))
|
||||||
|
|
||||||
if(DB_NAME == "changeme" && DB_PASS == "changeme") {
|
if(DB_NAME == "changeme" && DB_PASS == "changeme") {
|
||||||
$ret = array (
|
$ret = array (
|
||||||
"done" => false
|
"done" => false,
|
||||||
|
"type" => "S2CSimpleReply"
|
||||||
);
|
);
|
||||||
header("X-Zontreck-Setup-Completed", "FALSE");
|
header("X-Zontreck-Setup-Completed", "FALSE");
|
||||||
die(json_encode($ret));
|
die(json_encode($ret));
|
||||||
}else {
|
}else {
|
||||||
$ret = array (
|
$ret = array (
|
||||||
"done" => true
|
"done" => true,
|
||||||
|
"type" => "S2CSimpleReply"
|
||||||
);
|
);
|
||||||
header("X-Zontreck-Setup-Completed", "TRUE");
|
header("X-Zontreck-Setup-Completed", "TRUE");
|
||||||
die(json_encode($ret));
|
die(json_encode($ret));
|
||||||
|
|
|
@ -1,6 +0,0 @@
|
||||||
<?php
|
|
||||||
|
|
||||||
define("PSK", "No PSK Set");
|
|
||||||
define("ClientPSK", "No Client PSK Set");
|
|
||||||
|
|
||||||
?>
|
|
Loading…
Reference in a new issue