add matrix api implementation

- login
- get rooms
- logout
This commit is contained in:
DIlkhush00 committed 2026-03-18 06:10:47 +05:30
1 parent 9a8005d8fe
commit 668ff01ef9
6 files changed
+453 -2

No files matched your search

+2 -1
View File
@@ -5,4 +5,5 @@ add_subdirectory(mbedtls)
add_subdirectory(httpbin) add_subdirectory(httpbin)
add_subdirectory(wikipedia) add_subdirectory(wikipedia)
add_subdirectory(iconfinder) add_subdirectory(iconfinder)
add_subdirectory(matrix)
+5 -1
View File
@@ -16,11 +16,15 @@ Public APIs:
2. **Build:** 2. **Build:**
```bash ```bash
cd Mbed-TLS-Integration-Examples cd Mbed-TLS-Integration-Examples
# please refer the doc to build MbedTLS library
# build programs
mkdir build && cd build mkdir build && cd build
cmake .. cmake ..
make make
# or just run the script # or just run the script to build programs
./build.sh ./build.sh
``` ```
3. **Run:** 3. **Run:**
+11
View File
@@ -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
)
+62
View File
@@ -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
View File
@@ -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);
}
+32
View File
@@ -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