Finish making account registration possible
This commit is contained in:
parent
f37af74687
commit
fb6928cb30
9 changed files with 375 additions and 40 deletions
|
@ -8,7 +8,7 @@ class Constants {
|
|||
static const DRAWER_COLOR = Color.fromARGB(148, 0, 97, 97);
|
||||
static const PORTFOLIO_CARD_COLOR = Color.fromARGB(255, 0, 71, 97);
|
||||
|
||||
static const VERSION = "1.0.051524.1622";
|
||||
static const VERSION = "Version 1.0.051524.2243";
|
||||
static const COPYRIGHT = "Copyright 2024 - Tara Piccari. All rights Reserved";
|
||||
static const CLIENTPSK =
|
||||
"f5c6caf3efe1ec5aa4b7c572f92aa14782b7be34b4c7844fa9c6d47fdf94246";
|
||||
|
@ -16,6 +16,8 @@ class Constants {
|
|||
static const SERVICES_JSON =
|
||||
"https://raw.githubusercontent.com/AriasCreations/AriasCreations/main/services.json";
|
||||
|
||||
static const ALLOW_ANY_LAST_NAME = false;
|
||||
|
||||
static Future<Map<String, dynamic>> pullServicesJson() async {
|
||||
Settings settings = Settings();
|
||||
var reply = await settings.dio.get(SERVICES_JSON);
|
||||
|
|
|
@ -186,3 +186,60 @@ class C2SPingPacket implements IPacket {
|
|||
return json.encode({"client": client});
|
||||
}
|
||||
}
|
||||
|
||||
class C2SRegisterAccountPacket implements IPacket {
|
||||
final String firstName;
|
||||
final String lastName;
|
||||
final String passwordHash;
|
||||
final String email;
|
||||
final int level;
|
||||
final String title;
|
||||
final String clientKey;
|
||||
|
||||
C2SRegisterAccountPacket({
|
||||
required this.firstName,
|
||||
required this.lastName,
|
||||
required this.passwordHash,
|
||||
required this.email,
|
||||
required this.level,
|
||||
required this.title,
|
||||
required this.clientKey,
|
||||
});
|
||||
|
||||
@override
|
||||
HTTPMethod method() {
|
||||
return HTTPMethod.Post;
|
||||
}
|
||||
|
||||
@override
|
||||
String getType() {
|
||||
return "C2SRegisterAccount";
|
||||
}
|
||||
|
||||
@override
|
||||
String encode() {
|
||||
return json.encode({
|
||||
"first": firstName,
|
||||
"last": lastName,
|
||||
"password": passwordHash,
|
||||
"email": email,
|
||||
"type": getType(),
|
||||
"level": level,
|
||||
"title": title,
|
||||
"clientKey": clientKey,
|
||||
});
|
||||
}
|
||||
|
||||
static C2SRegisterAccountPacket decode(String params) {
|
||||
var map = json.decode(params);
|
||||
|
||||
return C2SRegisterAccountPacket(
|
||||
firstName: map['first'] as String,
|
||||
lastName: map['last'] as String,
|
||||
passwordHash: map['password'] as String,
|
||||
email: map['email'] as String,
|
||||
level: map['level'] as int,
|
||||
title: map['title'] as String,
|
||||
clientKey: map['clientKey'] as String);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -9,6 +9,7 @@ enum APIEndpoint {
|
|||
SetupCheck(script: "SetupCheck.php", path: "/ac/home/supports/"),
|
||||
Ping(script: "Ping.php", path: "/ac/home/supports/"),
|
||||
Setup(script: "Setup.php", path: "/ac/home/supports/"),
|
||||
Register(script: "Register.php", path: "/ac/home/supports/"),
|
||||
Login(script: "Login.php", path: "/ac/home/supports/");
|
||||
|
||||
final String script;
|
||||
|
@ -21,6 +22,15 @@ enum APIEndpoint {
|
|||
}
|
||||
}
|
||||
|
||||
enum UserTitles {
|
||||
OPERATOR(title: "Grid Operator"),
|
||||
ADMIN(title: "Grid Admin"),
|
||||
USER(title: "Resident");
|
||||
|
||||
final String title;
|
||||
const UserTitles({required this.title});
|
||||
}
|
||||
|
||||
enum HTTPMethod { Get, Post, Put, Delete }
|
||||
|
||||
class Settings {
|
||||
|
@ -56,6 +66,9 @@ class Settings {
|
|||
String displayName = "";
|
||||
int totalGridUsers = 0;
|
||||
|
||||
bool get hasUsers => totalGridUsers != 0;
|
||||
bool get hasNoUsers => totalGridUsers == 0;
|
||||
|
||||
void setServices(Map<String, dynamic> js) {
|
||||
var protocol = js['api']['protocol'] as String;
|
||||
var port = js['api']['port'] as int;
|
||||
|
|
|
@ -4,6 +4,7 @@ import 'package:footer/footer_view.dart';
|
|||
import 'package:zontreck/Constants.dart';
|
||||
import 'package:zontreck/pages/OpenSim.dart';
|
||||
import 'package:zontreck/pages/Portfolio.dart';
|
||||
import 'package:zontreck/pages/RegisterAccount.dart';
|
||||
|
||||
class MainPage extends StatelessWidget {
|
||||
const MainPage({super.key});
|
||||
|
@ -14,6 +15,7 @@ class MainPage extends StatelessWidget {
|
|||
routes: {
|
||||
"/": (context) => const HomePage(),
|
||||
"/opensim": (context) => const OpenSimPage(),
|
||||
"/opensim/register": (context) => RegisterAccountPage(),
|
||||
"/portfolio": (context) => PortfolioPage(),
|
||||
"/portfolio/coun": (context) => CardsOfUtterNonsense()
|
||||
},
|
||||
|
|
|
@ -84,7 +84,10 @@ class OpenSimPageState extends State<OpenSimPage> {
|
|||
ElevatedButton(
|
||||
onPressed: () {}, child: Text("Login")),
|
||||
ElevatedButton(
|
||||
onPressed: () {},
|
||||
onPressed: () {
|
||||
Navigator.pushNamed(
|
||||
context, "/opensim/register");
|
||||
},
|
||||
child: Text("Register Account"))
|
||||
],
|
||||
))
|
||||
|
|
|
@ -1,4 +1,6 @@
|
|||
import 'package:flutter/material.dart';
|
||||
import 'package:footer/footer.dart';
|
||||
import 'package:footer/footer_view.dart';
|
||||
import 'package:zontreck/Constants.dart';
|
||||
|
||||
class PortfolioPage extends StatelessWidget {
|
||||
|
@ -7,33 +9,45 @@ class PortfolioPage extends StatelessWidget {
|
|||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return Scaffold(
|
||||
appBar: AppBar(
|
||||
title: Text("Zontreck.com - Portfolio of Tara Piccari"),
|
||||
backgroundColor: Constants.TITLEBAR_COLOR,
|
||||
),
|
||||
body: Padding(
|
||||
padding: EdgeInsets.all(8),
|
||||
child: SingleChildScrollView(
|
||||
child: Row(
|
||||
children: [
|
||||
PortfolioEntry(
|
||||
title: ListTile(title: Text("Cards of Utter Nonsense")),
|
||||
body: Text(
|
||||
"A product I created for Second Life, but may port to the mobile phone at some point"),
|
||||
onTap: () {
|
||||
Navigator.pushNamed(context, "/portfolio/coun");
|
||||
},
|
||||
),
|
||||
PortfolioEntry(
|
||||
title: Text("Zontreck.com"),
|
||||
body: Text(
|
||||
("This website, which is written entirely in Flutter, with some supporting API files in PHP")),
|
||||
onTap: () {})
|
||||
],
|
||||
),
|
||||
appBar: AppBar(
|
||||
title: Text("Zontreck.com - Portfolio of Tara Piccari"),
|
||||
backgroundColor: Constants.TITLEBAR_COLOR,
|
||||
),
|
||||
),
|
||||
);
|
||||
body: FooterView(
|
||||
footer: Footer(
|
||||
alignment: Alignment.center,
|
||||
backgroundColor: ThemeData.dark().focusColor,
|
||||
child:
|
||||
const Text("${Constants.COPYRIGHT}\n${Constants.VERSION}")),
|
||||
children: [
|
||||
Padding(
|
||||
padding: EdgeInsets.all(8),
|
||||
child: SingleChildScrollView(
|
||||
child: Row(
|
||||
children: [
|
||||
PortfolioEntry(
|
||||
title: ListTile(title: Text("Cards of Utter Nonsense")),
|
||||
body: Text(
|
||||
"A product I created for Second Life, but may port to the mobile phone at some point"),
|
||||
onTap: () {
|
||||
Navigator.pushNamed(context, "/portfolio/coun");
|
||||
},
|
||||
),
|
||||
PortfolioEntry(
|
||||
title: Text("Zontreck.com"),
|
||||
body: Text(
|
||||
("This website, which is written entirely in Flutter, with some supporting API files in PHP")),
|
||||
onTap: () {}),
|
||||
PortfolioEntry(
|
||||
title: Text("Minecraft Modding"),
|
||||
body: Text(
|
||||
"These mods are all written in Java. The various mods I currently maintain, previously maintained, or have contributed to are: Thresholds, Aria's Essentials, LibZontreck, Let's Do Beachparty, WatchMyDurability"),
|
||||
onTap: () {})
|
||||
],
|
||||
),
|
||||
),
|
||||
),
|
||||
]));
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -1,5 +1,10 @@
|
|||
import 'package:flutter/material.dart';
|
||||
import 'package:footer/footer.dart';
|
||||
import 'package:footer/footer_view.dart';
|
||||
import 'package:libac_flutter/utils/Hashing.dart';
|
||||
import 'package:zontreck/Constants.dart';
|
||||
import 'package:zontreck/Packets.dart';
|
||||
import 'package:zontreck/Settings.dart';
|
||||
|
||||
class RegisterAccountPage extends StatefulWidget {
|
||||
RegisterAccountPage({super.key});
|
||||
|
@ -11,21 +16,193 @@ class RegisterAccountPage extends StatefulWidget {
|
|||
class RegisterAccountState extends State<RegisterAccountPage> {
|
||||
RegisterAccountState();
|
||||
|
||||
Settings settings = Settings();
|
||||
|
||||
TextEditingController firstNameController = TextEditingController();
|
||||
TextEditingController lastNameController = TextEditingController();
|
||||
|
||||
TextEditingController password = TextEditingController();
|
||||
TextEditingController confirm = TextEditingController();
|
||||
|
||||
TextEditingController email = TextEditingController();
|
||||
|
||||
bool get passwordMatches =>
|
||||
password.text == confirm.text &&
|
||||
password.text != "" &&
|
||||
confirm.text != "";
|
||||
|
||||
bool get canSubmit =>
|
||||
firstNameController.text != "" &&
|
||||
lastNameController.text != "" &&
|
||||
passwordMatches &&
|
||||
email.text != "";
|
||||
|
||||
@override
|
||||
void didChangeDependencies() {
|
||||
lastNameController.text = settings.hasNoUsers ? "Piccari" : "";
|
||||
|
||||
setState(() {});
|
||||
}
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return Scaffold(
|
||||
appBar: AppBar(
|
||||
title: Text("OpenSim - Register Account"),
|
||||
backgroundColor: Constants.TITLEBAR_COLOR,
|
||||
),
|
||||
body: Padding(
|
||||
padding: EdgeInsets.all(8),
|
||||
child: SingleChildScrollView(
|
||||
child: Column(
|
||||
children: [],
|
||||
),
|
||||
appBar: AppBar(
|
||||
title: Text("OpenSim - Register Account"),
|
||||
backgroundColor: Constants.TITLEBAR_COLOR,
|
||||
),
|
||||
),
|
||||
);
|
||||
floatingActionButton: canSubmit
|
||||
? ElevatedButton(
|
||||
onPressed: () async {
|
||||
C2SRegisterAccountPacket packet = C2SRegisterAccountPacket(
|
||||
firstName: firstNameController.text,
|
||||
lastName: lastNameController.text,
|
||||
passwordHash: Hashing.md5Hash(password.text),
|
||||
email: email.text,
|
||||
level: settings.hasNoUsers ? 240 : 1,
|
||||
title: settings.hasNoUsers
|
||||
? UserTitles.OPERATOR.title
|
||||
: UserTitles.USER.title,
|
||||
clientKey: Constants.CLIENTPSK,
|
||||
);
|
||||
|
||||
var response = await settings.sendPacketToEndpoint(
|
||||
APIEndpoint.Register, packet) as S2CSimpleReplyPacket;
|
||||
|
||||
if (response.done) {
|
||||
ScaffoldMessenger.of(context).showSnackBar(SnackBar(
|
||||
content: Text(
|
||||
"User Account Created. You must now login to finish setting up the account")));
|
||||
Navigator.pop(context);
|
||||
} else {
|
||||
ScaffoldMessenger.of(context).showSnackBar(SnackBar(
|
||||
content:
|
||||
Text("Fatal error when creating user account")));
|
||||
}
|
||||
},
|
||||
child: Text("Create my Account"))
|
||||
: null,
|
||||
body: FooterView(
|
||||
footer: Footer(
|
||||
alignment: Alignment.center,
|
||||
backgroundColor: ThemeData.dark().focusColor,
|
||||
child:
|
||||
const Text("${Constants.COPYRIGHT}\n${Constants.VERSION}")),
|
||||
children: [
|
||||
Padding(
|
||||
padding: EdgeInsets.all(8),
|
||||
child: SingleChildScrollView(
|
||||
child: Column(
|
||||
children: [
|
||||
settings.hasNoUsers
|
||||
? ListTile(
|
||||
title: Text("There are no users on this grid."),
|
||||
tileColor: Constants.TITLEBAR_COLOR,
|
||||
subtitle: Text(
|
||||
"This account will be granted Level 240, and the User Title : ${UserTitles.OPERATOR.title}"),
|
||||
)
|
||||
: SizedBox(),
|
||||
ListTile(
|
||||
title: Text("First Name"),
|
||||
subtitle: TextField(
|
||||
controller: firstNameController,
|
||||
onChanged: (v) {
|
||||
setState(() {});
|
||||
},
|
||||
),
|
||||
),
|
||||
ListTile(
|
||||
title: Text("Last Name"),
|
||||
subtitle: Constants.ALLOW_ANY_LAST_NAME ||
|
||||
settings.hasNoUsers
|
||||
? TextField(
|
||||
controller: lastNameController,
|
||||
onChanged: (v) {
|
||||
setState(() {});
|
||||
},
|
||||
)
|
||||
: DropdownMenu(
|
||||
onSelected: (V) {
|
||||
setState(() {
|
||||
lastNameController.text = V as String;
|
||||
});
|
||||
},
|
||||
dropdownMenuEntries:
|
||||
LastNames.getCurrentNames(),
|
||||
)),
|
||||
ListTile(
|
||||
title: Text("Password"),
|
||||
subtitle: TextField(
|
||||
controller: password,
|
||||
decoration: InputDecoration(
|
||||
hintText: "*******",
|
||||
),
|
||||
obscureText: true,
|
||||
obscuringCharacter: "*",
|
||||
onChanged: (V) {
|
||||
setState(() {});
|
||||
},
|
||||
),
|
||||
),
|
||||
ListTile(
|
||||
title: Text("Password Confirmation"),
|
||||
subtitle: TextField(
|
||||
controller: confirm,
|
||||
decoration: InputDecoration(
|
||||
hintText: "*******",
|
||||
),
|
||||
obscureText: true,
|
||||
obscuringCharacter: "*",
|
||||
onChanged: (V) {
|
||||
setState(() {});
|
||||
},
|
||||
),
|
||||
),
|
||||
passwordMatches ||
|
||||
password.text == "" && confirm.text == ""
|
||||
? Divider(
|
||||
thickness: 2,
|
||||
)
|
||||
: ListTile(
|
||||
title: Text("Passwords do not match"),
|
||||
tileColor: Constants.TITLEBAR_COLOR,
|
||||
),
|
||||
ListTile(
|
||||
title: Text("Email Address"),
|
||||
subtitle: TextField(
|
||||
onChanged: (V) {
|
||||
setState(() {});
|
||||
},
|
||||
controller: email,
|
||||
decoration: InputDecoration(
|
||||
hintText:
|
||||
"Your email address. It is not used by zontreck.com, but if needed, can be used to reach you"),
|
||||
),
|
||||
)
|
||||
],
|
||||
),
|
||||
),
|
||||
),
|
||||
]));
|
||||
}
|
||||
}
|
||||
|
||||
enum LastNames {
|
||||
Aabye,
|
||||
Aarde,
|
||||
Bailey,
|
||||
Caballero;
|
||||
|
||||
static List<DropdownMenuEntry<Object?>> getCurrentNames() {
|
||||
return [
|
||||
LastNames.Aabye.getEntry(),
|
||||
LastNames.Aarde.getEntry(),
|
||||
LastNames.Bailey.getEntry(),
|
||||
LastNames.Caballero.getEntry()
|
||||
];
|
||||
}
|
||||
|
||||
DropdownMenuEntry<String> getEntry() {
|
||||
return DropdownMenuEntry(value: this.name, label: this.name);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -2,6 +2,9 @@
|
|||
if(defined("COMMON")) return;
|
||||
define("COMMON", 1);
|
||||
|
||||
define("NULLKEY", "00000000-0000-0000-0000-000000000000");
|
||||
|
||||
|
||||
function get_DB() {
|
||||
return mysqli_connect(DB_HOST, DB_USER, DB_PASS, DB_NAME);
|
||||
|
||||
|
@ -45,5 +48,33 @@ if(file_exists("../system.user.php"))
|
|||
require("../system.user.php");
|
||||
|
||||
|
||||
|
||||
function gen_uuid()
|
||||
{
|
||||
return sprintf(
|
||||
'%04x%04x-%04x-%04x-%04x-%04x%04x%04x',
|
||||
// 32 bits for "time_low"
|
||||
mt_rand(0, 0xffff),
|
||||
mt_rand(0, 0xffff),
|
||||
|
||||
// 16 bits for "time_mid"
|
||||
mt_rand(0, 0xffff),
|
||||
|
||||
// 16 bits for "time_hi_and_version",
|
||||
// four most significant bits holds version number 4
|
||||
mt_rand(0, 0x0fff) | 0x4000,
|
||||
|
||||
// 16 bits, 8 bits for "clk_seq_hi_res",
|
||||
// 8 bits for "clk_seq_low",
|
||||
// two most significant bits holds zero and one for variant DCE1.1
|
||||
mt_rand(0, 0x3fff) | 0x8000,
|
||||
|
||||
// 48 bits for "node"
|
||||
mt_rand(0, 0xffff),
|
||||
mt_rand(0, 0xffff),
|
||||
mt_rand(0, 0xffff)
|
||||
);
|
||||
}
|
||||
|
||||
session_start();
|
||||
?>
|
36
php/Register.php
Normal file
36
php/Register.php
Normal file
|
@ -0,0 +1,36 @@
|
|||
<?php
|
||||
|
||||
if(!defined("COMMON"))
|
||||
require("Common.php");
|
||||
|
||||
$js = getJsonizedInput();
|
||||
|
||||
$first = $js['first'];
|
||||
$last = $js['last'];
|
||||
$password = $js['password'];
|
||||
$ID = gen_uuid();
|
||||
|
||||
$level = $js['level'];
|
||||
$title = $js['title'];
|
||||
$email = $js['email'];
|
||||
|
||||
// Make salt
|
||||
$salt = md5(time().":".md5(time().":".gen_uuid()));
|
||||
$pwhash = md5($password.":".$salt);
|
||||
|
||||
$clientKey = $js['clientKey'];
|
||||
if($clientKey == CLIENTPSK) {
|
||||
// Perform registration
|
||||
$DB = get_DB();
|
||||
$DB->query("INSERT INTO `auth` (UUID, passwordHash, passwordSalt, webLoginKey, accountType) VALUES ('$ID', '$pwhash', '$salt', '".NULLKEY."', 'UserAccount');");
|
||||
|
||||
$DB->query("INSERT INTO `UserAccounts` (PrincipalID, ScopeID, FirstName, LastName, Email, ServiceURLs, Created, UserLevel, UserFlags, UserTitle, active) VALUES ('$ID', '".NULLKEY."', '$first', '$last', '$email', '', '".time()."', '$level', '0', '$title', '1');");
|
||||
|
||||
die(json_encode(array("done"=>true, "type"=> "S2CSimpleReply")));
|
||||
|
||||
}else {
|
||||
|
||||
die(json_encode(array("done"=>false, "type"=> "S2CSimpleReply")));
|
||||
}
|
||||
|
||||
?>
|
Loading…
Reference in a new issue