Change "client key" to "client id" (#3130)

In #3118 @ryneeverett mentioned that "key" suggests that this is a
secret, when in truth it's just a user identifier. So "ID" is a better
word for it than "key".
This commit is contained in:
Dustin J. Mitchell
2023-07-11 22:13:53 -04:00
committed by GitHub
parent 8097e28318
commit 7f68441916
32 changed files with 387 additions and 388 deletions

View File

@@ -16,8 +16,8 @@ pub enum ServerConfig {
/// Sync server "origin"; a URL with schema and hostname but no path or trailing `/`
origin: String,
/// Client Key to identify and authenticate this replica to the server
client_key: Uuid,
/// Client ID to identify and authenticate this replica to the server
client_id: Uuid,
/// Private encryption secret used to encrypt all data sent to the server. This can
/// be any suitably un-guessable string of bytes.
@@ -32,9 +32,9 @@ impl ServerConfig {
ServerConfig::Local { server_dir } => Box::new(LocalServer::new(server_dir)?),
ServerConfig::Remote {
origin,
client_key,
client_id,
encryption_secret,
} => Box::new(RemoteServer::new(origin, client_key, encryption_secret)?),
} => Box::new(RemoteServer::new(origin, client_id, encryption_secret)?),
})
}
}

View File

@@ -12,23 +12,23 @@ const TASK_APP_ID: u8 = 1;
/// An Cryptor stores a secret and allows sealing and unsealing. It derives a key from the secret,
/// which takes a nontrivial amount of time, so it should be created once and re-used for the given
/// client_key.
/// client_id.
pub(super) struct Cryptor {
key: aead::LessSafeKey,
rng: rand::SystemRandom,
}
impl Cryptor {
pub(super) fn new(client_key: Uuid, secret: &Secret) -> Result<Self> {
pub(super) fn new(client_id: Uuid, secret: &Secret) -> Result<Self> {
Ok(Cryptor {
key: Self::derive_key(client_key, secret)?,
key: Self::derive_key(client_id, secret)?,
rng: rand::SystemRandom::new(),
})
}
/// Derive a key as specified for version 1. Note that this may take 10s of ms.
fn derive_key(client_key: Uuid, secret: &Secret) -> Result<aead::LessSafeKey> {
let salt = digest::digest(&digest::SHA256, client_key.as_bytes());
fn derive_key(client_id: Uuid, secret: &Secret) -> Result<aead::LessSafeKey> {
let salt = digest::digest(&digest::SHA256, client_id.as_bytes());
let mut key_bytes = vec![0u8; aead::CHACHA20_POLY1305.key_len()];
pbkdf2::derive(
@@ -268,10 +268,10 @@ mod test {
fn round_trip_bad_key() {
let version_id = Uuid::new_v4();
let payload = b"HISTORY REPEATS ITSELF".to_vec();
let client_key = Uuid::new_v4();
let client_id = Uuid::new_v4();
let secret = Secret(b"SEKRIT".to_vec());
let cryptor = Cryptor::new(client_key, &secret).unwrap();
let cryptor = Cryptor::new(client_id, &secret).unwrap();
let unsealed = Unsealed {
version_id,
@@ -280,7 +280,7 @@ mod test {
let sealed = cryptor.seal(unsealed).unwrap();
let secret = Secret(b"DIFFERENT_SECRET".to_vec());
let cryptor = Cryptor::new(client_key, &secret).unwrap();
let cryptor = Cryptor::new(client_id, &secret).unwrap();
assert!(cryptor.unseal(sealed).is_err());
}
@@ -288,10 +288,10 @@ mod test {
fn round_trip_bad_version() {
let version_id = Uuid::new_v4();
let payload = b"HISTORY REPEATS ITSELF".to_vec();
let client_key = Uuid::new_v4();
let client_id = Uuid::new_v4();
let secret = Secret(b"SEKRIT".to_vec());
let cryptor = Cryptor::new(client_key, &secret).unwrap();
let cryptor = Cryptor::new(client_id, &secret).unwrap();
let unsealed = Unsealed {
version_id,
@@ -303,13 +303,13 @@ mod test {
}
#[test]
fn round_trip_bad_client_key() {
fn round_trip_bad_client_id() {
let version_id = Uuid::new_v4();
let payload = b"HISTORY REPEATS ITSELF".to_vec();
let client_key = Uuid::new_v4();
let client_id = Uuid::new_v4();
let secret = Secret(b"SEKRIT".to_vec());
let cryptor = Cryptor::new(client_key, &secret).unwrap();
let cryptor = Cryptor::new(client_id, &secret).unwrap();
let unsealed = Unsealed {
version_id,
@@ -317,8 +317,8 @@ mod test {
};
let sealed = cryptor.seal(unsealed).unwrap();
let client_key = Uuid::new_v4();
let cryptor = Cryptor::new(client_key, &secret).unwrap();
let client_id = Uuid::new_v4();
let cryptor = Cryptor::new(client_id, &secret).unwrap();
assert!(cryptor.unseal(sealed).is_err());
}
@@ -340,13 +340,13 @@ mod test {
#[test]
fn good() {
let (version_id, client_key, encryption_secret) = defaults();
let (version_id, client_id, encryption_secret) = defaults();
let sealed = Sealed {
version_id,
payload: include_bytes!("test-good.data").to_vec(),
};
let cryptor = Cryptor::new(client_key, &Secret(encryption_secret)).unwrap();
let cryptor = Cryptor::new(client_id, &Secret(encryption_secret)).unwrap();
let unsealed = cryptor.unseal(sealed).unwrap();
assert_eq!(unsealed.payload, b"SUCCESS");
@@ -355,61 +355,61 @@ mod test {
#[test]
fn bad_version_id() {
let (version_id, client_key, encryption_secret) = defaults();
let (version_id, client_id, encryption_secret) = defaults();
let sealed = Sealed {
version_id,
payload: include_bytes!("test-bad-version-id.data").to_vec(),
};
let cryptor = Cryptor::new(client_key, &Secret(encryption_secret)).unwrap();
let cryptor = Cryptor::new(client_id, &Secret(encryption_secret)).unwrap();
assert!(cryptor.unseal(sealed).is_err());
}
#[test]
fn bad_client_key() {
let (version_id, client_key, encryption_secret) = defaults();
fn bad_client_id() {
let (version_id, client_id, encryption_secret) = defaults();
let sealed = Sealed {
version_id,
payload: include_bytes!("test-bad-client-key.data").to_vec(),
payload: include_bytes!("test-bad-client-id.data").to_vec(),
};
let cryptor = Cryptor::new(client_key, &Secret(encryption_secret)).unwrap();
let cryptor = Cryptor::new(client_id, &Secret(encryption_secret)).unwrap();
assert!(cryptor.unseal(sealed).is_err());
}
#[test]
fn bad_secret() {
let (version_id, client_key, encryption_secret) = defaults();
let (version_id, client_id, encryption_secret) = defaults();
let sealed = Sealed {
version_id,
payload: include_bytes!("test-bad-secret.data").to_vec(),
};
let cryptor = Cryptor::new(client_key, &Secret(encryption_secret)).unwrap();
let cryptor = Cryptor::new(client_id, &Secret(encryption_secret)).unwrap();
assert!(cryptor.unseal(sealed).is_err());
}
#[test]
fn bad_version() {
let (version_id, client_key, encryption_secret) = defaults();
let (version_id, client_id, encryption_secret) = defaults();
let sealed = Sealed {
version_id,
payload: include_bytes!("test-bad-version.data").to_vec(),
};
let cryptor = Cryptor::new(client_key, &Secret(encryption_secret)).unwrap();
let cryptor = Cryptor::new(client_id, &Secret(encryption_secret)).unwrap();
assert!(cryptor.unseal(sealed).is_err());
}
#[test]
fn bad_app_id() {
let (version_id, client_key, encryption_secret) = defaults();
let (version_id, client_id, encryption_secret) = defaults();
let sealed = Sealed {
version_id,
payload: include_bytes!("test-bad-app-id.data").to_vec(),
};
let cryptor = Cryptor::new(client_key, &Secret(encryption_secret)).unwrap();
let cryptor = Cryptor::new(client_id, &Secret(encryption_secret)).unwrap();
assert!(cryptor.unseal(sealed).is_err());
}
}

View File

@@ -1,6 +1,6 @@
# This file generates test-encrypted.data. To run it:
# - pip install cryptography pbkdf2
# - python taskchampion/src/server/generate-test-data.py taskchampion/src/server/
# - python taskchampion/taskchampion/src/server/generate-test-data.py taskchampion/taskchampion/src/server/
import os
import hashlib
@@ -12,15 +12,15 @@ import uuid
from cryptography.hazmat.primitives.ciphers.aead import ChaCha20Poly1305
# these values match values used in the rust tests
client_key = "0666d464-418a-4a08-ad53-6f15c78270cd"
client_id = "0666d464-418a-4a08-ad53-6f15c78270cd"
encryption_secret = b"b4a4e6b7b811eda1dc1a2693ded"
version_id = "b0517957-f912-4d49-8330-f612e73030c4"
def gen(
version_id=version_id, client_key=client_key, encryption_secret=encryption_secret,
version_id=version_id, client_id=client_id, encryption_secret=encryption_secret,
app_id=1, version=1):
# first, generate the encryption key
salt = hashlib.sha256(uuid.UUID(client_key).bytes).digest()
salt = hashlib.sha256(uuid.UUID(client_id).bytes).digest()
key = pbkdf2.PBKDF2(
encryption_secret,
salt,
@@ -61,8 +61,8 @@ def main():
with open(os.path.join(dir, 'test-bad-version-id.data'), "wb") as f:
f.write(gen(version_id=uuid.uuid4().hex))
with open(os.path.join(dir, 'test-bad-client-key.data'), "wb") as f:
f.write(gen(client_key=uuid.uuid4().hex))
with open(os.path.join(dir, 'test-bad-client-id.data'), "wb") as f:
f.write(gen(client_id=uuid.uuid4().hex))
with open(os.path.join(dir, 'test-bad-secret.data'), "wb") as f:
f.write(gen(encryption_secret=b"xxxxxxxxxxxxxxxxxxxxx"))

View File

@@ -10,7 +10,7 @@ use super::crypto::{Cryptor, Sealed, Secret, Unsealed};
pub struct RemoteServer {
origin: String,
client_key: Uuid,
client_id: Uuid,
cryptor: Cryptor,
agent: ureq::Agent,
}
@@ -25,18 +25,18 @@ const SNAPSHOT_CONTENT_TYPE: &str = "application/vnd.taskchampion.snapshot";
/// taskchampion-sync-server).
impl RemoteServer {
/// Construct a new RemoteServer. The `origin` is the sync server's protocol and hostname
/// without a trailing slash, such as `https://tcsync.example.com`. Pass a client_key to
/// without a trailing slash, such as `https://tcsync.example.com`. Pass a client_id to
/// identify this client to the server. Multiple replicas synchronizing the same task history
/// should use the same client_key.
/// should use the same client_id.
pub fn new(
origin: String,
client_key: Uuid,
client_id: Uuid,
encryption_secret: Vec<u8>,
) -> Result<RemoteServer> {
Ok(RemoteServer {
origin,
client_key,
cryptor: Cryptor::new(client_key, &Secret(encryption_secret.to_vec()))?,
client_id,
cryptor: Cryptor::new(client_id, &Secret(encryption_secret.to_vec()))?,
agent: ureq::AgentBuilder::new()
.timeout_connect(Duration::from_secs(10))
.timeout_read(Duration::from_secs(60))
@@ -86,7 +86,7 @@ impl Server for RemoteServer {
.agent
.post(&url)
.set("Content-Type", HISTORY_SEGMENT_CONTENT_TYPE)
.set("X-Client-Key", &self.client_key.to_string())
.set("X-Client-Id", &self.client_id.to_string())
.send_bytes(sealed.as_ref())
{
Ok(resp) => {
@@ -115,7 +115,7 @@ impl Server for RemoteServer {
match self
.agent
.get(&url)
.set("X-Client-Key", &self.client_key.to_string())
.set("X-Client-Id", &self.client_id.to_string())
.call()
{
Ok(resp) => {
@@ -148,7 +148,7 @@ impl Server for RemoteServer {
.agent
.post(&url)
.set("Content-Type", SNAPSHOT_CONTENT_TYPE)
.set("X-Client-Key", &self.client_key.to_string())
.set("X-Client-Id", &self.client_id.to_string())
.send_bytes(sealed.as_ref())
.map(|_| ())?)
}
@@ -158,7 +158,7 @@ impl Server for RemoteServer {
match self
.agent
.get(&url)
.set("X-Client-Key", &self.client_key.to_string())
.set("X-Client-Id", &self.client_id.to_string())
.call()
{
Ok(resp) => {

View File

@@ -1,2 +1,2 @@
$á­
†—Õ^~B>n)ji†¯1—î9™|µœÓ~
®
<EFBFBD>KŸo]æâʶ£McØ\ï©QL)cHÂ;ÚÎ-:

View File

@@ -0,0 +1 @@
%<25>ۇ <09><07><>ko¹<6F>{hكb<D983><62><EFBFBD>

View File

@@ -1 +0,0 @@
<01>ΝA4φ―Γθ

View File

@@ -1 +1 @@
/}åd E°‡dIcÁXéè-‡!V°Û%è4îáòd]³ÃÇ}
κsq<0F><>nΟΐk,Βν\ ‹ΕΘ;W¶< ΄'

View File

@@ -1 +1 @@
lΰζδa|ο@Ο<>S_¬…γzέV9£q¦Ρ…‘)+¦
 ñ±ŸâajJšÕ·ïq\IF4¤ó<C2A4>Y Ó£

View File

@@ -1 +1 @@
c╤TH╗Гp>╔╚Ф╨╕m4О╧к~в1╣0P░IЖ╢W╒
cR<06>ùË|¯|iKoÌÀ˜³+t•U|Ñ™ï˜&  —BIŸ·3

View File

@@ -1 +1 @@
pÑ¿µÒŸ½V²ûÝäToë"}cT·äY7Æ ˆÀ@ÙdLTý`Ò
PRÇojÇ—Þgs²&vMØYÔn<>œ?ƒÛcå¼~:œ