Skip to content

Commit

Permalink
Merge pull request #103 from smswithoutborders/feature/grpc_api
Browse files Browse the repository at this point in the history
feat(api): add StoreEntityToken gRPC function
  • Loading branch information
PromiseFru authored Jun 13, 2024
2 parents 05017d8 + 38fe343 commit 91a3f30
Show file tree
Hide file tree
Showing 12 changed files with 501 additions and 58 deletions.
6 changes: 6 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -142,3 +142,9 @@ dmypy.json
*.sqlite
*.sqlite3
*.db

# Ignore all .proto files
*.proto

# Except for vault.proto
!vault.proto
9 changes: 9 additions & 0 deletions Makefile
Original file line number Diff line number Diff line change
@@ -1,4 +1,7 @@
python=python3
PROTO_URL=https://raw.githubusercontent.com/smswithoutborders/SMSWithoutBorders-Publisher/feature/grpc-api/protos/v1/publisher.proto
PROTO_DIR=protos/v1
PROTO_FILE=$(PROTO_DIR)/publisher.proto

define log_message
@echo "[$(shell date +'%Y-%m-%d %H:%M:%S')] - $1"
Expand Down Expand Up @@ -61,3 +64,9 @@ grpc-compile:
--grpc_python_out=. \
./protos/v1/*.proto
$(call log_message,INFO - gRPC Compilation complete!)

download-publisher-proto:
$(call log_message,INFO - Downloading publisher.proto ...)
@mkdir -p $(PROTO_DIR)
@curl -o $(PROTO_FILE) -L $(PROTO_URL)
$(call log_message,INFO - Publisher.proto downloaded successfully!)
117 changes: 117 additions & 0 deletions docs/grpc.md
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@
- [Initiate Authentication](#initiate-authentication)
- [Complete Authentication](#complete-authentication)
- [List an Entity's Stored Tokens](#list-an-entitys-stored-tokens)
- [Store an Entity's Token](#store-an-entitys-token)

## Download Protocol Buffer File

Expand Down Expand Up @@ -509,3 +510,119 @@ localhost:6000 vault.v1.Entity/ListEntityStoredTokens
"message": "Tokens retrieved successfully."
}
```

### Store an Entity's Token

This step involves storing tokens securely for the authenticated entity.

---

> [!NOTE]
>
> Ensure you have generated your authorization URL before using this function.
> For Gmail and Twitter offline access, use the following recommended
> parameters:
>
> **Gmail:**
>
> - **scope:** >
> `openid https://www.googleapis.com/auth/gmail.send https://www.googleapis.com/auth/userinfo.profile https://www.googleapis.com/auth/userinfo.email`
> - **access_type:** `offline`
> - **prompt:** `consent`
>
> **Twitter:**
>
> - **scope:** `tweet.read tweet.write users.read offline.access`
> - **prompt:** `consent`
>
> You can use the publisher's [Get Authorization URL](#) function to help
> generate the URL for you, or use other tools that can construct the URL.
---

> `request` **StoreEntityTokenRequest**
> [!IMPORTANT]
>
> The table lists only the required fields for this step. Other fields will be
> ignored.
| Field | Type | Description |
| ------------------ | ------ | ------------------------------------------------------------------- |
| long_lived_token | string | The long-lived token for the authenticated session. |
| authorization_code | string | The authorization code obtained from the OAuth2 flow. |
| platform | string | The platform from which the token is being issued. (e.g., "gmail"). |
| protocol | string | The protocol used for authentication (e.g., "oauth2"). |

Optional fields:

| Field | Type | Description |
| ------------- | ------ | ---------------------------------------------------- |
| code_verifier | string | A cryptographic random string used in the PKCE flow. |

---

> `response` **StoreEntityTokenResponse**
> [!IMPORTANT]
>
> The table lists only the fields that are populated for this step. Other fields
> may be empty, omitted, or false.
| Field | Type | Description |
| ------- | ------- | ------------------------------------------ |
| message | string | A response message from the server. |
| success | boolean | Indicates if the operation was successful. |

---

> `method` **StoreEntityToken**
> [!TIP]
>
> The examples below use
> [grpcurl](https://github.com/fullstorydev/grpcurl#grpcurl).
> [!NOTE]
>
> Here is what a successful response from the server looks like.
>
> The server would return a status code of `0 OK` if the API transaction goes
> through without any friction. Otherwise, it will return any other code out of
> the
> [17 codes supported by gRPC](https://grpc.github.io/grpc/core/md_doc_statuscodes.html).
---

**Sample request**

```bash
grpcurl -plaintext \
-d @ \
-proto protos/v1/vault.proto \
localhost:6000 vault.v1.Entity/StoreEntityToken <payload.json
```

---

**Sample payload.json**

```json
{
"long_lived_token": "long_lived_token",
"authorization_code": "oauth2_code",
"platform": "gmail",
"protocol": "oauth2"
}
```

---

**Sample response**

```json
{
"message": "Token stored successfully.",
"success": true
}
```
10 changes: 7 additions & 3 deletions grpc_server.py
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,10 @@
from src.utils import get_configs
from src.grpc_entity_service import EntityService

logger = logging.getLogger("[GRPC SERVER]")
logging.basicConfig(
level=logging.INFO, format=("%(asctime)s - %(name)s - %(levelname)s - %(message)s")
)
logger = logging.getLogger("[Vault gRPC Server]")


def serve():
Expand Down Expand Up @@ -74,7 +77,9 @@ def serve():
raise
else:
server.add_insecure_port(f"{hostname}:{port}")
logger.info("The server is running in insecure mode at %s:%s", hostname, port)
logger.warning(
"The server is running in insecure mode at %s:%s", hostname, port
)

server.start()

Expand All @@ -87,5 +92,4 @@ def serve():


if __name__ == "__main__":
logging.basicConfig(level=logging.INFO)
serve()
24 changes: 24 additions & 0 deletions protos/v1/vault.proto
Original file line number Diff line number Diff line change
Expand Up @@ -86,6 +86,28 @@ message Token {
string account_identifier = 2;
}

// Request message for storing an entity's token.
message StoreEntityTokenRequest {
// The long-lived token of the authenticated entity.
string long_lived_token = 1;
// The authorization code for the token.
string authorization_code = 2;
// The code verifier for the token.
string code_verifier = 3;
// The platform associated with the token.
string platform = 4;
// The protocol used for the request.
string protocol = 5;
}

// Response message for storing an entity's token.
message StoreEntityTokenResponse {
// A response message.
string message = 1;
// Indicates whether the operation was successful.
bool success = 2;
}

// Service for managing entities.
service Entity {
// Creates an entity.
Expand All @@ -94,4 +116,6 @@ service Entity {
rpc AuthenticateEntity (AuthenticateEntityRequest) returns (AuthenticateEntityResponse);
// Lists stored tokens for an entity.
rpc ListEntityStoredTokens (ListEntityStoredTokenRequest) returns (ListEntityStoredTokenResponse);
// Stores a token for an entity.
rpc StoreEntityToken (StoreEntityTokenRequest) returns (StoreEntityTokenResponse);
}
3 changes: 3 additions & 0 deletions src/db.py
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,9 @@
from src.utils import ensure_database_exists, get_configs
from settings import Configurations

logging.basicConfig(
level=logging.INFO, format=("%(asctime)s - %(name)s - %(levelname)s - %(message)s")
)
logger = logging.getLogger(__name__)

DATABASE_CONFIGS = {
Expand Down
Loading

0 comments on commit 91a3f30

Please sign in to comment.