From a90ace5af983b7e01433e9102750dc4fcdaeba4f Mon Sep 17 00:00:00 2001 From: yukirij Date: Sat, 24 Aug 2024 15:19:06 -0700 Subject: [PATCH] Add URL and authentication persistence. --- server/src/app/mod.rs | 15 + server/src/app/user.rs | 4 +- server/src/main.rs | 18 +- server/src/manager/data.rs | 10 +- server/src/manager/ws.rs | 6 +- server/src/protocol/packet/game_history.rs | 3 + server/src/system/filesystem/mod.rs | 6 +- www/.html | 4 +- www/js/game_asset.js | 18 +- www/js/scene.js | 145 ++++-- www/js/system.js | 537 +++++++++++---------- www/js/ui.js | 41 +- www/js/util.js | 17 +- 13 files changed, 459 insertions(+), 365 deletions(-) diff --git a/server/src/app/mod.rs b/server/src/app/mod.rs index 5aa3586..50aa4d5 100644 --- a/server/src/app/mod.rs +++ b/server/src/app/mod.rs @@ -28,6 +28,8 @@ pub struct App { pub auths:Trie, pub sessions:Trie, + pub contests:Vec, + pub session_time:Chain, } 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 { diff --git a/server/src/app/user.rs b/server/src/app/user.rs index edd94c3..d7daff7 100644 --- a/server/src/app/user.rs +++ b/server/src/app/user.rs @@ -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, pub na_key:u32, diff --git a/server/src/main.rs b/server/src/main.rs index 01129e4..3552e9b 100644 --- a/server/src/main.rs +++ b/server/src/main.rs @@ -53,21 +53,15 @@ async fn service_http(mut request:hyper::Request, args:Ht .unwrap()) } } else { - match request.uri().path() { - "/" => Ok(Response::builder() + 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() .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()) { - 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()) - } } } } diff --git a/server/src/manager/data.rs b/server/src/manager/data.rs index 19123a8..abd93e7 100644 --- a/server/src/manager/data.rs +++ b/server/src/manager/data.rs @@ -105,12 +105,12 @@ pub async fn thread_system(mut app:App, bus:Bus) 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) } 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) } 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) { diff --git a/server/src/manager/ws.rs b/server/src/manager/ws.rs index ac0e958..deed771 100644 --- a/server/src/manager/ws.rs +++ b/server/src/manager/ws.rs @@ -64,7 +64,7 @@ pub async fn handle_ws(ws:WebSocketStream>, 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>, 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>, args:HttpServiceAr QRPacket::new(conn_id, QRPacketData::QAuthResume(packet)) ).ok(); } - Err(_) => { } + Err(_) => { println!("error: packet decode failed."); } } CODE_AUTH_REVOKE => { diff --git a/server/src/protocol/packet/game_history.rs b/server/src/protocol/packet/game_history.rs index 59291c4..cc14b9e 100644 --- a/server/src/protocol/packet/game_history.rs +++ b/server/src/protocol/packet/game_history.rs @@ -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, @@ -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), diff --git a/server/src/system/filesystem/mod.rs b/server/src/system/filesystem/mod.rs index c6d3a9c..71e92cd 100644 --- a/server/src/system/filesystem/mod.rs +++ b/server/src/system/filesystem/mod.rs @@ -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, diff --git a/www/.html b/www/.html index 0dffd91..913d963 100644 --- a/www/.html +++ b/www/.html @@ -7,8 +7,8 @@ - - + + diff --git a/www/js/game_asset.js b/www/js/game_asset.js index 575b8b5..6fe0d22 100644 --- a/www/js/game_asset.js +++ b/www/js/game_asset.js @@ -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") ], ], }; diff --git a/www/js/scene.js b/www/js/scene.js index 58abcef..27c7f30 100644 --- a/www/js/scene.js +++ b/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); + } } diff --git a/www/js/system.js b/www/js/system.js index defe51e..08a7ad0 100644 --- a/www/js/system.js +++ b/www/js/system.js @@ -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,265 +46,178 @@ function RESUME() { } function MESSAGE(event) { - if(SCENE.message !== undefined) { - let bytes = new Uint8Array(event.data); - let code = 0; - let index = 2; - let data = null; - let result = null; + let bytes = new Uint8Array(event.data); + let code = 0; + let index = 2; + let data = null; + let result = null; - if(bytes.length >= 2) { - code = (bytes[0] << 8) + bytes[1]; - } + if(bytes.length >= 2) { + code = (bytes[0] << 8) + bytes[1]; + } - switch(code) { - case OpCode.Register: { - console.log("RECV Register"); + switch(code) { + case OpCode.Register: { + console.log("RECV Register"); - if(bytes.length - index == 26) { - data = { - status:(bytes[2] << 8) + bytes[3], - token:new Uint8Array(8), - secret:new Uint8Array(16), - }; - index += 2; + if(bytes.length - index == 26) { + data = { + status:(bytes[2] << 8) + bytes[3], + token:new Uint8Array(8), + secret:new Uint8Array(16), + }; + index += 2; - for(let i = 0; i < 8; ++i) { - data.token[i] = bytes[index++]; - } - for(let i = 0; i < 16; ++i) { - data.secret[i] = bytes[index++]; - } - } else { - console.error("Register packet bad length:" + bytes.length); - return; + for(let i = 0; i < 8; ++i) { + data.token[i] = bytes[index++]; } - } break; - - case OpCode.Authenticate: { - console.log("RECV Authenticate"); - - if(bytes.length - index == 26) { - data = { - status:(bytes[2] << 8) + bytes[3], - token:new Uint8Array(), - secret:new Uint8Array(), - }; - index += 2; - - for(let i = 0; i < 8; ++i) { - data.token += bytes[index++]; - } - for(let i = 0; i < 16; ++i) { - data.secret += bytes[index++]; - } - } else { - console.error("Authenticate packet bad length:" + bytes.length); - return; + for(let i = 0; i < 16; ++i) { + data.secret[i] = bytes[index++]; } - } break; + } else { + console.error("Register packet bad length:" + bytes.length); + return; + } + } break; - case OpCode.Resume: { - console.log("RECV Resume"); + case OpCode.Authenticate: { + console.log("RECV Authenticate"); + + if(bytes.length - index == 26) { + data = { + status:(bytes[2] << 8) + bytes[3], + token:new Uint8Array(8), + secret:new Uint8Array(16), + }; + index += 2; + + for(let i = 0; i < 8; ++i) { + data.token[i] = bytes[index++]; + } + for(let i = 0; i < 16; ++i) { + data.secret[i] = bytes[index++]; + } + } else { + console.error("Authenticate packet bad length:" + bytes.length); + return; + } + } break; + + case OpCode.Resume: { + console.log("RECV Resume"); + + result = UNPACK.u16(bytes, index); + index = result.index; + if(result.data != Status.Ok) { + sessionStorage.clear(); + } + + LOAD_URL(); + } break; + + case OpCode.Deauthenticate: { + console.log("RECV Deauthenticate"); + } break; + + case OpCode.SessionList: { + console.log("RECV Session list"); + + if(bytes.length - index >= 2) { + data = { + records: [], + }; result = UNPACK.u16(bytes, index); index = result.index; - if(result.data != Status.Ok) { - CONTEXT.Auth = null; - } + let count = result.data; - LOAD(CONTEXT.Scene); - } break; - - case OpCode.Deauthenticate: { - console.log("RECV Deauthenticate"); - } break; - - case OpCode.SessionList: { - console.log("RECV Session list"); - - if(bytes.length - index >= 2) { - data = { - records: [], + for(let i = 0; i < count; ++i) { + let record = { + token: new Uint8Array(8), + dawn: "", + dusk: "", + turn: 0, + move: "", + viewers: 0, + player: false, }; - result = UNPACK.u16(bytes, index); - index = result.index; - let count = result.data; - - for(let i = 0; i < count; ++i) { - let record = { - token: new Uint8Array(8), - dawn: "", - dusk: "", - turn: 0, - move: "", - viewers: 0, - player: false, - }; - - if(index <= bytes.length + 8) { - for(let i = 0; i < 8; ++i) { - record.token[i] = bytes[index]; - index += 1; - } + if(index <= bytes.length + 8) { + for(let i = 0; i < 8; ++i) { + record.token[i] = bytes[index]; + index += 1; } - - result = UNPACK.string(bytes, index); - index = result.index; - record.dawn = result.data; - - result = UNPACK.string(bytes, index); - index = result.index; - record.dusk = result.data; - - result = UNPACK.u16(bytes, index); - index = result.index; - record.turn = result.data; - - if(index <= bytes.length + 3) { - let move = new Uint8Array(3); - for(let i = 0; i < 3; ++i) { - move[i] = bytes[index]; - index += 1; - } - record.move = UNPACK.move(move); - } - - result = UNPACK.u32(bytes, index); - index = result.index; - record.viewers = result.data; - - record.player = bytes[index++] != 0; - - data.records.push(record); } - } - } break; - - case OpCode.SessionCreate: - case OpCode.SessionJoin: { - console.log("RECV SessionCreate/Join"); - - if(bytes.length - index == 11) { - data = { - status:0, - token:new Uint8Array(8), - mode:2, - }; - - result = UNPACK.u16(bytes, index); - index = result.index; - data.status = result.data; - - result = UNPACK.u8(bytes, index); - index = result.index; - data.mode = result.data; - - for(let i = 0; i < 8; ++i) { data.token[i] = bytes[index++]; } - } - } break; - - case OpCode.GameState: { - console.log("RECV GameState"); - - //if(bytes.length - index >= 22) { - data = { - status:0, - player:2, - turn:0, - play:new GAME.Play(), - dawn:"", - dusk:"", - pool_dawn:[ ], - pool_dusk:[ ], - pieces:[ ], - }; - - // Status - result = UNPACK.u16(bytes, index); - index = result.index; - data.status = result.data; - - // Flags - result = UNPACK.u16(bytes, index); - index = result.index; - let flags = result.data; - - data.player = flags & 0x3; - - // Last Play - result = UNPACK.u16(bytes, index); - index = result.index; - data.play.source = result.data & 0xF; - data.play.from = (result.data >> 4) & 0x3F; - data.play.to = (result.data >> 10) & 0x3F; - - // Turn - result = UNPACK.u16(bytes, index); - index = result.index; - data.turn = result.data; - - // Handles - result = UNPACK.string(bytes, index); - index = result.index; - data.dawn = result.data; result = UNPACK.string(bytes, index); index = result.index; - data.dusk = result.data; + record.dawn = result.data; + + result = UNPACK.string(bytes, index); + index = result.index; + record.dusk = result.data; - // Dawn pool result = UNPACK.u16(bytes, index); index = result.index; - let dawn_pool_bits = result.data; + record.turn = result.data; - data.pool_dawn.push(dawn_pool_bits & 0x1F); - data.pool_dawn.push((dawn_pool_bits >> 5) & 0x3); - data.pool_dawn.push((dawn_pool_bits >> 7) & 0x3); - data.pool_dawn.push((dawn_pool_bits >> 9) & 0x3); - data.pool_dawn.push((dawn_pool_bits >> 11) & 0x3); - data.pool_dawn.push((dawn_pool_bits >> 13) & 0x1); - data.pool_dawn.push((dawn_pool_bits >> 14) & 0x1); - - // Dusk pool - result = UNPACK.u16(bytes, index); - index = result.index; - let dusk_pool_bits = result.data; - - data.pool_dusk.push(dusk_pool_bits & 0x1f); - data.pool_dusk.push((dusk_pool_bits >> 5) & 0x3); - data.pool_dusk.push((dusk_pool_bits >> 7) & 0x3); - data.pool_dusk.push((dusk_pool_bits >> 9) & 0x3); - data.pool_dusk.push((dusk_pool_bits >> 11) & 0x3); - data.pool_dusk.push((dusk_pool_bits >> 13) & 0x1); - data.pool_dusk.push((dusk_pool_bits >> 14) & 0x1); - - // Pieces - for(let i = 0; i < GAME.Const.Count.Pieces; ++i) { - result = UNPACK.u16(bytes, index); - index = result.index; - let piece_data = result.data; - - if((piece_data & 1) != 0) { - let piece = new GAME.Piece((piece_data >> 1) & 0x7, (piece_data >> 5) & 1); - piece.promoted = ((piece_data >> 4) & 1) != 0; - piece.tile = (piece_data >> 6) & 0x3F; - - data.pieces.push(piece); - } else { - data.pieces.push(null); + if(index <= bytes.length + 3) { + let move = new Uint8Array(3); + for(let i = 0; i < 3; ++i) { + move[i] = bytes[index]; + index += 1; } + record.move = UNPACK.move(move); } - //} - } break; - case OpCode.GamePlay: { - console.log("RECV GamePlay"); + result = UNPACK.u32(bytes, index); + index = result.index; + record.viewers = result.data; + record.player = bytes[index++] != 0; + + data.records.push(record); + } + } + } break; + + case OpCode.SessionCreate: + case OpCode.SessionJoin: { + console.log("RECV SessionCreate/Join"); + + if(bytes.length - index == 11) { data = { status:0, - play:new GAME.Play(0, 0, 0), + token:new Uint8Array(8), + mode:2, + }; + + result = UNPACK.u16(bytes, index); + index = result.index; + data.status = result.data; + + result = UNPACK.u8(bytes, index); + index = result.index; + data.mode = result.data; + + for(let i = 0; i < 8; ++i) { data.token[i] = bytes[index++]; } + } + } break; + + case OpCode.GameState: { + console.log("RECV GameState"); + + //if(bytes.length - index >= 22) { + data = { + status:0, + player:2, + turn:0, + play:new GAME.Play(), + dawn:"", + dusk:"", + pool_dawn:[ ], + pool_dusk:[ ], + pieces:[ ], }; // Status @@ -306,33 +225,24 @@ function MESSAGE(event) { index = result.index; data.status = result.data; - // Turn + // Flags result = UNPACK.u16(bytes, index); index = result.index; - data.turn = result.data; + let flags = result.data; - // Play description + data.player = flags & 0x3; + + // Last Play result = UNPACK.u16(bytes, index); index = result.index; data.play.source = result.data & 0xF; data.play.from = (result.data >> 4) & 0x3F; data.play.to = (result.data >> 10) & 0x3F; - } break; - case OpCode.GameHistory: { - console.log("RECV GameHistory"); - - data = { - status:0, - dawn:"", - dusk:"", - history:[ ], - }; - - // Status + // Turn result = UNPACK.u16(bytes, index); index = result.index; - data.status = result.data; + data.turn = result.data; // Handles result = UNPACK.string(bytes, index); @@ -343,30 +253,127 @@ function MESSAGE(event) { index = result.index; data.dusk = result.data; - // Pieces + // Dawn pool result = UNPACK.u16(bytes, index); index = result.index; - let history_length = result.data; + let dawn_pool_bits = result.data; - for(let i = 0; i < history_length; ++i) { + data.pool_dawn.push(dawn_pool_bits & 0x1F); + data.pool_dawn.push((dawn_pool_bits >> 5) & 0x3); + data.pool_dawn.push((dawn_pool_bits >> 7) & 0x3); + data.pool_dawn.push((dawn_pool_bits >> 9) & 0x3); + data.pool_dawn.push((dawn_pool_bits >> 11) & 0x3); + data.pool_dawn.push((dawn_pool_bits >> 13) & 0x1); + data.pool_dawn.push((dawn_pool_bits >> 14) & 0x1); + + // Dusk pool + result = UNPACK.u16(bytes, index); + index = result.index; + let dusk_pool_bits = result.data; + + data.pool_dusk.push(dusk_pool_bits & 0x1f); + data.pool_dusk.push((dusk_pool_bits >> 5) & 0x3); + data.pool_dusk.push((dusk_pool_bits >> 7) & 0x3); + data.pool_dusk.push((dusk_pool_bits >> 9) & 0x3); + data.pool_dusk.push((dusk_pool_bits >> 11) & 0x3); + data.pool_dusk.push((dusk_pool_bits >> 13) & 0x1); + data.pool_dusk.push((dusk_pool_bits >> 14) & 0x1); + + // Pieces + for(let i = 0; i < GAME.Const.Count.Pieces; ++i) { result = UNPACK.u16(bytes, index); index = result.index; - - data.history.push(new GAME.Play( - result.data & 0xF, - (result.data >> 4) & 0x3F, - (result.data >> 10) & 0x3F, - )); + let piece_data = result.data; + + if((piece_data & 1) != 0) { + let piece = new GAME.Piece((piece_data >> 1) & 0x7, (piece_data >> 5) & 1); + piece.promoted = ((piece_data >> 4) & 1) != 0; + piece.tile = (piece_data >> 6) & 0x3F; + + data.pieces.push(piece); + } else { + data.pieces.push(null); + } } - } break; + //} + } break; - default: - console.log("RECV Undefined " + code); - return; - } + case OpCode.GamePlay: { + console.log("RECV GamePlay"); - if(SCENE.message !== undefined) { SCENE.message(code, data) }; + data = { + status:0, + play:new GAME.Play(0, 0, 0), + }; + + // Status + result = UNPACK.u16(bytes, index); + index = result.index; + data.status = result.data; + + // Turn + result = UNPACK.u16(bytes, index); + index = result.index; + data.turn = result.data; + + // Play description + result = UNPACK.u16(bytes, index); + index = result.index; + data.play.source = result.data & 0xF; + data.play.from = (result.data >> 4) & 0x3F; + data.play.to = (result.data >> 10) & 0x3F; + } break; + + case OpCode.GameHistory: { + console.log("RECV GameHistory"); + + data = { + status:0, + token:new Uint8Array(8), + dawn:"", + dusk:"", + history:[ ], + }; + + // Status + result = UNPACK.u16(bytes, index); + 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; + data.dawn = result.data; + + result = UNPACK.string(bytes, index); + index = result.index; + data.dusk = result.data; + + // Pieces + result = UNPACK.u16(bytes, index); + index = result.index; + let history_length = result.data; + + for(let i = 0; i < history_length; ++i) { + result = UNPACK.u16(bytes, index); + index = result.index; + + data.history.push(new GAME.Play( + result.data & 0xF, + (result.data >> 4) & 0x3F, + (result.data >> 10) & 0x3F, + )); + } + } break; + + default: + console.log("RECV Undefined " + code); + return; } + if(SCENE.message !== undefined) { SCENE.message(code, data) }; } function MESSAGE_COMPOSE(data) { diff --git a/www/js/ui.js b/www/js/ui.js index 1932c95..4d260a5 100644 --- a/www/js/ui.js +++ b/www/js/ui.js @@ -90,31 +90,20 @@ 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 { - left.appendChild(UI.button("Contest", () => { MESSAGE_SESSION_START(); })); - left.appendChild(UI.button("Challenge", () => { })); + 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)); diff --git a/www/js/util.js b/www/js/util.js index 88e0a94..825475d 100644 --- a/www/js/util.js +++ b/www/js/util.js @@ -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 = {