Add URL and authentication persistence.
This commit is contained in:
parent
1df7dab092
commit
a90ace5af9
@ -28,6 +28,8 @@ pub struct App {
|
||||
pub auths:Trie<Authentication>,
|
||||
pub sessions:Trie<Session>,
|
||||
|
||||
pub contests:Vec<u32>,
|
||||
|
||||
pub session_time:Chain<SessionToken>,
|
||||
}
|
||||
impl App {
|
||||
@ -35,6 +37,8 @@ impl App {
|
||||
{
|
||||
if let Ok(mut filesystem) = FileSystem::init() {
|
||||
|
||||
let mut contests = Vec::new();
|
||||
|
||||
// Load salts
|
||||
println!("Loading salts..");
|
||||
let mut salts = Sparse::new();
|
||||
@ -60,6 +64,15 @@ impl App {
|
||||
let user_count = filesystem.user_count()?;
|
||||
for id in 0..user_count {
|
||||
let user = filesystem.user_fetch(id as u32).unwrap();
|
||||
|
||||
// Add user to contests if flag is set.
|
||||
if (user.flags & user::F_CONTEST) != 0 {
|
||||
match contests.binary_search(&user.id) {
|
||||
Ok(_) => { }
|
||||
Err(pos) => { contests.insert(pos, user.id); }
|
||||
}
|
||||
}
|
||||
|
||||
let user_local_id = users.add(user);
|
||||
user_id.set(user_local_id as isize, id);
|
||||
}
|
||||
@ -106,6 +119,8 @@ impl App {
|
||||
auths:Trie::new(),
|
||||
sessions,
|
||||
|
||||
contests,
|
||||
|
||||
session_time,
|
||||
})
|
||||
} else {
|
||||
|
@ -1,6 +1,8 @@
|
||||
pub const F_CONTEST :u32 = 0x0000_0001;
|
||||
|
||||
pub struct User {
|
||||
pub id:u32,
|
||||
pub handle_id:u32,
|
||||
pub flags:u32,
|
||||
pub handle:String,
|
||||
pub secret:Vec<u8>,
|
||||
pub na_key:u32,
|
||||
|
@ -53,21 +53,15 @@ async fn service_http(mut request:hyper::Request<hyper::body::Incoming>, args:Ht
|
||||
.unwrap())
|
||||
}
|
||||
} else {
|
||||
match request.uri().path() {
|
||||
"/" => Ok(Response::builder()
|
||||
.header(CONTENT_TYPE, "text/html")
|
||||
.header(CACHE_CONTROL, "no-cache")
|
||||
.body(Full::new(Bytes::from(args.cache.fetch("/.html").unwrap().data))).unwrap()),
|
||||
|
||||
_ => match args.cache.fetch(request.uri().path()) {
|
||||
match args.cache.fetch(request.uri().path()) {
|
||||
Some(data) => Ok(Response::builder()
|
||||
.header(CONTENT_TYPE, &data.mime)
|
||||
.header(CACHE_CONTROL, "no-cache")
|
||||
.body(Full::new(Bytes::from(data.data))).unwrap()),
|
||||
None => Ok(Response::builder()
|
||||
.status(404)
|
||||
.body(Full::new(Bytes::new())).unwrap())
|
||||
}
|
||||
.header(CONTENT_TYPE, "text/html")
|
||||
.header(CACHE_CONTROL, "no-cache")
|
||||
.body(Full::new(Bytes::from(args.cache.fetch("/.html").unwrap().data))).unwrap()),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -105,12 +105,12 @@ pub async fn thread_system(mut app:App, bus:Bus<protocol::QRPacket>)
|
||||
let user_id = app.filesystem.user_count().unwrap() as u32;
|
||||
|
||||
// Register user pool id and handle
|
||||
let handle_id = app.filesystem.handle_store(&handle, user_id).unwrap();
|
||||
app.filesystem.handle_store(&handle, user_id).ok();
|
||||
app.user_handle.set(handle.as_bytes(), user_id);
|
||||
|
||||
let user_data = User {
|
||||
id:user_id,
|
||||
handle_id,
|
||||
flags:0,
|
||||
handle:display_name,
|
||||
secret,
|
||||
na_key:salt_id,
|
||||
@ -225,6 +225,8 @@ pub async fn thread_system(mut app:App, bus:Bus<protocol::QRPacket>)
|
||||
}
|
||||
|
||||
QRPacketData::QAuthResume(request) => {
|
||||
println!("Request: Auth Resume");
|
||||
|
||||
let mut response = PacketAuthResumeResponse::new();
|
||||
response.status = STATUS_ERROR;
|
||||
|
||||
@ -250,6 +252,8 @@ pub async fn thread_system(mut app:App, bus:Bus<protocol::QRPacket>)
|
||||
}
|
||||
|
||||
QRPacketData::QAuthRevoke => {
|
||||
println!("Request: Auth Revoke");
|
||||
|
||||
if let Some(conn) = app.connections.get_mut(qr.id as usize) {
|
||||
match conn.auth {
|
||||
Some(auth) => {
|
||||
@ -692,6 +696,8 @@ fn generate_game_history(app:&App, session:&Session) -> protocol::PacketGameHist
|
||||
|
||||
let mut response = PacketGameHistoryResponse::new();
|
||||
|
||||
response.token = session.token;
|
||||
|
||||
// Get Dawn handle
|
||||
if let Some(id) = session.p_dawn.user {
|
||||
if let Some(user) = app.get_user_by_id(id) {
|
||||
|
@ -64,7 +64,7 @@ pub async fn handle_ws(ws:WebSocketStream<TokioIo<Upgraded>>, args:HttpServiceAr
|
||||
QRPacket::new(conn_id, QRPacketData::QRegister(packet))
|
||||
).ok();
|
||||
}
|
||||
Err(_) => { }
|
||||
Err(_) => { println!("error: packet decode failed."); }
|
||||
}
|
||||
|
||||
CODE_AUTH => match PacketAuth::decode(&data, &mut index) {
|
||||
@ -74,7 +74,7 @@ pub async fn handle_ws(ws:WebSocketStream<TokioIo<Upgraded>>, args:HttpServiceAr
|
||||
QRPacket::new(conn_id, QRPacketData::QAuth(packet))
|
||||
).ok();
|
||||
}
|
||||
Err(_) => { }
|
||||
Err(_) => { println!("error: packet decode failed."); }
|
||||
}
|
||||
|
||||
CODE_AUTH_RESUME => match PacketAuthResume::decode(&data, &mut index) {
|
||||
@ -84,7 +84,7 @@ pub async fn handle_ws(ws:WebSocketStream<TokioIo<Upgraded>>, args:HttpServiceAr
|
||||
QRPacket::new(conn_id, QRPacketData::QAuthResume(packet))
|
||||
).ok();
|
||||
}
|
||||
Err(_) => { }
|
||||
Err(_) => { println!("error: packet decode failed."); }
|
||||
}
|
||||
|
||||
CODE_AUTH_REVOKE => {
|
||||
|
@ -41,6 +41,7 @@ impl Packet for PacketGameHistory {
|
||||
#[derive(Clone)]
|
||||
pub struct PacketGameHistoryResponse {
|
||||
pub status:u16,
|
||||
pub token:SessionToken,
|
||||
pub dawn_handle:String,
|
||||
pub dusk_handle:String,
|
||||
pub history:Vec<Play>,
|
||||
@ -50,6 +51,7 @@ impl PacketGameHistoryResponse {
|
||||
{
|
||||
Self {
|
||||
status:0,
|
||||
token:SessionToken::default(),
|
||||
dawn_handle:String::new(),
|
||||
dusk_handle:String::new(),
|
||||
history:Vec::new(),
|
||||
@ -72,6 +74,7 @@ impl Packet for PacketGameHistoryResponse {
|
||||
|
||||
[
|
||||
pack_u16(self.status),
|
||||
self.token.to_vec(),
|
||||
pack_u16(self.dawn_handle.len() as u16),
|
||||
self.dawn_handle.as_bytes().to_vec(),
|
||||
pack_u16(self.dusk_handle.len() as u16),
|
||||
|
@ -308,7 +308,7 @@ impl FileSystem {
|
||||
let handle = user.handle.as_bytes().to_vec();
|
||||
|
||||
// Write user information
|
||||
file.write(&pack_u32(user.handle_id)).map_err(|_| ())?;
|
||||
file.write(&pack_u32(user.flags)).map_err(|_| ())?;
|
||||
file.write(&pack_u32(user.na_key)).map_err(|_| ())?;
|
||||
file.write(&pack_u16(user.secret.len() as u16)).map_err(|_| ())?;
|
||||
file.write(&user.secret).map_err(|_| ())?;
|
||||
@ -340,7 +340,7 @@ impl FileSystem {
|
||||
let mut buffer_u32 = [0u8; 4];
|
||||
|
||||
file.read_exact(&mut buffer_u32).map_err(|_| ())?;
|
||||
let handle_id = unpack_u32(&buffer_u32, &mut 0);
|
||||
let flags = unpack_u32(&buffer_u32, &mut 0);
|
||||
|
||||
file.read_exact(&mut buffer_u32).map_err(|_| ())?;
|
||||
let na_key = unpack_u32(&buffer_u32, &mut 0);
|
||||
@ -361,7 +361,7 @@ impl FileSystem {
|
||||
|
||||
Ok(User {
|
||||
id,
|
||||
handle_id,
|
||||
flags,
|
||||
handle,
|
||||
secret,
|
||||
na_key,
|
||||
|
@ -7,8 +7,8 @@
|
||||
<meta name="application-name" content="Omen">
|
||||
<meta name="description" content="Strategy board game played on a hexagon grid.">
|
||||
<link rel="icon" href="/favicon.png">
|
||||
<link rel="stylesheet" href=".css">
|
||||
<script src=".js"></script>
|
||||
<link rel="stylesheet" href="/.css">
|
||||
<script src="/.js"></script>
|
||||
</head>
|
||||
<body>
|
||||
<noscript>This application requires JavaScript to function.</noscript>
|
||||
|
@ -7,15 +7,15 @@ GAME_ASSET.load_image = (image) => {
|
||||
};
|
||||
|
||||
GAME_ASSET.Image = {
|
||||
Promote: GAME_ASSET.load_image("asset/promote.svg"),
|
||||
Promote: GAME_ASSET.load_image("/asset/promote.svg"),
|
||||
Piece: [
|
||||
[ GAME_ASSET.load_image("asset/militia_dawn.svg"), GAME_ASSET.load_image("asset/militia_dusk.svg") ],
|
||||
[ GAME_ASSET.load_image("asset/lance_dawn.svg"), GAME_ASSET.load_image("asset/lance_dusk.svg") ],
|
||||
[ GAME_ASSET.load_image("asset/knight_dawn.svg"), GAME_ASSET.load_image("asset/knight_dusk.svg") ],
|
||||
[ GAME_ASSET.load_image("asset/tower_dawn.svg"), GAME_ASSET.load_image("asset/tower_dusk.svg") ],
|
||||
[ GAME_ASSET.load_image("asset/castle_dawn.svg"), GAME_ASSET.load_image("asset/castle_dusk.svg") ],
|
||||
[ GAME_ASSET.load_image("asset/dragon_dawn.svg"), GAME_ASSET.load_image("asset/dragon_dusk.svg") ],
|
||||
[ GAME_ASSET.load_image("asset/behemoth_dawn.svg"), GAME_ASSET.load_image("asset/behemoth_dusk.svg") ],
|
||||
[ GAME_ASSET.load_image("asset/omen_dawn.svg"), GAME_ASSET.load_image("asset/omen_dusk.svg") ],
|
||||
[ GAME_ASSET.load_image("/asset/militia_dawn.svg"), GAME_ASSET.load_image("/asset/militia_dusk.svg") ],
|
||||
[ GAME_ASSET.load_image("/asset/lance_dawn.svg"), GAME_ASSET.load_image("/asset/lance_dusk.svg") ],
|
||||
[ GAME_ASSET.load_image("/asset/knight_dawn.svg"), GAME_ASSET.load_image("/asset/knight_dusk.svg") ],
|
||||
[ GAME_ASSET.load_image("/asset/tower_dawn.svg"), GAME_ASSET.load_image("/asset/tower_dusk.svg") ],
|
||||
[ GAME_ASSET.load_image("/asset/castle_dawn.svg"), GAME_ASSET.load_image("/asset/castle_dusk.svg") ],
|
||||
[ GAME_ASSET.load_image("/asset/dragon_dawn.svg"), GAME_ASSET.load_image("/asset/dragon_dusk.svg") ],
|
||||
[ GAME_ASSET.load_image("/asset/behemoth_dawn.svg"), GAME_ASSET.load_image("/asset/behemoth_dusk.svg") ],
|
||||
[ GAME_ASSET.load_image("/asset/omen_dawn.svg"), GAME_ASSET.load_image("/asset/omen_dusk.svg") ],
|
||||
],
|
||||
};
|
||||
|
145
www/js/scene.js
145
www/js/scene.js
@ -1,8 +1,7 @@
|
||||
const SCENES = {
|
||||
Init:{
|
||||
load() {
|
||||
LOAD_STACK(SCENES.Offline);
|
||||
CONTEXT.Scene = SCENES.Browse;
|
||||
LOAD(SCENES.Offline);
|
||||
RECONNECT();
|
||||
return true;
|
||||
},
|
||||
@ -11,20 +10,20 @@ const SCENES = {
|
||||
Offline:{
|
||||
load() {
|
||||
UI.nav([
|
||||
UI.button("Reconnect", () => { RECONNECT(); })
|
||||
UI.button("Reconnect", () => { RECONNECT(); }),
|
||||
], []);
|
||||
return true;
|
||||
},
|
||||
reconnect() {
|
||||
LOAD(CONTEXT.Scene);
|
||||
LOAD_URL();
|
||||
}
|
||||
},
|
||||
|
||||
Register:{
|
||||
load() {
|
||||
if(CONTEXT.Auth !== null) return false;
|
||||
if(sessionStorage.getItem("auth") !== null) return false;
|
||||
UI.mainmenu("register");
|
||||
UI.mainnav([], []);
|
||||
UI.mainnav([], [], { auth:true });
|
||||
|
||||
let container = document.createElement("section");
|
||||
let form = document.createElement("div");
|
||||
@ -81,8 +80,14 @@ const SCENES = {
|
||||
let submit = document.getElementById("submit");
|
||||
switch(data.status) {
|
||||
case Status.Ok: {
|
||||
CONTEXT.Auth = data;
|
||||
LOAD(SCENES.Browse);
|
||||
let b64_token = PACK.base64(data.token);
|
||||
let b64_secret = PACK.base64(data.secret);
|
||||
console.log(b64_token);
|
||||
console.log(b64_secret);
|
||||
|
||||
sessionStorage.setItem("auth", b64_token);
|
||||
sessionStorage.setItem("auth_secret", b64_secret);
|
||||
LOAD_URL();
|
||||
} break;
|
||||
default: {
|
||||
submit.removeAttribute("disabled");
|
||||
@ -105,15 +110,15 @@ const SCENES = {
|
||||
}
|
||||
},
|
||||
disconnect() {
|
||||
LOAD_STACK(SCENES.Offline);
|
||||
LOAD(SCENES.Offline);
|
||||
},
|
||||
},
|
||||
|
||||
Authenticate:{
|
||||
load() {
|
||||
if(CONTEXT.Auth !== null) return false;
|
||||
if(sessionStorage.getItem("auth") !== null) return false;
|
||||
UI.mainmenu("authenticate");
|
||||
UI.mainnav([], []);
|
||||
UI.mainnav([], [], { auth:true });
|
||||
|
||||
let container = document.createElement("section");
|
||||
let form = document.createElement("div");
|
||||
@ -163,8 +168,9 @@ const SCENES = {
|
||||
let submit = document.getElementById("submit");
|
||||
switch(data.status) {
|
||||
case Status.Ok: {
|
||||
CONTEXT.Auth = data;
|
||||
LOAD(SCENES.Browse);
|
||||
sessionStorage.setItem("auth", PACK.base64(data.token));
|
||||
sessionStorage.setItem("auth_secret", PACK.base64(data.secret));
|
||||
LOAD_URL();
|
||||
} break;
|
||||
case Status.Error: {
|
||||
submit.removeAttribute("disabled");
|
||||
@ -177,7 +183,7 @@ const SCENES = {
|
||||
}
|
||||
},
|
||||
disconnect() {
|
||||
LOAD_STACK(SCENES.Offline);
|
||||
LOAD(SCENES.Offline);
|
||||
},
|
||||
},
|
||||
|
||||
@ -189,14 +195,15 @@ const SCENES = {
|
||||
};
|
||||
|
||||
UI.mainmenu("browse");
|
||||
UI.mainnav_std(
|
||||
UI.mainnav(
|
||||
[ ],
|
||||
[
|
||||
UI.div([UI.text("0 - 0 of 0")]),
|
||||
UI.button("◀", null),
|
||||
UI.button("▶", null),
|
||||
UI.button("Refresh", null),
|
||||
]
|
||||
],
|
||||
{ auth:true, session:true }
|
||||
);
|
||||
|
||||
let table = document.createElement("table");
|
||||
@ -205,6 +212,8 @@ const SCENES = {
|
||||
MAIN.appendChild(table);
|
||||
|
||||
SCENE.refresh();
|
||||
|
||||
history.pushState(null, "Omen", "/");
|
||||
return true;
|
||||
},
|
||||
refresh() {
|
||||
@ -229,13 +238,13 @@ const SCENES = {
|
||||
}
|
||||
},
|
||||
disconnect() {
|
||||
LOAD_STACK(SCENES.Offline);
|
||||
LOAD(SCENES.Offline);
|
||||
},
|
||||
},
|
||||
|
||||
Continue:{
|
||||
load() {
|
||||
if(CONTEXT.Auth === null) return false;
|
||||
if(sessionStorage.getItem("auth") === null) return false;
|
||||
|
||||
CONTEXT.Data = {
|
||||
page:0,
|
||||
@ -243,14 +252,15 @@ const SCENES = {
|
||||
};
|
||||
|
||||
UI.mainmenu("continue");
|
||||
UI.mainnav_std(
|
||||
UI.mainnav(
|
||||
[ ],
|
||||
[
|
||||
UI.div([UI.text("0 - 0 of 0")]),
|
||||
UI.button("◀", null),
|
||||
UI.button("▶", null),
|
||||
UI.button("Refresh", null),
|
||||
]
|
||||
],
|
||||
{ auth:true, session:true }
|
||||
);
|
||||
|
||||
let table = document.createElement("table");
|
||||
@ -259,6 +269,8 @@ const SCENES = {
|
||||
MAIN.appendChild(table);
|
||||
|
||||
SCENE.refresh();
|
||||
|
||||
history.pushState(null, "Omen - Continue", "/continue/");
|
||||
return true;
|
||||
},
|
||||
refresh() {
|
||||
@ -283,13 +295,13 @@ const SCENES = {
|
||||
}
|
||||
},
|
||||
disconnect() {
|
||||
LOAD_STACK(SCENES.Offline);
|
||||
LOAD(SCENES.Offline);
|
||||
},
|
||||
},
|
||||
|
||||
Join:{
|
||||
load() {
|
||||
if(CONTEXT.Auth === null) return false;
|
||||
if(sessionStorage.getItem("auth") === null) return false;
|
||||
|
||||
CONTEXT.Data = {
|
||||
page:0,
|
||||
@ -297,14 +309,15 @@ const SCENES = {
|
||||
};
|
||||
|
||||
UI.mainmenu("join");
|
||||
UI.mainnav_std(
|
||||
UI.mainnav(
|
||||
[ ],
|
||||
[
|
||||
UI.div([UI.text("0 - 0 of 0")]),
|
||||
UI.button("◀", null),
|
||||
UI.button("▶", null),
|
||||
UI.button("Refresh", null),
|
||||
]
|
||||
],
|
||||
{ auth:true, session:true }
|
||||
);
|
||||
|
||||
let table = document.createElement("table");
|
||||
@ -313,6 +326,8 @@ const SCENES = {
|
||||
MAIN.appendChild(table);
|
||||
|
||||
SCENE.refresh();
|
||||
|
||||
history.pushState(null, "Omen - Join", "/join/");
|
||||
return true;
|
||||
},
|
||||
refresh() {
|
||||
@ -337,7 +352,7 @@ const SCENES = {
|
||||
}
|
||||
},
|
||||
disconnect() {
|
||||
LOAD_STACK(SCENES.Offline);
|
||||
LOAD(SCENES.Offline);
|
||||
},
|
||||
},
|
||||
|
||||
@ -349,14 +364,15 @@ const SCENES = {
|
||||
};
|
||||
|
||||
UI.mainmenu("live");
|
||||
UI.mainnav_std(
|
||||
UI.mainnav(
|
||||
[ ],
|
||||
[
|
||||
UI.div([UI.text("0 - 0 of 0")]),
|
||||
UI.button("◀", null),
|
||||
UI.button("▶", null),
|
||||
UI.button("Refresh", null),
|
||||
]
|
||||
],
|
||||
{ auth:true, session:true }
|
||||
);
|
||||
|
||||
let table = document.createElement("table");
|
||||
@ -365,6 +381,8 @@ const SCENES = {
|
||||
MAIN.appendChild(table);
|
||||
|
||||
SCENE.refresh();
|
||||
|
||||
history.pushState(null, "Omen - Live", "/live/");
|
||||
return true;
|
||||
},
|
||||
refresh() {
|
||||
@ -389,7 +407,7 @@ const SCENES = {
|
||||
}
|
||||
},
|
||||
disconnect() {
|
||||
LOAD_STACK(SCENES.Offline);
|
||||
LOAD(SCENES.Offline);
|
||||
},
|
||||
},
|
||||
|
||||
@ -401,14 +419,15 @@ const SCENES = {
|
||||
};
|
||||
|
||||
UI.mainmenu("history");
|
||||
UI.mainnav_std(
|
||||
UI.mainnav(
|
||||
[ ],
|
||||
[
|
||||
UI.div([UI.text("0 - 0 of 0")]),
|
||||
UI.button("◀", null),
|
||||
UI.button("▶", null),
|
||||
UI.button("Refresh", null),
|
||||
]
|
||||
],
|
||||
{ auth:true }
|
||||
);
|
||||
|
||||
let table = document.createElement("table");
|
||||
@ -417,6 +436,8 @@ const SCENES = {
|
||||
MAIN.appendChild(table);
|
||||
|
||||
SCENE.refresh();
|
||||
|
||||
history.pushState(null, "Omen - History", "/history/");
|
||||
return true;
|
||||
},
|
||||
refresh() {
|
||||
@ -440,7 +461,7 @@ const SCENES = {
|
||||
}
|
||||
},
|
||||
disconnect() {
|
||||
LOAD_STACK(SCENES.Offline);
|
||||
LOAD(SCENES.Offline);
|
||||
},
|
||||
},
|
||||
|
||||
@ -458,6 +479,8 @@ const SCENES = {
|
||||
MAIN.appendChild(body);
|
||||
|
||||
this.refresh("game.html");
|
||||
|
||||
history.pushState(null, "Omen - Guide", "/guide/");
|
||||
return true;
|
||||
},
|
||||
refresh(page) {
|
||||
@ -483,6 +506,8 @@ const SCENES = {
|
||||
MAIN.appendChild(body);
|
||||
|
||||
this.refresh("main.html");
|
||||
|
||||
history.pushState(null, "Omen - About", "/about/");
|
||||
return true;
|
||||
},
|
||||
refresh(page) {
|
||||
@ -521,6 +546,7 @@ const SCENES = {
|
||||
|
||||
INTERFACE.init(data, INTERFACE.Mode.Online);
|
||||
|
||||
history.pushState(null, "Omen - Game", "/game/" + PACK.base64(data.token).slice(0, -1));
|
||||
return true;
|
||||
},
|
||||
unload() {
|
||||
@ -541,7 +567,7 @@ const SCENES = {
|
||||
}
|
||||
},
|
||||
disconnect() {
|
||||
LOAD_STACK(SCENES.Offline);
|
||||
LOAD(SCENES.Offline);
|
||||
},
|
||||
},
|
||||
|
||||
@ -563,6 +589,7 @@ const SCENES = {
|
||||
|
||||
INTERFACE.init(data, INTERFACE.Mode.Local);
|
||||
|
||||
history.pushState(null, "Omen - Practice", "/practice/");
|
||||
return true;
|
||||
},
|
||||
unload() {
|
||||
@ -573,7 +600,7 @@ const SCENES = {
|
||||
GameHistory:{
|
||||
load(data) {
|
||||
let buttons_bottom = [ ];
|
||||
buttons_bottom.push(UI.button("Back", () => { LOAD(SCENES.Browse) }));
|
||||
buttons_bottom.push(UI.button("Back", () => { LOAD(SCENES.History) }));
|
||||
|
||||
UI.nav([
|
||||
UI.button("Rotate", () => { INTERFACE.rotate(); }),
|
||||
@ -607,6 +634,7 @@ const SCENES = {
|
||||
|
||||
INTERFACE.init(data, INTERFACE.Mode.Replay);
|
||||
|
||||
history.pushState(null, "Omen - History", "/history/" + PACK.base64(data.token).slice(0, -1));
|
||||
return true;
|
||||
},
|
||||
unload() {
|
||||
@ -619,8 +647,6 @@ function LOAD(scene, data=null) {
|
||||
UNLOAD();
|
||||
UI.rebuild();
|
||||
SCENE = scene;
|
||||
CONTEXT.Scene = SCENE;
|
||||
CONTEXT.Data = null;
|
||||
if(!SCENE.load(data)) { LOAD(SCENES.Browse); }
|
||||
}
|
||||
|
||||
@ -628,10 +654,47 @@ function UNLOAD() {
|
||||
if(SCENE !== null && SCENE.unload !== undefined) { SCENE.unload(); }
|
||||
}
|
||||
|
||||
function LOAD_STACK(scene, data=null) {
|
||||
UNLOAD();
|
||||
UI.rebuild();
|
||||
SCENE = scene;
|
||||
CONTEXT.Data = null;
|
||||
if(!SCENE.load(data)) { LOAD(SCENES.Browse); }
|
||||
function LOAD_URL() {
|
||||
let parts = window.location.pathname.split("/");
|
||||
|
||||
if(parts.length > 1) {
|
||||
switch(parts[1]) {
|
||||
case "continue": LOAD(SCENES.Continue); break;
|
||||
case "live": LOAD(SCENES.Live); break;
|
||||
case "practice": LOAD(SCENES.GamePractice); break;
|
||||
case "guide": LOAD(SCENES.Guide); break;
|
||||
case "practice": LOAD(SCENES.About); break;
|
||||
|
||||
case "history": {
|
||||
LOAD(SCENES.History);
|
||||
if(parts[2]) {
|
||||
let token = UNPACK.base64(parts[2] + "=");
|
||||
MESSAGE_COMPOSE([
|
||||
PACK.u16(OpCode.GameHistory),
|
||||
token,
|
||||
]);
|
||||
}
|
||||
} break;
|
||||
|
||||
case "join": {
|
||||
LOAD(SCENES.Join);
|
||||
if(parts[2]) {
|
||||
let token = UNPACK.base64(parts[2] + "=");
|
||||
MESSAGE_SESSION_JOIN(token, true);
|
||||
}
|
||||
} break;
|
||||
|
||||
case "game": {
|
||||
LOAD(SCENES.Browse);
|
||||
if(parts[2]) {
|
||||
let token = UNPACK.base64(parts[2] + "=");
|
||||
MESSAGE_SESSION_JOIN(token, false);
|
||||
}
|
||||
} break;
|
||||
|
||||
default: LOAD(SCENES.Browse);
|
||||
}
|
||||
} else {
|
||||
LOAD(SCENES.Browse);
|
||||
}
|
||||
}
|
||||
|
@ -29,10 +29,16 @@ function RECONNECT() {
|
||||
}
|
||||
|
||||
function RESUME() {
|
||||
if(CONTEXT.Auth !== null) {
|
||||
//sessionStorage.clear();
|
||||
let b64_auth = sessionStorage.getItem("auth");
|
||||
if(b64_auth !== null) {
|
||||
let auth = UNPACK.base64(b64_auth);
|
||||
let secret = UNPACK.base64(sessionStorage.getItem("auth_secret"));
|
||||
|
||||
MESSAGE_COMPOSE([
|
||||
CONTEXT.Auth.token,
|
||||
CONTEXT.Auth.secret,
|
||||
PACK.u16(OpCode.Resume),
|
||||
auth,
|
||||
secret,
|
||||
]);
|
||||
} else {
|
||||
if(SCENE.reconnect !== undefined) { SCENE.reconnect(); }
|
||||
@ -40,7 +46,6 @@ function RESUME() {
|
||||
}
|
||||
|
||||
function MESSAGE(event) {
|
||||
if(SCENE.message !== undefined) {
|
||||
let bytes = new Uint8Array(event.data);
|
||||
let code = 0;
|
||||
let index = 2;
|
||||
@ -81,16 +86,16 @@ function MESSAGE(event) {
|
||||
if(bytes.length - index == 26) {
|
||||
data = {
|
||||
status:(bytes[2] << 8) + bytes[3],
|
||||
token:new Uint8Array(),
|
||||
secret:new Uint8Array(),
|
||||
token:new Uint8Array(8),
|
||||
secret:new Uint8Array(16),
|
||||
};
|
||||
index += 2;
|
||||
|
||||
for(let i = 0; i < 8; ++i) {
|
||||
data.token += bytes[index++];
|
||||
data.token[i] = bytes[index++];
|
||||
}
|
||||
for(let i = 0; i < 16; ++i) {
|
||||
data.secret += bytes[index++];
|
||||
data.secret[i] = bytes[index++];
|
||||
}
|
||||
} else {
|
||||
console.error("Authenticate packet bad length:" + bytes.length);
|
||||
@ -104,10 +109,10 @@ function MESSAGE(event) {
|
||||
result = UNPACK.u16(bytes, index);
|
||||
index = result.index;
|
||||
if(result.data != Status.Ok) {
|
||||
CONTEXT.Auth = null;
|
||||
sessionStorage.clear();
|
||||
}
|
||||
|
||||
LOAD(CONTEXT.Scene);
|
||||
LOAD_URL();
|
||||
} break;
|
||||
|
||||
case OpCode.Deauthenticate: {
|
||||
@ -324,6 +329,7 @@ function MESSAGE(event) {
|
||||
|
||||
data = {
|
||||
status:0,
|
||||
token:new Uint8Array(8),
|
||||
dawn:"",
|
||||
dusk:"",
|
||||
history:[ ],
|
||||
@ -334,6 +340,9 @@ function MESSAGE(event) {
|
||||
index = result.index;
|
||||
data.status = result.data;
|
||||
|
||||
// Token
|
||||
for(let i = 0; i < 8; ++i) { data.token[i] = bytes[index++]; }
|
||||
|
||||
// Handles
|
||||
result = UNPACK.string(bytes, index);
|
||||
index = result.index;
|
||||
@ -364,10 +373,8 @@ function MESSAGE(event) {
|
||||
console.log("RECV Undefined " + code);
|
||||
return;
|
||||
}
|
||||
|
||||
if(SCENE.message !== undefined) { SCENE.message(code, data) };
|
||||
}
|
||||
}
|
||||
|
||||
function MESSAGE_COMPOSE(data) {
|
||||
if(SOCKET !== null) {
|
||||
|
37
www/js/ui.js
37
www/js/ui.js
@ -90,32 +90,21 @@ const UI = {
|
||||
return table;
|
||||
},
|
||||
|
||||
mainnav(left_children, right_children) {
|
||||
let header = document.createElement("nav");
|
||||
|
||||
let left = document.createElement("section");
|
||||
for(child of left_children) { left.appendChild(child); }
|
||||
|
||||
let right = document.createElement("section");
|
||||
for(child of right_children) { right.appendChild(child); }
|
||||
|
||||
header.appendChild(left);
|
||||
header.appendChild(right);
|
||||
|
||||
MAIN.appendChild(header);
|
||||
},
|
||||
|
||||
mainnav_std(left_children, right_children) {
|
||||
mainnav(left_children, right_children, features={}) {
|
||||
let header = document.createElement("nav");
|
||||
let left = document.createElement("section");
|
||||
|
||||
if(CONTEXT.Auth === null) {
|
||||
left.appendChild(UI.button("Register", () => { LOAD_STACK(SCENES.Register); }));
|
||||
left.appendChild(UI.button("Log In", () => { LOAD_STACK(SCENES.Authenticate); }));
|
||||
if(sessionStorage.getItem("auth") === null) {
|
||||
if(features.auth === true) {
|
||||
left.appendChild(UI.button("Register", () => { LOAD(SCENES.Register); }));
|
||||
left.appendChild(UI.button("Log In", () => { LOAD(SCENES.Authenticate); }));
|
||||
}
|
||||
} else {
|
||||
if(features.session === true) {
|
||||
left.appendChild(UI.button("Contest", () => { MESSAGE_SESSION_START(); }));
|
||||
left.appendChild(UI.button("Challenge", () => { }));
|
||||
}
|
||||
}
|
||||
|
||||
for(child of left_children) { left.appendChild(child); }
|
||||
|
||||
@ -144,7 +133,7 @@ const UI = {
|
||||
let bottom = [ ];
|
||||
|
||||
top.push(UI.button("Browse", () => { LOAD(SCENES.Browse); }, page == "browse"));
|
||||
if(CONTEXT.Auth !== null) {
|
||||
if(sessionStorage.getItem("auth") !== null) {
|
||||
top.push(UI.button("Continue", () => { LOAD(SCENES.Continue); }, page == "continue"));
|
||||
top.push(UI.button("Join", () => { LOAD(SCENES.Join); }, page == "join"));
|
||||
}
|
||||
@ -154,13 +143,13 @@ const UI = {
|
||||
top.push(UI.button("Guide", () => { LOAD(SCENES.Guide); }, page == "guide"));
|
||||
top.push(UI.button("About", () => { LOAD(SCENES.About); }, page == "about"));
|
||||
|
||||
if(CONTEXT.Auth !== null) {
|
||||
if(sessionStorage.getItem("auth") !== null) {
|
||||
bottom.push(UI.button("Logout", () => {
|
||||
MESSAGE_COMPOSE([
|
||||
PACK.u16(OpCode.Deauthenticate),
|
||||
]);
|
||||
CONTEXT.Auth = null;
|
||||
LOAD(SCENE);
|
||||
sessionStorage.clear();
|
||||
LOAD_URL();
|
||||
}));
|
||||
}
|
||||
|
||||
@ -186,7 +175,7 @@ const UI = {
|
||||
if(records[r].player) {
|
||||
buttons.push(UI.button("Resume", join_callback));
|
||||
} else {
|
||||
if(CONTEXT.Auth !== null && (records[r].dawn == "" || records[r].dusk == "")) {
|
||||
if(sessionStorage.getItem("auth") !== null && (records[r].dawn == "" || records[r].dusk == "")) {
|
||||
buttons.push(UI.button("Join", join_callback));
|
||||
}
|
||||
buttons.push(UI.button("Spectate", spectate_callback));
|
||||
|
@ -13,6 +13,13 @@ const PACK = {
|
||||
value & 0xFF
|
||||
]);
|
||||
},
|
||||
base64(bytes) {
|
||||
let str = "";
|
||||
for(let i = 0; i < bytes.length; ++i) {
|
||||
str += String.fromCharCode(bytes[i]);
|
||||
}
|
||||
return window.btoa(str);
|
||||
},
|
||||
};
|
||||
|
||||
const UNPACK = {
|
||||
@ -107,7 +114,15 @@ const UNPACK = {
|
||||
if(take != "") { str += " " + take; }
|
||||
}
|
||||
return str;
|
||||
},
|
||||
base64(data) {
|
||||
let str = window.atob(data);
|
||||
let bytes = new Uint8Array(str.length);
|
||||
for(let i = 0; i < bytes.length; ++i) {
|
||||
bytes[i] = str.charCodeAt(i);
|
||||
}
|
||||
return bytes;
|
||||
},
|
||||
};
|
||||
|
||||
const BITWISE = {
|
||||
|
Loading…
x
Reference in New Issue
Block a user