Skip to content

Commit

Permalink
Merge branch 'develop'
Browse files Browse the repository at this point in the history
  • Loading branch information
nykma committed Aug 24, 2022
2 parents 8f8bd51 + 02b920d commit d5aa762
Show file tree
Hide file tree
Showing 12 changed files with 99 additions and 38 deletions.
2 changes: 2 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -1,5 +1,7 @@
/lambda.mk
/target

.vscode

/config/*.toml
!/config/main_sample.toml
5 changes: 5 additions & 0 deletions Dockerfile
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,11 @@ ADD Cargo.lock .

RUN source ~/.cargo/env && cargo fetch

ARG COMMIT=""
ARG NOW=""
ENV KV_SERVER_BUILD_AT=${NOW}
ENV KV_SERVER_CURRENT_COMMIT_ID=${COMMIT}

ADD . .
RUN source ~/.cargo/env && cargo build --release --example lambda

Expand Down
2 changes: 1 addition & 1 deletion Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,7 @@ lambda-delete:
@aws lambda delete-function --function-name ${func}

lambda-container-build:
@docker build --platform linux/amd64 -t nextid/kv-server-lambda:latest .
@docker build --platform linux/amd64 --build-arg=COMMIT=$(git rev-parse --short HEAD) --build-arg=NOW=$(date +%s) -t nextid/kv-server-lambda:latest .

pg-connect:
@echo "kv_server\n" | docker-compose exec pg psql -Ukv_server kv_server_development
Expand Down
22 changes: 13 additions & 9 deletions docs/api.apib
Original file line number Diff line number Diff line change
Expand Up @@ -30,17 +30,19 @@ for Rust.

+ Parameters

- persona (string, required) - Persona pubilc key (hexstring started with `0x`).
- persona (string, required) - Deprecated. Use `avatar` instead.
- avatar (string, required) - Persona public key (hexstring started with `0x`).

+ Example

`GET /v1/kv?persona=0x04c7cacde73af939c35d527b34e0556ea84bab27e6c0ed7c6c59be70f6d2db59c206b23529977117dc8a5d61fa848f94950422b79d1c142bcf623862e49f9e6575`
`GET /v1/kv?avatar=0x04c7cacde73af939c35d527b34e0556ea84bab27e6c0ed7c6c59be70f6d2db59c206b23529977117dc8a5d61fa848f94950422b79d1c142bcf623862e49f9e6575`

+ Response 200 (application/json)

+ Attributes (object)

+ persona (string, required) - Persona public key (uncomressed hexstring started with `0x`).
+ persona (string, required) - Deprecated. Use `avatar` instead.
+ avatar (string, required) - Avatar public key (uncompressed hexstring started with `0x`).
+ proofs (array[object], required) - All proofs belong to this persona
+ platform (string, required) - Platform (incl. `nextid`, which means public key itself).
+ identity (string, required) - Identity.
Expand All @@ -49,7 +51,7 @@ for Rust.
+ Body

{
"persona": "0x04c7cacde73af939c35d527b34e0556ea84bab27e6c0ed7c6c59be70f6d2db59c206b23529977117dc8a5d61fa848f94950422b79d1c142bcf623862e49f9e6575",
"avatar": "0x04c7cacde73af939c35d527b34e0556ea84bab27e6c0ed7c6c59be70f6d2db59c206b23529977117dc8a5d61fa848f94950422b79d1c142bcf623862e49f9e6575",
"proofs": [{
"platform": "nextid",
"identity": "0x04c7cacde73.....",
Expand All @@ -69,7 +71,7 @@ for Rust.

+ Response 404 (application/json)

Persona not found (no KV was ever created).
Avatar not found (no KV was ever created).

## Get signature payload for updating [POST /v1/kv/payload]

Expand All @@ -79,15 +81,16 @@ Persona not found (no KV was ever created).

+ Attributes (object)

+ persona (string, required) - Persona public key (both comressed / uncompressed and with/without `0x` are OK).
+ persona (string, required) - Deprecated. Use `avatar` instead.
+ avatar (string, required) - Avatar public key (both comressed / uncompressed and with/without `0x` are OK).
+ platform (string, required) - Platform (incl. `nextid`, which means public key itself).
+ identity (string, required) - Identity.
+ patch (object, required) - Patch to current data

+ Body

{
"persona": "0x04c7cacde73af939c35d527b34e0556ea84bab27e6c0ed7c6c59be70f6d2db59c206b23529977117dc8a5d61fa848f94950422b79d1c142bcf623862e49f9e6575",
"avatar": "0x04c7cacde73af939c35d527b34e0556ea84bab27e6c0ed7c6c59be70f6d2db59c206b23529977117dc8a5d61fa848f94950422b79d1c142bcf623862e49f9e6575",
"platform": "nextid",
"identity": "0x04c7cacde73af939c35d527b34e0556ea84bab27e6c0ed7c6c59be70f6d2db59c206b23529977117dc8a5d61fa848f94950422b79d1c142bcf623862e49f9e6575",
"patch": {
Expand Down Expand Up @@ -124,7 +127,8 @@ Persona not found (no KV was ever created).

+ Attributes (object)

+ persona (string, required) - Persona public key.
+ persona (string, required) - Deprecated. Use `avatar` instead.
+ avatar (string, required) - Avatar public key.
+ platform (string, required) - Platform (incl. `nextid`, which means public key itself).
+ identity (string, required) - Identity.
+ uuid (string, required) - UUID generated by server in `POST /v1/kv/payload`.
Expand All @@ -135,7 +139,7 @@ Persona not found (no KV was ever created).
+ Body

{
"persona": "0x04c7cacde73af939c35d527b34e0556ea84bab27e6c0ed7c6c59be70f6d2db59c206b23529977117dc8a5d61fa848f94950422b79d1c142bcf623862e49f9e6575",
"avatar": "0x04c7cacde73af939c35d527b34e0556ea84bab27e6c0ed7c6c59be70f6d2db59c206b23529977117dc8a5d61fa848f94950422b79d1c142bcf623862e49f9e6575",
"platform": "nextid",
"identity": "0x04c7cacde73af939c35d527b34e0556ea84bab27e6c0ed7c6c59be70f6d2db59c206b23529977117dc8a5d61fa848f94950422b79d1c142bcf623862e49f9e6575",
"uuid": "40c13c92-31e5-40d1-aebb-143d8e5b9c5e",
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
-- This file should undo anything in `up.sql`

CREATE UNIQUE INDEX idx_platform_identity
ON kv((lower(platform)), (lower(identity)));
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
-- Your SQL goes here

DROP INDEX IF EXISTS idx_platform_identity;
4 changes: 4 additions & 0 deletions src/controller/healthz.rs
Original file line number Diff line number Diff line change
Expand Up @@ -8,13 +8,17 @@ use serde::Serialize;
#[derive(Serialize)]
struct HealthzResponse {
pub hello: String,
pub build_at: String,
pub commit_version: String,
}

pub async fn controller(_req: Request) -> Result<Response, Error> {
json_response(
StatusCode::OK,
&HealthzResponse {
hello: "kv server".to_string(),
build_at: option_env!("KV_SERVER_BUILD_AT").unwrap_or("UNKNOWN").to_string(),
commit_version: option_env!("KV_SERVER_CURRENT_COMMIT_ID").unwrap_or("UNKNOWN").to_string(),
},
)
}
23 changes: 17 additions & 6 deletions src/controller/payload.rs
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,8 @@ use serde::{Deserialize, Serialize};

#[derive(Debug, Clone, Serialize, Deserialize)]
struct PayloadRequest {
pub persona: String,
pub persona: Option<String>,
pub avatar: Option<String>,
pub platform: String,
pub identity: String,
pub patch: serde_json::Value,
Expand All @@ -25,7 +26,13 @@ struct PayloadResponse {

pub async fn controller(req: Request) -> Result<Response, Error> {
let params: PayloadRequest = json_parse_body(&req)?;
let keypair = Secp256k1KeyPair::from_pubkey_hex(&params.persona)?;

let keypair = Secp256k1KeyPair::from_pubkey_hex(
&params
.avatar
.or(params.persona)
.ok_or_else(|| Error::ParamError("avatar not found".into()))?,
)?;
can_set_kv(&keypair.public_key, &params.platform, &params.identity).await?;
let conn = establish_connection();
let mut new_kvchain = NewKVChain::for_persona(&conn, &keypair.public_key)?;
Expand Down Expand Up @@ -54,8 +61,10 @@ mod tests {
use serde_json::json;

use crate::{
crypto::util::{compress_public_key, hex_public_key}, model::kv_chains::KVChain, schema::kv_chains::dsl::*,
util::{vec_to_base64, naive_now},
crypto::util::{compress_public_key, hex_public_key},
model::kv_chains::KVChain,
schema::kv_chains::dsl::*,
util::{naive_now, vec_to_base64},
};

use super::*;
Expand Down Expand Up @@ -89,7 +98,8 @@ mod tests {
} = Secp256k1KeyPair::generate();

let req_body = PayloadRequest {
persona: compress_public_key(&public_key),
persona: Some(compress_public_key(&public_key)),
avatar: None,
platform: "facebook".into(),
identity: Faker.fake(),
patch: json!({"test":"abc"}),
Expand Down Expand Up @@ -120,7 +130,8 @@ mod tests {
let old_kv_chain = generate_data(&conn, &public_key).unwrap();

let req_body = PayloadRequest {
persona: compress_public_key(&public_key),
persona: None,
avatar: Some(compress_public_key(&public_key)),
platform: "facebook".into(),
identity: Faker.fake(),
patch: json!({"test":"abc"}),
Expand Down
15 changes: 9 additions & 6 deletions src/controller/query.rs
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@ use super::json_response;
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct QueryResponse {
pub persona: String,
pub avatar: String,
pub proofs: Vec<QueryResponseSingleProof>,
}

Expand All @@ -26,13 +27,14 @@ pub struct QueryResponseSingleProof {

pub async fn controller(req: Request) -> Result<Response, Error> {
let params = query_parse(req);
let persona_hex = params
.get("persona")
.ok_or(Error::ParamMissing("persona".into()))?;
let avatar_hex = params
.get("avatar")
.or(params.get("persona"))
.ok_or(Error::ParamMissing("avatar".into()))?;
let Secp256k1KeyPair {
public_key,
secret_key: _,
} = Secp256k1KeyPair::from_pubkey_hex(persona_hex)?;
} = Secp256k1KeyPair::from_pubkey_hex(avatar_hex)?;

let conn = establish_connection();
let response = query_response(&conn, &public_key)?;
Expand All @@ -49,6 +51,7 @@ pub fn query_response(
let persona_hex = hex_public_key(persona_public_key);
let mut response = QueryResponse {
persona: format!("0x{}", persona_hex),
avatar: format!("0x{}", persona_hex),
proofs: vec![],
};
for proof in results.iter() {
Expand Down Expand Up @@ -86,7 +89,7 @@ mod tests {
let resp = controller(req).await.unwrap();
let body: QueryResponse = serde_json::from_str(resp.body()).unwrap();
assert_eq!(0, body.proofs.len());
assert_eq!(format!("0x{}", pubkey_hex), body.persona);
assert_eq!(format!("0x{}", pubkey_hex), body.avatar);
}

#[tokio::test]
Expand All @@ -109,7 +112,7 @@ mod tests {
let resp = controller(req).await.unwrap();
let body: QueryResponse = serde_json::from_str(resp.body()).unwrap();
assert_eq!(1, body.proofs.len());
assert_eq!(format!("0x{}", hex_public_key(&public_key)), body.persona);
assert_eq!(format!("0x{}", hex_public_key(&public_key)), body.avatar);
assert_eq!("twitter", body.proofs.first().unwrap().platform);
assert_eq!(json!({}), body.proofs.first().unwrap().content);
}
Expand Down
28 changes: 20 additions & 8 deletions src/controller/upload.rs
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,8 @@ use serde::{Deserialize, Serialize};

#[derive(Debug, Clone, Deserialize, Serialize)]
struct UploadRequest {
pub persona: String,
pub persona: Option<String>,
pub avatar: Option<String>,
pub platform: String,
pub identity: String,
pub signature: String,
Expand All @@ -24,7 +25,11 @@ struct UploadRequest {
pub async fn controller(request: Request) -> Result<Response, Error> {
let req: UploadRequest = json_parse_body(&request)?;
let sig = base64_to_vec(&req.signature)?;
let persona = Secp256k1KeyPair::from_pubkey_hex(&req.persona)?;
let persona = Secp256k1KeyPair::from_pubkey_hex(
&req.avatar
.or(req.persona)
.ok_or_else(|| Error::ParamError("avatar not found".into()))?,
)?;
let uuid = uuid::Uuid::parse_str(&req.uuid)?;
can_set_kv(&persona.public_key, &req.platform, &req.identity).await?;

Expand All @@ -36,7 +41,8 @@ pub async fn controller(request: Request) -> Result<Response, Error> {
new_kv.patch = req.patch.clone();
new_kv.uuid = uuid;
new_kv.created_at = timestamp_to_naive(req.created_at);
new_kv.signature_payload = serde_json::to_string(&new_kv.generate_signature_payload()?).unwrap();
new_kv.signature_payload =
serde_json::to_string(&new_kv.generate_signature_payload()?).unwrap();

// Validate signature
new_kv.validate()?;
Expand All @@ -58,7 +64,7 @@ mod tests {
controller::query::QueryResponse,
crypto::util::{compress_public_key, hex_public_key},
model::{establish_connection, kv},
util::{vec_to_base64, naive_now},
util::{naive_now, vec_to_base64},
};
use fake::{Fake, Faker};
use http::Method;
Expand All @@ -81,7 +87,8 @@ mod tests {
new_kv_chain.signature = new_kv_chain.sign(&keypair).unwrap();

let req_body = UploadRequest {
persona: compress_public_key(&keypair.public_key),
persona: None,
avatar: Some(compress_public_key(&keypair.public_key)),
platform: new_kv_chain.platform.clone(),
identity: new_kv_chain.identity,
signature: vec_to_base64(&new_kv_chain.signature),
Expand All @@ -99,7 +106,10 @@ mod tests {
assert_eq!(resp.status(), StatusCode::CREATED);
let resp_body: QueryResponse = serde_json::from_str(resp.body()).unwrap();
assert_eq!(1, resp_body.proofs.len());
assert_eq!(format!("0x{}", hex_public_key(&keypair.public_key)), resp_body.persona);
assert_eq!(
format!("0x{}", hex_public_key(&keypair.public_key)),
resp_body.persona
);
assert_eq!(
new_kv_chain.platform,
resp_body.proofs.first().unwrap().platform
Expand Down Expand Up @@ -137,7 +147,8 @@ mod tests {
new_kv_chain.signature = sig;

let req_body = UploadRequest {
persona: compress_public_key(&keypair.public_key),
persona: Some(compress_public_key(&keypair.public_key)),
avatar: None,
platform: new_kv_chain.platform.clone(),
identity: new_kv_chain.identity,
signature: vec_to_base64(&new_kv_chain.signature),
Expand All @@ -162,7 +173,8 @@ mod tests {
#[tokio::test]
async fn test_actual_case_1() {
let req_body = UploadRequest{
persona: "0x0289689d4846db795310b3fb6dea7ab8aba2b6734ddd3b3744a412ab174bf8cbfc".into(),
persona: Some("0x0289689d4846db795310b3fb6dea7ab8aba2b6734ddd3b3744a412ab174bf8cbfc".into()),
avatar: None,
platform: "twitter".into(),
identity: "weipingzhu2".into(),
signature: "De/UN6E7HosqZxhpG3+CRD7m8T+ozcdvKO/JCXTr/X9Hek0KP2SQFZQtZQOv/F9XgwufvHeGyD387I7QwJAxqRs=".into(),
Expand Down
23 changes: 18 additions & 5 deletions src/crypto/secp256k1.rs
Original file line number Diff line number Diff line change
Expand Up @@ -211,7 +211,14 @@ impl Secp256k1KeyPair {
mod tests {
use serde_json::json;

use crate::{crypto::util::hex_public_key, model::{kv_chains::{SignPayload, NewKVChain}, self}, util};
use crate::{
crypto::util::hex_public_key,
model::{
self,
kv_chains::{NewKVChain, SignPayload},
},
util,
};

use super::*;

Expand All @@ -226,7 +233,7 @@ mod tests {
let payload = SignPayload {
version: "1".into(),
uuid: uuid::Uuid::parse_str("fd042b27-0f21-476d-9e23-478c98ac6700")?,
persona: hex_public_key(&public_key),
avatar: hex_public_key(&public_key),
platform: "twitter".into(),
identity: "weipingzhu2".into(),
patch: json!({
Expand Down Expand Up @@ -264,7 +271,7 @@ mod tests {
let payload = SignPayload {
version: "1".into(),
uuid: uuid::Uuid::parse_str("b333f060-2cdd-4a7f-8fb1-c790c0fadc20")?,
persona: hex_public_key(&public_key),
avatar: hex_public_key(&public_key),
platform: "nextid".into(),
identity: "0x03b0a3ebb1fb9b7f3ba7653dfb8776e9db5de537e8cd6c4b9cc927cbbcdc394018".into(),
patch: json!({"com.maskbook.tip":[{"created_at":"1650188620","identity":"0x8c5494d05b4f18639834a0f1f4577d5c0a67adf0","invalid_reason":"","isDefault":0,"isPublic":1,"is_valid":true,"last_checked_at":"1650188620","platform":"ethereum"},{"created_at":"1650195158","identity":"0x2ec8ebb0a8eaa40e4ce620cf9f84a96df68d4669","invalid_reason":"","isDefault":1,"isPublic":1,"is_valid":true,"last_checked_at":"1650195158","platform":"ethereum"}]}),
Expand All @@ -273,7 +280,10 @@ mod tests {
};
let expected_payload = r#"{"version":"1","uuid":"b333f060-2cdd-4a7f-8fb1-c790c0fadc20","persona":"04b0a3ebb1fb9b7f3ba7653dfb8776e9db5de537e8cd6c4b9cc927cbbcdc394018b99ab0ebafec620820056af9fe162dda5c536b408aedacbd2cdd79db7f56ef91","platform":"nextid","identity":"0x03b0a3ebb1fb9b7f3ba7653dfb8776e9db5de537e8cd6c4b9cc927cbbcdc394018","patch":{"com.maskbook.tip":[{"created_at":"1650188620","identity":"0x8c5494d05b4f18639834a0f1f4577d5c0a67adf0","invalid_reason":"","isDefault":0,"isPublic":1,"is_valid":true,"last_checked_at":"1650188620","platform":"ethereum"},{"created_at":"1650195158","identity":"0x2ec8ebb0a8eaa40e4ce620cf9f84a96df68d4669","invalid_reason":"","isDefault":1,"isPublic":1,"is_valid":true,"last_checked_at":"1650195158","platform":"ethereum"}]},"created_at":1650209531,"previous":null}"#;

assert_eq!(serde_json::to_string(&payload)?, expected_payload.to_string());
assert_eq!(
serde_json::to_string(&payload)?,
expected_payload.to_string()
);
let signature = util::base64_to_vec(&"CNn87foZQt8AY+yRA/ys2/99zlD6gEnph3ujaIdQXxlKdHB41Ev+/rS/fzIULuWrljGreVbR/hRHL7RB51jIfRs=".into())?;
let pubkey_recovered =
Secp256k1KeyPair::recover_from_personal_signature(&signature, &expected_payload)?;
Expand All @@ -288,7 +298,10 @@ mod tests {
new_kv.uuid = payload.uuid;
new_kv.created_at = util::timestamp_to_naive(payload.created_at);

assert_eq!(expected_payload, serde_json::to_string(&new_kv.generate_signature_payload()?)?);
assert_eq!(
expected_payload,
serde_json::to_string(&new_kv.generate_signature_payload()?)?
);

Ok(())
}
Expand Down
Loading

0 comments on commit d5aa762

Please sign in to comment.