add matrix api implementation
- login - get rooms - logout
This commit is contained in:
1 parent
9a8005d8fe
commit
668ff01ef9
6 files changed
+453
-2
No files matched your search
+2
-1
@@ -5,4 +5,5 @@ add_subdirectory(mbedtls)
|
||||
|
||||
add_subdirectory(httpbin)
|
||||
add_subdirectory(wikipedia)
|
||||
add_subdirectory(iconfinder)
|
||||
add_subdirectory(iconfinder)
|
||||
add_subdirectory(matrix)
|
||||
@@ -16,11 +16,15 @@ Public APIs:
|
||||
2. **Build:**
|
||||
```bash
|
||||
cd Mbed-TLS-Integration-Examples
|
||||
|
||||
# please refer the doc to build MbedTLS library
|
||||
|
||||
# build programs
|
||||
mkdir build && cd build
|
||||
cmake ..
|
||||
make
|
||||
|
||||
# or just run the script
|
||||
# or just run the script to build programs
|
||||
./build.sh
|
||||
```
|
||||
3. **Run:**
|
||||
|
||||
@@ -0,0 +1,11 @@
|
||||
add_executable(matrix_c main.c matrix.c)
|
||||
|
||||
target_link_libraries(matrix_c
|
||||
PRIVATE
|
||||
mbedtls
|
||||
)
|
||||
|
||||
target_include_directories(matrix_c
|
||||
PRIVATE
|
||||
${MBEDTLS_SOURCE_DIR}/include
|
||||
)
|
||||
@@ -0,0 +1,62 @@
|
||||
#include "matrix.h"
|
||||
#include "mbedtls/platform.h"
|
||||
|
||||
int main(int argc, char **argv)
|
||||
{
|
||||
if (argc < 3) {
|
||||
mbedtls_printf("Usage: %s <username> <password>\n", argv[0]);
|
||||
mbedtls_printf("Example: %s @user:matrix.org password123\n", argv[0]);
|
||||
return 1;
|
||||
}
|
||||
|
||||
const char *username = argv[1];
|
||||
const char *password = argv[2];
|
||||
char access_token[512];
|
||||
|
||||
matrix_connection_t conn;
|
||||
|
||||
// initialize PSA Crypto
|
||||
psa_status_t psa_status = psa_crypto_init();
|
||||
if (psa_status != PSA_SUCCESS) {
|
||||
mbedtls_printf(" ! failed (%d)\n", (int)psa_status);
|
||||
return -1;
|
||||
}
|
||||
|
||||
// connect
|
||||
if (matrix_connect(&conn) != 0) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
// login
|
||||
if (matrix_login(&conn, username, password, access_token, sizeof(access_token)) != 0) {
|
||||
matrix_logout(&conn, access_token);
|
||||
return -1;
|
||||
}
|
||||
|
||||
// disconnect & then reconnect. I'm doing this cause after each request
|
||||
// i'm closing the connection. for actual use we should use keep-alive
|
||||
matrix_disconnect(&conn);
|
||||
if (matrix_connect(&conn) != 0) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
// get rooms
|
||||
if (matrix_get_rooms(&conn, access_token) != 0) {
|
||||
matrix_logout(&conn, access_token);
|
||||
return -1;
|
||||
}
|
||||
|
||||
// reconnect again
|
||||
matrix_disconnect(&conn);
|
||||
if (matrix_connect(&conn) != 0) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
// finally logout & close the connection
|
||||
if (matrix_logout(&conn, access_token) != 0) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
+341
@@ -0,0 +1,341 @@
|
||||
#include "matrix.h"
|
||||
#include "mbedtls/platform.h"
|
||||
#include "mbedtls/build_info.h"
|
||||
#include "mbedtls/debug.h"
|
||||
#include "mbedtls/error.h"
|
||||
|
||||
#include <string.h>
|
||||
#include <stdio.h>
|
||||
#include <unistd.h>
|
||||
|
||||
#define SERVER_PORT "443"
|
||||
#define SERVER_NAME "matrix.org"
|
||||
#define DEBUG_LEVEL 0
|
||||
#define CA_CERT_PATH "/etc/ssl/certs/ca-certificates.crt"
|
||||
#define BUFFER_SIZE 8192
|
||||
|
||||
static void my_debug(void *ctx, int level,
|
||||
const char *file, int line, const char *str)
|
||||
{
|
||||
((void) level);
|
||||
mbedtls_fprintf((FILE *) ctx, "%s:%04d: %s", file, line, str); // smth's up
|
||||
fflush((FILE *) ctx);
|
||||
}
|
||||
|
||||
// connect to matrix server (TLS handshake)
|
||||
int matrix_connect(matrix_connection_t *conn)
|
||||
{
|
||||
int ret;
|
||||
|
||||
mbedtls_net_init(&conn->server_fd);
|
||||
mbedtls_ssl_init(&conn->ssl);
|
||||
mbedtls_ssl_config_init(&conn->conf);
|
||||
mbedtls_x509_crt_init(&conn->cacert);
|
||||
|
||||
mbedtls_printf(" - Connecting to %s:%s...", SERVER_NAME, SERVER_PORT);
|
||||
fflush(stdout);
|
||||
|
||||
if ((ret = mbedtls_net_connect(&conn->server_fd, SERVER_NAME,
|
||||
SERVER_PORT, MBEDTLS_NET_PROTO_TCP)) != 0) {
|
||||
mbedtls_printf(" ! Connection error: -0x%x\n", -ret);
|
||||
return -1;
|
||||
}
|
||||
|
||||
if ((ret = mbedtls_net_set_block(&conn->server_fd)) != 0) {
|
||||
mbedtls_printf(" ! failed\n");
|
||||
return -1;
|
||||
}
|
||||
|
||||
if ((ret = mbedtls_ssl_config_defaults(&conn->conf,
|
||||
MBEDTLS_SSL_IS_CLIENT,
|
||||
MBEDTLS_SSL_TRANSPORT_STREAM,
|
||||
MBEDTLS_SSL_PRESET_DEFAULT)) != 0) {
|
||||
mbedtls_printf(" ! failed\n");
|
||||
return -1;
|
||||
}
|
||||
|
||||
// Load CA certificates
|
||||
mbedtls_x509_crt_parse_file(&conn->cacert, CA_CERT_PATH);
|
||||
mbedtls_ssl_conf_ca_chain(&conn->conf, &conn->cacert, NULL);
|
||||
mbedtls_ssl_conf_authmode(&conn->conf, MBEDTLS_SSL_VERIFY_OPTIONAL);
|
||||
|
||||
mbedtls_debug_set_threshold(DEBUG_LEVEL);
|
||||
mbedtls_ssl_conf_dbg(&conn->conf, my_debug, stdout);
|
||||
|
||||
if ((ret = mbedtls_ssl_setup(&conn->ssl, &conn->conf)) != 0) {
|
||||
mbedtls_printf(" ! failed\n");
|
||||
return -1;
|
||||
}
|
||||
|
||||
if ((ret = mbedtls_ssl_set_hostname(&conn->ssl, SERVER_NAME)) != 0) {
|
||||
mbedtls_printf(" ! failed\n");
|
||||
return -1;
|
||||
}
|
||||
|
||||
mbedtls_ssl_set_bio(&conn->ssl, &conn->server_fd, mbedtls_net_send, mbedtls_net_recv, NULL);
|
||||
|
||||
while ((ret = mbedtls_ssl_handshake(&conn->ssl)) != 0) {
|
||||
if (ret != MBEDTLS_ERR_SSL_WANT_READ && ret != MBEDTLS_ERR_SSL_WANT_WRITE) {
|
||||
mbedtls_printf(" ! Handshake error: -0x%x\n", -ret);
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
|
||||
mbedtls_printf(" ok\n");
|
||||
return 0;
|
||||
}
|
||||
|
||||
// HTTP request/response
|
||||
int matrix_send_request(matrix_connection_t *conn,
|
||||
const char *req, char *res, size_t res_len)
|
||||
{
|
||||
ssize_t bytes_read;
|
||||
unsigned char buf[BUFFER_SIZE];
|
||||
int retry_count = 0;
|
||||
int retry_delay = 100; // ms
|
||||
size_t res_size = 0;
|
||||
|
||||
// send request
|
||||
size_t req_len = strlen(req);
|
||||
if (mbedtls_ssl_write(&conn->ssl, (const unsigned char*)req, req_len) < 0) {
|
||||
mbedtls_printf(" ! Failed to send request\n");
|
||||
return -1;
|
||||
}
|
||||
|
||||
memset(res, 0, res_len); // clear the buffer
|
||||
|
||||
// read response
|
||||
while (1) {
|
||||
bytes_read = mbedtls_ssl_read(&conn->ssl, buf, sizeof(buf) - 1);
|
||||
|
||||
if (bytes_read > 0) {
|
||||
if (res_size + bytes_read < res_len) {
|
||||
memcpy(res + res_size, buf, bytes_read);
|
||||
res_size += bytes_read;
|
||||
}
|
||||
retry_count = 0;
|
||||
retry_delay = 100;
|
||||
|
||||
} else if (bytes_read == 0) {
|
||||
break; // connection closed
|
||||
|
||||
} else if (bytes_read == MBEDTLS_ERR_SSL_RECEIVED_NEW_SESSION_TICKET) {
|
||||
usleep(100000);
|
||||
continue;
|
||||
|
||||
} else if (bytes_read == MBEDTLS_ERR_SSL_WANT_READ || bytes_read == MBEDTLS_ERR_SSL_WANT_WRITE) {
|
||||
if (retry_count < 100) {
|
||||
usleep(retry_delay * 1000);
|
||||
retry_count++;
|
||||
if (retry_delay < 5000)
|
||||
retry_delay *= 2;
|
||||
continue;
|
||||
} else {
|
||||
break;
|
||||
}
|
||||
} else {
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
// extract the token
|
||||
int matrix_extract_access_token(const char *res, char *token, size_t token_len)
|
||||
{
|
||||
const char *start = strstr(res, "\"access_token\":");
|
||||
if (!start) {
|
||||
mbedtls_printf(" no access_token found in response\n");
|
||||
return -1;
|
||||
}
|
||||
|
||||
start = strchr(start, ':');
|
||||
if (!start) return -1;
|
||||
|
||||
start = strchr(start, '"');
|
||||
if (!start) return -1;
|
||||
start++;
|
||||
|
||||
const char *end = strchr(start, '"');
|
||||
if (!end) return -1;
|
||||
|
||||
size_t len = end - start;
|
||||
if (len >= token_len) {
|
||||
mbedtls_printf(" token too long\n");
|
||||
return -1;
|
||||
}
|
||||
|
||||
strncpy(token, start, len);
|
||||
token[len] = '\0';
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
// login to matrix and get access token
|
||||
int matrix_login(matrix_connection_t *conn, const char *username,
|
||||
const char *password, char *access_token, size_t token_len)
|
||||
{
|
||||
char login_request[2048];
|
||||
char response[4096];
|
||||
|
||||
size_t json_len = snprintf(NULL, 0, "{\"type\":\"m.login.password\",\"user\":\"%s\",\"password\":\"%s\"}",
|
||||
username, password);
|
||||
snprintf(login_request, sizeof(login_request),
|
||||
"POST /_matrix/client/v3/login HTTP/1.1\r\n"
|
||||
"Host: matrix.org\r\n"
|
||||
"Content-Type: application/json\r\n"
|
||||
"Content-Length: %zu\r\n"
|
||||
"Connection: close\r\n\r\n"
|
||||
"{\"type\":\"m.login.password\",\"user\":\"%s\",\"password\":\"%s\"}",
|
||||
json_len, username, password);
|
||||
|
||||
mbedtls_printf(" - Logging in as: %s ...", username);
|
||||
|
||||
if (matrix_send_request(conn, login_request, response, sizeof(response)) != 0) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
// extract the token
|
||||
if (matrix_extract_access_token(response, access_token, token_len) != 0) {
|
||||
mbedtls_printf(" ! Login failed\n");
|
||||
return -1;
|
||||
}
|
||||
|
||||
mbedtls_printf(" ok (got the token)\n");
|
||||
return 0;
|
||||
}
|
||||
|
||||
// get all rooms the user has joined
|
||||
int matrix_get_rooms(matrix_connection_t *conn, const char *access_token)
|
||||
{
|
||||
char get_rooms_request[512];
|
||||
char response[16384];
|
||||
const char *json_start;
|
||||
|
||||
snprintf(get_rooms_request, sizeof(get_rooms_request),
|
||||
"GET /_matrix/client/v3/joined_rooms HTTP/1.1\r\n"
|
||||
"Host: matrix.org\r\n"
|
||||
"Authorization: Bearer %s\r\n"
|
||||
"Connection: close\r\n\r\n",
|
||||
access_token);
|
||||
|
||||
mbedtls_printf(" - Fetching room list... ");
|
||||
|
||||
if (matrix_send_request(conn, get_rooms_request, response, sizeof(response)) != 0) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
// skip headers and strt with JSON body
|
||||
json_start = strstr(response, "\r\n\r\n");
|
||||
if (!json_start) {
|
||||
json_start = strstr(response, "\n\n");
|
||||
if (!json_start) {
|
||||
mbedtls_printf(" ! Invalid response format\n");
|
||||
return -1;
|
||||
}
|
||||
json_start += 2;
|
||||
} else {
|
||||
json_start += 4;
|
||||
}
|
||||
|
||||
// parse joined_rooms list
|
||||
const char *room_list = strstr(json_start, "\"joined_rooms\":");
|
||||
if (room_list) {
|
||||
const char *start = strchr(room_list, '[');
|
||||
const char *end = strchr(start, ']');
|
||||
|
||||
if (start && end) {
|
||||
mbedtls_printf(" ok\n");
|
||||
mbedtls_printf(" \nAll rooms:\n\n");
|
||||
|
||||
const char *pos = start + 1;
|
||||
int room_count = 0;
|
||||
|
||||
while (pos < end) {
|
||||
const char *room_start = strchr(pos, '"');
|
||||
if (!room_start || room_start >= end) break;
|
||||
room_start++;
|
||||
|
||||
const char *room_end = strchr(room_start, '"');
|
||||
if (!room_end || room_end >= end) break;
|
||||
|
||||
room_count++;
|
||||
mbedtls_printf(" %d. ", room_count);
|
||||
for (const char *p = room_start; p < room_end; p++) {
|
||||
mbedtls_printf("%c", *p);
|
||||
}
|
||||
mbedtls_printf("\n");
|
||||
|
||||
pos = room_end + 1;
|
||||
}
|
||||
|
||||
if (room_count == 0) {
|
||||
mbedtls_printf(" (No rooms joined)\n");
|
||||
} else {
|
||||
mbedtls_printf("\n Total: %d rooms\n", room_count);
|
||||
}
|
||||
}
|
||||
} else {
|
||||
mbedtls_printf(" ! Failed to parse room list\n");
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
// logout & close the connection
|
||||
int matrix_logout(matrix_connection_t *conn, const char *access_token)
|
||||
{
|
||||
char logout_request[512];
|
||||
char response[1024];
|
||||
|
||||
snprintf(logout_request, sizeof(logout_request),
|
||||
"POST /_matrix/client/v3/logout HTTP/1.1\r\n"
|
||||
"Host: matrix.org\r\n"
|
||||
"Authorization: Bearer %s\r\n"
|
||||
"Connection: close\r\n\r\n",
|
||||
access_token);
|
||||
|
||||
mbedtls_printf(" - Logging out...");
|
||||
fflush(stdout);
|
||||
|
||||
if (matrix_send_request(conn, logout_request, response, sizeof(response)) != 0) {
|
||||
mbedtls_printf(" ! Logout request failed\n");
|
||||
return -1;
|
||||
}
|
||||
|
||||
size_t resp_len = strlen(response);
|
||||
|
||||
// check response status
|
||||
if (strstr(response, "HTTP/1.1 200") || strstr(response, "200 OK")) {
|
||||
mbedtls_printf(" ok (access token invalidated on server)\n");
|
||||
} else if (strstr(response, "HTTP/1.1 401")) {
|
||||
mbedtls_printf(" (unauthorized)\n");
|
||||
mbedtls_printf(" ! Invalid or expired token\n");
|
||||
} else if (resp_len > 0) {
|
||||
mbedtls_printf(" (unexpected response)\n");
|
||||
} else {
|
||||
mbedtls_printf(" (no response)\n");
|
||||
}
|
||||
|
||||
mbedtls_printf(" - Closing TLS connection...");
|
||||
fflush(stdout);
|
||||
mbedtls_ssl_close_notify(&conn->ssl);
|
||||
mbedtls_net_free(&conn->server_fd);
|
||||
mbedtls_ssl_free(&conn->ssl);
|
||||
mbedtls_ssl_config_free(&conn->conf);
|
||||
mbedtls_x509_crt_free(&conn->cacert);
|
||||
mbedtls_printf(" ok\n");
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
// and finally do the orderly cleanup
|
||||
void matrix_disconnect(matrix_connection_t *conn)
|
||||
{
|
||||
mbedtls_ssl_close_notify(&conn->ssl);
|
||||
mbedtls_net_free(&conn->server_fd);
|
||||
mbedtls_ssl_free(&conn->ssl);
|
||||
mbedtls_ssl_config_free(&conn->conf);
|
||||
mbedtls_x509_crt_free(&conn->cacert);
|
||||
}
|
||||
@@ -0,0 +1,32 @@
|
||||
#ifndef MATRIX_H
|
||||
#define MATRIX_H
|
||||
|
||||
#include "mbedtls/net_sockets.h"
|
||||
#include "mbedtls/ssl.h"
|
||||
#include "mbedtls/x509_crt.h"
|
||||
|
||||
typedef struct {
|
||||
mbedtls_net_context server_fd;
|
||||
mbedtls_ssl_context ssl;
|
||||
mbedtls_ssl_config conf;
|
||||
mbedtls_x509_crt cacert;
|
||||
} matrix_connection_t;
|
||||
|
||||
int matrix_connect(matrix_connection_t *conn);
|
||||
int matrix_logout(matrix_connection_t *conn, const char *access_token);
|
||||
void matrix_disconnect(matrix_connection_t *conn);
|
||||
|
||||
// HTTP request/response thing
|
||||
int matrix_send_request(matrix_connection_t *conn,
|
||||
const char *req, char *res, size_t res_len);
|
||||
|
||||
int matrix_login(matrix_connection_t *conn, const char *username,
|
||||
const char *password, char *access_token, size_t token_len);
|
||||
|
||||
int matrix_get_rooms(matrix_connection_t *conn, const char *access_token);
|
||||
|
||||
// extract access token from JSON response (very basic, not a full JSON parser)
|
||||
// we can use a real JSON parser but for demo purposes imma keep it simple
|
||||
int matrix_extract_access_token(const char *res, char *token, size_t token_len);
|
||||
|
||||
#endif
|
||||
Reference in new issue
Block a user