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:
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 })
+ }
+}