lab_presence

Unnamed repository; edit this file 'description' to name the repository.
Log | Files | Refs | README | LICENSE

commit 43a045fa37501800b163372416a045a26fdbcd88
parent 26f5e5b19ceffaa130cc5b3ca28b45e483157a7b
Author: minerva-jupiter <ryouturn@gmail.com>
Date:   Sat,  4 Jul 2026 21:46:36 +0900

feat: initialize workspace and implement shared presence logic

- Created a Rust workspace containing `lab_core`, `nfc_sender`, and `shared` crates.
- Implemented `LabPresence` struct and hashing utilities in the `shared` crate.
- Updated `README.md` to reflect new login authentication specifications.
- Configured `.gitignore` to ignore the `target` directory.

Diffstat:
A.env | 0
A.gitignore | 1+
ACargo.lock | 107+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
ACargo.toml | 3+++
MREADME.md | 96++++++++++++++++++++++++++++++++++++++++++++++++-------------------------------
Alab_core/Cargo.toml | 6++++++
Alab_core/src/main.rs | 3+++
Anfc_sender/Cargo.toml | 6++++++
Anfc_sender/src/main.rs | 3+++
Ashared/Cargo.toml | 8++++++++
Ashared/src/lib.rs | 82+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
11 files changed, 277 insertions(+), 38 deletions(-)

diff --git a/.env b/.env diff --git a/.gitignore b/.gitignore @@ -0,0 +1 @@ +/target diff --git a/Cargo.lock b/Cargo.lock @@ -0,0 +1,107 @@ +# This file is automatically @generated by Cargo. +# It is not intended for manual editing. +version = 4 + +[[package]] +name = "block-buffer" +version = "0.12.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d2f6c7dbe95a6ed67ad9f18e57daf93a2f034c524b99fd2b76d18fdfeb6660aa" +dependencies = [ + "hybrid-array", +] + +[[package]] +name = "cfg-if" +version = "1.0.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9330f8b2ff13f34540b44e946ef35111825727b38d33286ef986142615121801" + +[[package]] +name = "const-oid" +version = "0.10.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a6ef517f0926dd24a1582492c791b6a4818a4d94e789a334894aa15b0d12f55c" + +[[package]] +name = "cpufeatures" +version = "0.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8b2a41393f66f16b0823bb79094d54ac5fbd34ab292ddafb9a0456ac9f87d201" +dependencies = [ + "libc", +] + +[[package]] +name = "crypto-common" +version = "0.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ce6e4c961d6cd6c9a86db418387425e8bdeaf05b3c8bc1411e6dca4c252f1453" +dependencies = [ + "hybrid-array", +] + +[[package]] +name = "digest" +version = "0.11.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f1dd6dbb5841937940781866fa1281a1ff7bd3bf827091440879f9994983d5c2" +dependencies = [ + "block-buffer", + "const-oid", + "crypto-common", +] + +[[package]] +name = "dotenv" +version = "0.15.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "77c90badedccf4105eca100756a0b1289e191f6fcbdadd3cee1d2f614f97da8f" + +[[package]] +name = "hybrid-array" +version = "0.4.13" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "818356c5132c1fede50f837ca96afbe78ff42413047f4abb886217845e1b6c8c" +dependencies = [ + "typenum", +] + +[[package]] +name = "lab_core" +version = "0.1.0" + +[[package]] +name = "libc" +version = "0.2.186" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "68ab91017fe16c622486840e4c83c9a37afeff978bd239b5293d61ece587de66" + +[[package]] +name = "nfc_sender" +version = "0.1.0" + +[[package]] +name = "sha2" +version = "0.11.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "446ba717509524cb3f22f17ecc096f10f4822d76ab5c0b9822c5f9c284e825f4" +dependencies = [ + "cfg-if", + "cpufeatures", + "digest", +] + +[[package]] +name = "shared" +version = "0.1.0" +dependencies = [ + "dotenv", + "sha2", +] + +[[package]] +name = "typenum" +version = "1.20.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b6f5e870be6c3b371b77fe0ee0bafb859fa4964b4404c27de1d380043c4dda20" diff --git a/Cargo.toml b/Cargo.toml @@ -0,0 +1,3 @@ +[workspace] +members = ["shared","lab_core","nfc_sender"] +resolver = "2" diff --git a/README.md b/README.md @@ -34,42 +34,6 @@ https://spec.matrix.org/v1.18/client-server-api/#client-behaviour-8 However, to determine which state was the most recent when the Lab network was disconnected, it seems necessary to also send the timestamp of when that status was saved. # specs -## NFC sends toggle presence(maybe mean entering and leaving the lab) - -|item|spec| -|-|-| -|http method|put| -|end point|/api/v1/presence/toggle| -|auth|Authorization: Bearer <token>| - -### Request -```json -{ - "presence_toggle": true, - "timestamp": unixtime -} -``` -The <token> is created by adding the user ID, salt, and the pepper held by the NFC sender to the hash. - -### Response -|Status|Description| -|-|-| -|200|the new presence state was set.| -|404|user or nfc device is not found| - -#### 200 -```json -{} -``` - -#### 404 -```json -{ - "errorcode": "Not Found", -} -``` - - ## get presence(for slint or sync between the webserver and the hub) |item|spec| @@ -78,7 +42,7 @@ The <token> is created by adding the user ID, salt, and the pepper held by the N |end point|/api/v1/presence/{userId}/status| |auth|Authorization: Bearer <token>| -<token> is a device-specific access token. +<token> is a hashed onetime device-specific access token. ### Request @@ -127,7 +91,7 @@ Request parameters |end point|/api/v1/presence/{userId}/status| |auth|Authorizaiton: Bearer <token>| -<token is a device-specific access token. +<token> is a hashed onetime device-specific access token. ### Request @@ -164,5 +128,61 @@ Request parameters } ``` +## login(to get onetime device-specific access token) + +|item|spec| +|-|-| +|http method|post| +|end point|/api/v1/login| +|auth|none| + +### Request + +Request parameters + +|Name|Type|Description| +|-|-|-| +|device_id|string|Required: device id| +|device_secret|string|Required: device secret(like refresh token)| + +```json +{ + "device_id": "", + "device_secret": "" +} +``` + +### Response + +|Status|Description| +|-|-| +|200|The presence state for this device.| +|403|You are not allowed to get onetime access token.| +|404|There is no presence state for this device. This device may not exist or isn't exposing presence information to you.| + +#### 200 +```json +{ + "access_token": "", + "expires_in": 3600 +} +``` +#### 403 +```json +{ + "errcode": "M_FORBIDDEN", + "error": "authorization failed", +} +``` +#### 404 +```json +{ + "errcode": "M_NOT_FOUND", + "error": "requested device was not found." +} +``` + +--- + # another presence updete system can add! If you have right to look lab's internet ARP table, you can use it. diff --git a/lab_core/Cargo.toml b/lab_core/Cargo.toml @@ -0,0 +1,6 @@ +[package] +name = "lab_core" +version = "0.1.0" +edition = "2024" + +[dependencies] diff --git a/lab_core/src/main.rs b/lab_core/src/main.rs @@ -0,0 +1,3 @@ +fn main() { + println!("Hello, world!"); +} diff --git a/nfc_sender/Cargo.toml b/nfc_sender/Cargo.toml @@ -0,0 +1,6 @@ +[package] +name = "nfc_sender" +version = "0.1.0" +edition = "2024" + +[dependencies] diff --git a/nfc_sender/src/main.rs b/nfc_sender/src/main.rs @@ -0,0 +1,3 @@ +fn main() { + println!("Hello, world!"); +} diff --git a/shared/Cargo.toml b/shared/Cargo.toml @@ -0,0 +1,8 @@ +[package] +name = "shared" +version = "0.1.0" +edition = "2024" + +[dependencies] +dotenv = "0" +sha2 = "0" diff --git a/shared/src/lib.rs b/shared/src/lib.rs @@ -0,0 +1,82 @@ +use dotenv::dotenv; +use sha2::Digest; +use std::error::Error; + +pub struct LabPresence { + presence: String, + status_msg: Option<String>, + timestamp: u64, +} + +impl LabPresence { + pub fn new(presence: String, status_msg: Option<String>, timestamp: u64) -> Self { + Self { + presence, + status_msg, + timestamp, + } + } + + pub fn presence(&self) -> &str { + &self.presence + } + + pub fn status_msg(&self) -> Option<&str> { + self.status_msg.as_deref() + } + + pub fn timestamp(&self) -> u64 { + self.timestamp + } + + pub fn set( + &mut self, + presence: String, + status_msg: Option<String>, + timestamp: u64, + ) -> Result<(), Box<dyn Error>> { + self.presence = presence; + self.status_msg = status_msg; + self.timestamp = timestamp; + Ok(()) + } + + pub fn update( + &mut self, + presence: String, + status_msg: Option<String>, + timestamp: u64, + ) -> Result<(), Box<dyn std::error::Error>> { + if timestamp > self.timestamp { + self.presence = presence; + self.status_msg = status_msg; + self.timestamp = timestamp; + Ok(()) + } else { + Err(Box::new(std::io::Error::new( + std::io::ErrorKind::Other, + "timestamp is not greater than current timestamp", + ))) + } + } +} + +pub struct UserId { + pub id: String, +} +impl UserId { + pub fn get_id(idm: String) -> Result<Self, Box<dyn std::error::Error>> { + let _ = dotenv(); + let salt = std::env::var("SALT")?; + let mut hasher = sha2::Sha256::new(); + hasher.update(idm.as_bytes()); + hasher.update(salt.as_bytes()); + let result = hasher + .finalize() + .iter() + .map(|b| format!("{:02x}", b)) + .collect::<String>(); + + Ok(Self { id: result }) + } +}