Skip to content

Commit da279fa

Browse files
committed
feat: added WIP apikey request guard
1 parent 65e28bf commit da279fa

File tree

4 files changed

+70
-0
lines changed

4 files changed

+70
-0
lines changed

aw-server/src/config.rs

+7
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,8 @@ pub struct AWConfig {
2525
pub port: u16,
2626
#[serde(skip, default = "default_testing")]
2727
pub testing: bool, // This is not written to the config file (serde(skip))
28+
#[serde(default = "default_apikey")]
29+
pub apikey: Option<String>,
2830
#[serde(default = "default_cors")]
2931
pub cors: Vec<String>,
3032
}
@@ -35,6 +37,7 @@ impl Default for AWConfig {
3537
address: default_address(),
3638
port: default_port(),
3739
testing: default_testing(),
40+
apikey: default_apikey(),
3841
cors: default_cors(),
3942
}
4043
}
@@ -72,6 +75,10 @@ fn default_testing() -> bool {
7275
is_testing()
7376
}
7477

78+
fn default_apikey() -> Option<String> {
79+
None
80+
}
81+
7582
fn default_port() -> u16 {
7683
if is_testing() {
7784
5666

aw-server/src/endpoints/auth.rs

+51
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,51 @@
1+
/// On most systems we do not concern ourselves with local security [1], however on Android
2+
/// apps have their storage isolated yet ActivityWatch happily exposes its API and database
3+
/// through the HTTP API when the server is running. This could be considered a severe
4+
/// security flaw, and fixing it would significantly improve security on Android (as mentioned in [2]).
5+
///
6+
/// Requiring an API key can also be useful in other scenarios where an extra level of security is
7+
/// desired.
8+
///
9+
/// Based on the ApiKey example at [3].
10+
///
11+
/// [1]: https://docs.activitywatch.net/en/latest/security.html#activitywatch-is-only-as-secure-as-your-system
12+
/// [2]: https://forum.activitywatch.net/t/rest-api-supported-with-android-version-of-activity-watch/854/6?u=erikbjare
13+
/// [3]: https://api.rocket.rs/v0.4/rocket/request/trait.FromRequest.html
14+
use rocket::http::Status;
15+
use rocket::request::{self, FromRequest, Request};
16+
use rocket::{Outcome, State};
17+
18+
use crate::config::AWConfig;
19+
20+
struct ApiKey(Option<String>);
21+
22+
#[derive(Debug)]
23+
enum ApiKeyError {
24+
BadCount,
25+
Missing,
26+
Invalid,
27+
}
28+
29+
// TODO: Use guard on endpoints
30+
// TODO: Add tests for protected endpoints (important to ensure security)
31+
impl<'a, 'r> FromRequest<'a, 'r> for ApiKey {
32+
type Error = ApiKeyError;
33+
34+
fn from_request(request: &'a Request<'r>) -> request::Outcome<Self, Self::Error> {
35+
// TODO: How will this key be configured by the user?
36+
let config = request.guard::<State<AWConfig>>().unwrap();
37+
match &config.apikey {
38+
None => Outcome::Success(ApiKey(None)),
39+
Some(apikey) => {
40+
// TODO: How will this header be set in the browser?
41+
let keys: Vec<_> = request.headers().get("x-api-key").collect();
42+
match keys.len() {
43+
0 => Outcome::Failure((Status::BadRequest, ApiKeyError::Missing)),
44+
1 if apikey == keys[0] => Outcome::Success(ApiKey(Some(keys[0].to_string()))),
45+
1 => Outcome::Failure((Status::BadRequest, ApiKeyError::Invalid)),
46+
_ => Outcome::Failure((Status::BadRequest, ApiKeyError::BadCount)),
47+
}
48+
}
49+
}
50+
}
51+
}

aw-server/src/endpoints/cors.rs

+11
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,14 @@
1+
/// Cross-Origin Resource Sharing is a way to specify the permissions websites that do not share the origin have.
2+
///
3+
/// However, it's a check done by the browser when a response has already been received (but before it's accessible by the origin site).
4+
/// As such, it does *not* protect against all kinds of cross-origin attacks. As an example, a GET
5+
/// requests which has side-effects will still have such effects, even though the response was
6+
/// blocked by the browser.
7+
///
8+
/// In many cases, pre-flight requests are made to check CORS before the real request is made.
9+
///
10+
/// For more info, see: https://developer.mozilla.org/en-US/docs/Web/HTTP/CORS
11+
///
112
use rocket::http::Method;
213
use rocket_cors::{AllowedHeaders, AllowedOrigins};
314

aw-server/src/endpoints/mod.rs

+1
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,7 @@ pub struct ServerState {
1919

2020
#[macro_use]
2121
mod util;
22+
mod auth;
2223
mod bucket;
2324
mod cors;
2425
mod export;

0 commit comments

Comments
 (0)