Add better instructions for Visual Studio Windows compilation.

This commit adds better instructions for Visual Studio users, because
Windows programming is hell on earth.
It also adds some precompiled statically linked AMD64 binaries for
libolm for convenience.
This commit is contained in:
Jacob 2023-12-13 22:32:21 +01:00
parent c56c0d3cd1
commit 7a2af16beb
82 changed files with 14211 additions and 12373 deletions

16
.gitignore vendored
View file

@ -1,8 +1,8 @@
examples/test.cpp
test
build
docs/html
docs/latex
docs/man
subprojects/*-*
subprojects/packagecache
examples/test.cpp
test
build
docs/html
docs/latex
docs/man
subprojects/*-*
subprojects/packagecache

3
.vs/ProjectSettings.json Normal file
View file

@ -0,0 +1,3 @@
{
"CurrentProjectSetting": "No Configurations"
}

14
.vs/VSWorkspaceState.json Normal file
View file

@ -0,0 +1,14 @@
{
"DevContainersInfoBarHidden": true,
"ActiveTargetSystem": "Local Machine",
"ExpandedNodes": [
"",
"\\packages",
"\\src",
"\\windows-olm",
"\\windows-olm\\include",
"\\windows-olm\\include\\olm"
],
"SelectedNode": "\\packages.config",
"PreviewInSolutionExplorer": false
}

View file

@ -1,19 +1,19 @@
{
"configurations": [
{
"name": "windows-gcc-x64",
"includePath": [
"${workspaceFolder}/src/**",
"${workspaceFolder}/include/**"
],
"compilerPath": "gcc",
"cStandard": "${default}",
"cppStandard": "${default}",
"intelliSenseMode": "windows-gcc-x64",
"compilerArgs": [
""
]
}
],
"version": 4
{
"configurations": [
{
"name": "windows-gcc-x64",
"includePath": [
"${workspaceFolder}/src/**",
"${workspaceFolder}/include/**"
],
"compilerPath": "gcc",
"cStandard": "${default}",
"cppStandard": "${default}",
"intelliSenseMode": "windows-gcc-x64",
"compilerArgs": [
""
]
}
],
"version": 4
}

48
.vscode/launch.json vendored
View file

@ -1,24 +1,24 @@
{
"version": "0.2.0",
"configurations": [
{
"name": "C/C++ Runner: Debug Session",
"type": "cppdbg",
"request": "launch",
"args": [],
"stopAtEntry": false,
"externalConsole": true,
"cwd": "%userprofile%/libleet/include",
"program": "%userprofile%/libleet/include/build/Debug/outDebug",
"MIMode": "gdb",
"miDebuggerPath": "gdb",
"setupCommands": [
{
"description": "Enable pretty-printing for gdb",
"text": "-enable-pretty-printing",
"ignoreFailures": true
}
]
}
]
}
{
"version": "0.2.0",
"configurations": [
{
"name": "C/C++ Runner: Debug Session",
"type": "cppdbg",
"request": "launch",
"args": [],
"stopAtEntry": false,
"externalConsole": true,
"cwd": "%userprofile%/libleet/include",
"program": "%userprofile%/libleet/include/build/Debug/outDebug",
"MIMode": "gdb",
"miDebuggerPath": "gdb",
"setupCommands": [
{
"description": "Enable pretty-printing for gdb",
"text": "-enable-pretty-printing",
"ignoreFailures": true
}
]
}
]
}

116
.vscode/settings.json vendored
View file

@ -1,59 +1,59 @@
{
"C_Cpp_Runner.cCompilerPath": "gcc",
"C_Cpp_Runner.cppCompilerPath": "g++",
"C_Cpp_Runner.debuggerPath": "gdb",
"C_Cpp_Runner.cStandard": "",
"C_Cpp_Runner.cppStandard": "",
"C_Cpp_Runner.msvcBatchPath": "C:/Program Files/Microsoft Visual Studio/2022/Community/VC/Auxiliary/Build/vcvarsall.bat",
"C_Cpp_Runner.useMsvc": false,
"C_Cpp_Runner.warnings": [
"-Wall",
"-Wextra",
"-Wpedantic",
"-Wshadow",
"-Wformat=2",
"-Wcast-align",
"-Wconversion",
"-Wsign-conversion",
"-Wnull-dereference"
],
"C_Cpp_Runner.msvcWarnings": [
"/W4",
"/permissive-",
"/w14242",
"/w14287",
"/w14296",
"/w14311",
"/w14826",
"/w44062",
"/w44242",
"/w14905",
"/w14906",
"/w14263",
"/w44265",
"/w14928"
],
"C_Cpp_Runner.enableWarnings": true,
"C_Cpp_Runner.warningsAsError": false,
"C_Cpp_Runner.compilerArgs": [],
"C_Cpp_Runner.linkerArgs": [],
"C_Cpp_Runner.includePaths": [],
"C_Cpp_Runner.includeSearch": [
"*",
"**/*"
],
"C_Cpp_Runner.excludeSearch": [
"**/build",
"**/build/**",
"**/.*",
"**/.*/**",
"**/.vscode",
"**/.vscode/**"
],
"C_Cpp_Runner.useAddressSanitizer": false,
"C_Cpp_Runner.useUndefinedSanitizer": false,
"C_Cpp_Runner.useLeakSanitizer": false,
"C_Cpp_Runner.showCompilationTime": false,
"C_Cpp_Runner.useLinkTimeOptimization": false,
"C_Cpp_Runner.msvcSecureNoWarnings": false
{
"C_Cpp_Runner.cCompilerPath": "gcc",
"C_Cpp_Runner.cppCompilerPath": "g++",
"C_Cpp_Runner.debuggerPath": "gdb",
"C_Cpp_Runner.cStandard": "",
"C_Cpp_Runner.cppStandard": "",
"C_Cpp_Runner.msvcBatchPath": "C:/Program Files/Microsoft Visual Studio/2022/Community/VC/Auxiliary/Build/vcvarsall.bat",
"C_Cpp_Runner.useMsvc": false,
"C_Cpp_Runner.warnings": [
"-Wall",
"-Wextra",
"-Wpedantic",
"-Wshadow",
"-Wformat=2",
"-Wcast-align",
"-Wconversion",
"-Wsign-conversion",
"-Wnull-dereference"
],
"C_Cpp_Runner.msvcWarnings": [
"/W4",
"/permissive-",
"/w14242",
"/w14287",
"/w14296",
"/w14311",
"/w14826",
"/w44062",
"/w44242",
"/w14905",
"/w14906",
"/w14263",
"/w44265",
"/w14928"
],
"C_Cpp_Runner.enableWarnings": true,
"C_Cpp_Runner.warningsAsError": false,
"C_Cpp_Runner.compilerArgs": [],
"C_Cpp_Runner.linkerArgs": [],
"C_Cpp_Runner.includePaths": [],
"C_Cpp_Runner.includeSearch": [
"*",
"**/*"
],
"C_Cpp_Runner.excludeSearch": [
"**/build",
"**/build/**",
"**/.*",
"**/.*/**",
"**/.vscode",
"**/.vscode/**"
],
"C_Cpp_Runner.useAddressSanitizer": false,
"C_Cpp_Runner.useUndefinedSanitizer": false,
"C_Cpp_Runner.useLeakSanitizer": false,
"C_Cpp_Runner.showCompilationTime": false,
"C_Cpp_Runner.useLinkTimeOptimization": false,
"C_Cpp_Runner.msvcSecureNoWarnings": false
}

1322
LICENSE

File diff suppressed because it is too large Load diff

291
README.md
View file

@ -1,133 +1,158 @@
# libleet
C++ Matrix client library which aims to support most features in the Matrix
specification, as well as Element features for a great user experience.
**This library is very much work in progress.**
Expect things to change, and as such it is not suitable for use
yet. If you wish to help implement some of the many Matrix
features, feel free to do so in the form of a pull request.
libleet is the library that powers the backend for the
work-in-progress Matrix client [stellar](https://git.speedie.site/speedie/stellar).
## Currently supports
- Connecting to a Matrix instance
- Logging in
- Message (including attachment) downloading
- Message sending
- Room creation
- Room upgrades
- Room listing (including those inside spaces)
- Space listing
- User listing
- Aliases
- Attachment uploading and downloading
- Discovery
- Refresh tokens
- Read marker
- User presence
- End to end encryption
- Can send encrypted text messages.
- Currently **cannot** send encrypted attachments, read encrypted messages,
verify interactively or use key backups.
- Reporting content
- VOIP
- Can retrieve TURN server credentials. Not much thought has been put into
VOIP support, because I am not a big fan of how it is implemented in Matrix.
- And more trivial features that I don't think are worth listing here.
## Not yet supported
- Managing rooms/spaces
- Creating spaces
- Storing custom data
- Device management
- Threads
- Third-party/Phone number/SSO authentication
- Various end-to-end encryption features
- Push notification endpoints
## Dependencies
- boost
- nlohmann\_json
- C++20 [compiler](https://en.cppreference.com/w/cpp/compiler_support/20)
- olm
- For end to end encryption, -DLEET\_NO\_ENCRYPTION to disable
- openssl
- For end to end encryption, -DLEET\_NO\_ENCRYPTION to disable
To install these dependencies on **Debian**:
- `apt install meson nlohmann-json3-dev libolm-dev libssl-dev`
- Note that libolm is not available from standard Debian bookworm repositories.
If you're too lazy to compile these libraries yourself (I can't blame you),
you can simply rely on Meson. Meson will automatically download and build
all of the dependencies if they are not present on your system,
though if you're running Debian 12 it should be noted that you MUST
update your Meson version, otherwise it will fail to get the dependencies
where CMake is used upstream. If you use SID, this is not a problem you have
to deal with.
## Compiling with meson (Microsoft Windows/macOS/Linux/BSD)
You can compile libleet using the meson build system
on Windows, macOS, Linux and other Unix-like
operating systems.
You can do it like this:
- `meson setup build --prefix=/usr --reconfigure`
- `cd build`
- `meson install` as superuser.
If a dependency is not available, meson will fetch the source
code and attempt to build it to satisfy the dependency.
## Generating documentation
Doxygen is used project-wide for generating documentation.
To generate documentation: `cd docs; doxygen; cd ..`
## Compiling with Visual Studio (Microsoft Windows)
If you're compiling with Visual Studio, you can use the
included solution file. I don't use Windows so I don'
t really know if it works very well. Please note that
with this approach you must compile olm separately
for Windows. Thus, it is recommended that you use
Meson even when building on Windows.
## Design goals
- Easy to use
- Make use of C++ features
- Support Element as well as possible
- Be modern. libleet uses modern C++ features where appropriate
- Simplify much of the junk so that developers can just focus on
designing their user interface
## Features to implement
See the Issue tracker, as well as 'Not yet supported'.
## Examples
You can find examples in the examples subdirectory.
In addition,
[stellar-backend](https://git.speedie.site/speedie/stellar-backend)
is a web API which may also *serve* (get it?) as an example
for how to write a program to interface with Matrix using libleet.
## License
The project is licensed under the GNU Affero General
Public License version 3.0, which means it is
free software as defined by the Free Software Foundation.
Copyright (c) 2023 speedie (https://speedie.site)
# libleet
C++ Matrix client library which aims to support most features in the Matrix
specification, as well as Element features for a great user experience.
**This library is very much work in progress.**
Expect things to change, and as such it is not suitable for use
yet unless you feel like rewriting your code at a later date.
If you wish to help implement some of the many Matrix
features, feel free to do so in the form of a pull request.
It would be greatly appreciated :)
libleet is the library that powers the backend for the
work-in-progress Matrix client [stellar](https://git.speedie.site/speedie/stellar).
## Currently supports
- Connecting to a Matrix instance
- Logging in
- Message (including attachment) downloading
- Message sending
- Room creation
- Room upgrades
- Room listing (including those inside spaces)
- Space listing
- User listing
- Aliases
- Attachment uploading and downloading
- Discovery
- Refresh tokens
- Read marker
- User presence
- End to end encryption
- Can send encrypted text messages.
- Currently **cannot** send encrypted attachments, read encrypted messages,
verify interactively or use key backups.
- Reporting content
- VOIP
- Can retrieve TURN server credentials. Not much thought has been put into
VOIP support, because I am not a big fan of how it is implemented in Matrix.
- And more trivial features that I don't think are worth listing here.
## Not yet supported
- Managing rooms/spaces
- Creating spaces
- Storing custom data
- Device management
- Threads
- Third-party/Phone number/SSO authentication
- Various end-to-end encryption features
- Push notification endpoints
## Dependencies
- boost
- nlohmann\_json
- C++20 [compiler](https://en.cppreference.com/w/cpp/compiler_support/20)
- olm
- For end to end encryption, -DLEET\_NO\_ENCRYPTION to disable
- openssl
- For end to end encryption, -DLEET\_NO\_ENCRYPTION to disable
To install these dependencies on **Debian**:
- `apt install meson nlohmann-json3-dev libolm-dev libssl-dev libboost-dev`
- Note that libolm is not available from standard Debian bookworm repositories.
A meson wrap is included, which can be used if necessary.
To install these dependencies on **Arch**:
- `pacman -S meson nlohmann_json libolm openssl boost`
## Compiling with meson (Microsoft Windows/macOS/Linux/BSD)
You can compile libleet using the meson build system
on Windows, macOS, Linux and other Unix-like
operating systems.
You can do it like this:
- `meson setup build --prefix=/usr --reconfigure`
- `cd build`
- `meson install` as superuser.
If a dependency is not available, meson will fetch the source
code and attempt to build it to satisfy the dependency.
## Compiling with Visual Studio (Microsoft Windows)
To compile using Visual Studio 2022, you can open the solution file
and install the dependencies using nuget. All dependencies can be
installed this way, except for libolm.
To install libolm, you need to compile the CMake project manually.
You can do this by simply cloning [olm](https://gitlab.matrix.org/matrix-org/olm)
using Git. I recommend building a Release rather than a Debug build,
and I recommend that you statically link.
Then you can link with the resulting header files and the library
and then build libleet using msvc. You should end up with either
a dynamic library (.dll) or a static library (.lib)
## Use in projects
To use libleet in projects:
```cpp
/* Include libleet
* On Linux, the binary can be found in /usr/lib and the headers
* can be found in /usr/include/libleet.
* If you're using BSD or Windows, this may differ. You can use
* pkg-config to find the appropriate path and linker flag.
*/
#include <libleet/libleet.hpp>
```
Due to rather large dependencies, it is not recommended that you
statically link your program that depends on libleet. It's possible,
but not ideal in my opinion.
## Generating documentation
Doxygen is used project-wide for generating documentation.
To generate documentation: `cd docs; doxygen; cd ..`
## Design goals
- Fast
- Easy to use
- Cross-platform
- Make use of C++ features where appropriate, whilst not being too intimidating
- Support Element as well as possible
- Simplify Matrix API calls so that developers can just focus on
designing their user interface
## Features to implement
See the Issue tracker, as well as 'Not yet supported'.
## Examples
You can find examples in the examples subdirectory.
There are many examples that use different features
of the library. If you plan on writing a client, you should check
out `basic-chat-client` and perhaps `rest-api`.
You can build one of the examples using meson, in the same way
libleet is built.
## License
The project is licensed under the GNU Affero General
Public License version 3.0, which means it is
free software as defined by the Free Software Foundation.
Copyright (c) 2023 speedie (https://speedie.site)

File diff suppressed because it is too large Load diff

View file

@ -1,4 +1,4 @@
subprojects/*-*
subprojects/packagecache
build
basic-chat-program
subprojects/*-*
subprojects/packagecache
build
basic-chat-program

View file

@ -1,257 +1,257 @@
/* libleet example client
* ======================
*
* This is a libleet example client which hardcodes credentials and allows messages to be read
* and sent.
*/
#include <iostream>
#include <string>
#include <algorithm>
#include <filesystem>
#include <libleet/libleet.hpp>
int checkError() {
if (leet::errorCode != 0) { // Oh no, failed to login
std::cerr << "Failed. " << leet::friendlyError << " (" << leet::Error << ")\n"; // leet::friendlyError is a (usually) human-friendly error returned by the Matrix server. leet::Error is a more specific error code
return 1;
}
return 0;
}
int main() {
leet::User::Credentials cred; // Create a credentials object which we'll pass to the login functionm.
cred.Identifier = LEET_IDENTIFIER_USERID; // Our identifier. We're using a user ID, not a third party ID or phone number.
cred.Type = LEET_TYPE_PASSWORD; // Our type. We're authenticating using a password, and that's the only supported method as of now.
/* Get the username */
std::cout << "\033[2J\033[1;1H";
std::cout << "Enter a Matrix username (@<username>:<home server>)\n> ";
std::getline(std::cin, cred.Username);
/* Get the password */
std::cout << "\033[2J\033[1;1H";
std::cout << "Enter a Matrix password\n> ";
std::getline(std::cin, cred.Password);
/* In most Matrix clients, the device ID is simply a six character string of characters.
* This device ID is most likely issued by the home server, but for this example we explicitly
* set one for simplicity. If the device ID is not specified like this, the client must store
* this data in some way, for example by writing to a file and restoring it later.
*/
cred.deviceID = "libleet test client"; // Our device ID
/* leet::Homeserver specifies which Matrix server to use when making API requests.
* In most cases, this should be the same home server as you'd log in with.
*/
cred.Homeserver = leet::Homeserver; /* matrix.org is the default home server */
cred.Homeserver = leet::returnServerDiscovery(leet::returnHomeServerFromString(cred.Username));
leet::User::credentialsResponse resp;
/* Check if we should consider this an attempt to register. Then we will
* either log in or register.
*/
if (leet::checkIfUsernameIsAvailable(cred.Username)) {
resp = leet::registerAccount(&cred);
} else {
resp = leet::loginAccount(&cred);
}
/* Now that we don't need the credentials anymore, let's get rid of them for security reasons */
cred.clearCredentials();
if (checkError() == true) { // Yeah, appears something went wrong.
return false;
}
/* While libleet provides functions for saving a transaction ID to file and loading it:
*
* leet::transID = 0; // Initial value is zero, saved if no file exists
* leet::loadTransID("/tmp/basic-chat-program-transid"); // Now it will be set to the value saved to the file
* leet::saveTransID("/tmp/basic-chat-program-transid"); // Now we save the value
*
* These functions exist purely for demonstration purposes and should not be used in a serious project,
* because it's a very crude way to get a unique integer each time.
*
* A much better approach used by programs such as Element on the client side and
* Synapse on the server side is to simply use the amount of milliseconds passed
* since the Unix epoch, like this:
*
* leet::transID = leet::returnUnixTimestamp(); // This libleet function simply returns the amount of UNIX millis since January 1st 1970
*
* And then we can simply do this again each time we use a function that uses a transaction ID.
* Please note that the functions do not automatically increment this value, you are responsible
* for doing so. If you do not, the event will be considered a duplicate by the server as per the
* Matrix specification and as such most likely ignored.
*
* All functions that use a transaction ID will use leet::transID, functions will never require an integer to be manually specified.
*/
leet::transID = leet::returnUnixTimestamp();
std::string myRoom{""};
std::cout << "\033[2J\033[1;1H"; // Clear the screen on UNIX-like operating systems
/* Now we need to get a list of rooms. For simplicity,
* we won't bother to support spaces but all clients actually worth using
* should support spaces, because they are a basic feature of the Matrix spec.
*/
std::vector<leet::Room::Room> vector = leet::returnRooms(&resp, 9999);
std::cout << "\n";
/* Iterate through the room vector we received. It contains a lot of data,
* but let's just present the room alias (or ID if no alias is specified)
* and the topic. (if one is specified)
*/
for (auto& it : vector) {
const std::string Alias = it.Alias.compare("") ? it.Alias : it.roomID;
const std::string Topic = it.Topic.compare("") ? it.Topic : "No room topic specified.";
std::cout << Alias << " - " << Topic << "\n";
}
std::cout << "\n";
std::cout << "Enter a matrix channel:\n> ";
std::getline(std::cin, myRoom);
/* This finds the room ID used internally (i.e. #speedie:matrix.org -> !somelongstringoftext), something that is critical
* because Matrix operates using IDs, while humans probably don't want to memorize the actual room ID. From here on, functions
* will require the ID, and as such if you do not have an ID then you'll want to use leet::findRoomID() or leet::findUserID() among others.
*/
leet::Room::Room room;
room.roomID = leet::findRoomID(myRoom);
/* Now let's fill it with room properties */
room = leet::returnRoom(&resp, &room);
/* Set read marker */
leet::Event::Event event = leet::returnLatestEvent(&resp, &room);
leet::setReadMarkerPosition(&resp, &room, &event, &event, &event);
if (checkError() == true) { // Yeah, appears something went wrong. Most likely means the room ID is invalid.
std::cout << "Are you stupid? That isn't a valid channel... I think.\n";
return false;
}
#ifndef NO_ENCRYPTION
/* Let's create an Olm account */
leet::Encryption enc = leet::initEncryption();
/* Now let's create and upload our device keys */
enc = leet::uploadKeys(&resp, &enc);
/* Now let's create an Olm session with each device in the room and upload our new Megolm session */
enc = leet::createSessionInRoom(&resp, &enc, &room);
#endif
leet::Sync::Sync sync = leet::returnSync(&resp);
/* Read user messages in a loop */
for (;;) {
std::cout << "\033[2J\033[1;1H"; // Clear the screen on UNIX-like operating systems
std::vector<leet::Message::Message> messages = leet::returnMessages(&resp, &room, 25);
std::reverse(messages.begin(), messages.end());
int i{1};
for (auto &message : messages) {
std::cout << "\033[0;31m" << i << ". \033[0m" << message.Sender << " - " << message.messageText << "\n";
++i;
}
std::string myMessage{""};
std::cout << "> ";
std::getline(std::cin, myMessage);
/* Exiting, so we need to save the transaction ID. Vim-style keybinds are cool, so we'll use them for this example.
* And, you know, if you have no quit key, bad things will occur and you might have to unplug your computer.
*/
if (!myMessage.compare(":q")) {
#ifndef NO_ENCRYPTION
enc.destroy(); // We're done with encryption now
#endif
std::exit(0);
}
/* Message class, this will contain message information, and the message itself */
leet::Message::Message msg;
msg.messageText = myMessage;
msg.messageType = "m.text";
/* We upload a file if it exists
* Please note that this is a terrible implementation, ideally you
* should check if the file is an audio file, video file, image, and finally a generic file if all else fails.
*
* But for the simplicity of this example, we're going to use m.file, which will tell Matrix that it is a generic file.
* Below is an example of uploading a video, though.
*/
std::filesystem::path file{ myMessage };
if (std::filesystem::exists(file)) {
msg.messageType = "m.file";
msg.messageText = file.filename();
leet::Attachment::Attachment attachment = leet::uploadFile(&resp, myMessage);
msg.attachmentURL = attachment.URL;
if (leet::errorCode != 0) { /* Something went wrong */
continue;
}
}
/* Example of uploading a file embedded as a video.
* The main difference is, when you specify 'm.video' or any other more specific type, clients will
* treat the file differently. For example, on Element a .mp4 file will be displayed as a generic file if 'm.file'
* is used as a type, but if a more specific type such as 'm.video' in this case is used then it will attempt to embed and
* preview the video for users.
*
* Below is an example of a video file with 'm.video' rather than 'm.file'.
*
* msg.messageText = "test.mp4"; // Text, doesn't matter that much but Element does this so we'll copy it
* msg.messageType = "m.video"; // m.audio, m.video, m.image, m.text, m.file, ...
*
* leet::Attachment::Attachment attachment = leet::uploadFile(&resp, "/home/speedie/test.mp4"); // This uploads the file from our computer to the Matrix home server(s).
*
* msg.attachmentURL = attachment.URL; // Now our message has an attachment.
*/
/* Get a new transaction ID */
leet::transID = leet::returnUnixTimestamp();
/* Send the encrypted message
* You can use leet::sendMessage() to send plain text messages. leet::sendEncryptedMessage() should be used if you need to send an encrypted message.
* In a proper client, you'd check events to determine whether or not the room is encrypted or not, but that takes effort and I am a lazy programmer, just like you
* so I will only put in the bare minimum amount of effort into this example.
*/
#ifndef NO_ENCRYPTION
leet::sendEncryptedMessage(&resp, &enc, &room, &msg);
#else
leet::sendMessage(&resp, &room, &msg);
#endif
if (leet::errorCode != 0) {
#ifndef NO_ENCRYPTION
enc.destroy(); // We're done with encryption now
#endif
std::exit(1);
}
}
#ifndef NO_ENCRYPTION
enc.destroy(); // We're done with encryption now
#endif
/* Alright, so now that you've read the source code there are a few things you must keep in mind.
* This is not completely representative of what a fully featured client might look like. This is fine for prototype clients,
* or clients that serve a single purpose such as a Matrix bot, but when writing a proper client you should attempt to
* cache as much data as possible and asynchronously retrieve new data. This is for speed reasons, and because Matrix isn't
* particularly well designed.
*
* As for encryption, it is important to store sessions, both sent and received. But once again, for simplicity we're not doing that.
* Especially considering encryption in libleet is still in early development and not to be considered finalized. Encryption is easily
* the most difficult part of writing a Matrix client, and even with libleet that is no different.
*/
}
/* libleet example client
* ======================
*
* This is a libleet example client which hardcodes credentials and allows messages to be read
* and sent.
*/
#include <iostream>
#include <string>
#include <algorithm>
#include <filesystem>
#include <libleet/libleet.hpp>
int checkError() {
if (leet::errorCode != 0) { // Oh no, failed to login
std::cerr << "Failed. " << leet::friendlyError << " (" << leet::Error << ")\n"; // leet::friendlyError is a (usually) human-friendly error returned by the Matrix server. leet::Error is a more specific error code
return 1;
}
return 0;
}
int main() {
leet::User::Credentials cred; // Create a credentials object which we'll pass to the login functionm.
cred.Identifier = LEET_IDENTIFIER_USERID; // Our identifier. We're using a user ID, not a third party ID or phone number.
cred.Type = LEET_TYPE_PASSWORD; // Our type. We're authenticating using a password, and that's the only supported method as of now.
/* Get the username */
std::cout << "\033[2J\033[1;1H";
std::cout << "Enter a Matrix username (@<username>:<home server>)\n> ";
std::getline(std::cin, cred.Username);
/* Get the password */
std::cout << "\033[2J\033[1;1H";
std::cout << "Enter a Matrix password\n> ";
std::getline(std::cin, cred.Password);
/* In most Matrix clients, the device ID is simply a six character string of characters.
* This device ID is most likely issued by the home server, but for this example we explicitly
* set one for simplicity. If the device ID is not specified like this, the client must store
* this data in some way, for example by writing to a file and restoring it later.
*/
cred.deviceID = "libleet test client"; // Our device ID
/* leet::Homeserver specifies which Matrix server to use when making API requests.
* In most cases, this should be the same home server as you'd log in with.
*/
cred.Homeserver = leet::Homeserver; /* matrix.org is the default home server */
cred.Homeserver = leet::returnServerDiscovery(leet::returnHomeServerFromString(cred.Username));
leet::User::credentialsResponse resp;
/* Check if we should consider this an attempt to register. Then we will
* either log in or register.
*/
if (leet::checkIfUsernameIsAvailable(cred.Username)) {
resp = leet::registerAccount(&cred);
} else {
resp = leet::loginAccount(&cred);
}
/* Now that we don't need the credentials anymore, let's get rid of them for security reasons */
cred.clearCredentials();
if (checkError() == true) { // Yeah, appears something went wrong.
return false;
}
/* While libleet provides functions for saving a transaction ID to file and loading it:
*
* leet::transID = 0; // Initial value is zero, saved if no file exists
* leet::loadTransID("/tmp/basic-chat-program-transid"); // Now it will be set to the value saved to the file
* leet::saveTransID("/tmp/basic-chat-program-transid"); // Now we save the value
*
* These functions exist purely for demonstration purposes and should not be used in a serious project,
* because it's a very crude way to get a unique integer each time.
*
* A much better approach used by programs such as Element on the client side and
* Synapse on the server side is to simply use the amount of milliseconds passed
* since the Unix epoch, like this:
*
* leet::transID = leet::returnUnixTimestamp(); // This libleet function simply returns the amount of UNIX millis since January 1st 1970
*
* And then we can simply do this again each time we use a function that uses a transaction ID.
* Please note that the functions do not automatically increment this value, you are responsible
* for doing so. If you do not, the event will be considered a duplicate by the server as per the
* Matrix specification and as such most likely ignored.
*
* All functions that use a transaction ID will use leet::transID, functions will never require an integer to be manually specified.
*/
leet::transID = leet::returnUnixTimestamp();
std::string myRoom{""};
std::cout << "\033[2J\033[1;1H"; // Clear the screen on UNIX-like operating systems
/* Now we need to get a list of rooms. For simplicity,
* we won't bother to support spaces but all clients actually worth using
* should support spaces, because they are a basic feature of the Matrix spec.
*/
std::vector<leet::Room::Room> vector = leet::returnRooms(&resp, 9999);
std::cout << "\n";
/* Iterate through the room vector we received. It contains a lot of data,
* but let's just present the room alias (or ID if no alias is specified)
* and the topic. (if one is specified)
*/
for (auto& it : vector) {
const std::string Alias = it.Alias.compare("") ? it.Alias : it.roomID;
const std::string Topic = it.Topic.compare("") ? it.Topic : "No room topic specified.";
std::cout << Alias << " - " << Topic << "\n";
}
std::cout << "\n";
std::cout << "Enter a matrix channel:\n> ";
std::getline(std::cin, myRoom);
/* This finds the room ID used internally (i.e. #speedie:matrix.org -> !somelongstringoftext), something that is critical
* because Matrix operates using IDs, while humans probably don't want to memorize the actual room ID. From here on, functions
* will require the ID, and as such if you do not have an ID then you'll want to use leet::findRoomID() or leet::findUserID() among others.
*/
leet::Room::Room room;
room.roomID = leet::findRoomID(myRoom);
/* Now let's fill it with room properties */
room = leet::returnRoom(&resp, &room);
/* Set read marker */
leet::Event::Event event = leet::returnLatestEvent(&resp, &room);
leet::setReadMarkerPosition(&resp, &room, &event, &event, &event);
if (checkError() == true) { // Yeah, appears something went wrong. Most likely means the room ID is invalid.
std::cout << "Are you stupid? That isn't a valid channel... I think.\n";
return false;
}
#ifndef NO_ENCRYPTION
/* Let's create an Olm account */
leet::Encryption enc = leet::initEncryption();
/* Now let's create and upload our device keys */
enc = leet::uploadKeys(&resp, &enc);
/* Now let's create an Olm session with each device in the room and upload our new Megolm session */
enc = leet::createSessionInRoom(&resp, &enc, &room);
#endif
leet::Sync::Sync sync = leet::returnSync(&resp);
/* Read user messages in a loop */
for (;;) {
std::cout << "\033[2J\033[1;1H"; // Clear the screen on UNIX-like operating systems
std::vector<leet::Message::Message> messages = leet::returnMessages(&resp, &room, 25);
std::reverse(messages.begin(), messages.end());
int i{1};
for (auto &message : messages) {
std::cout << "\033[0;31m" << i << ". \033[0m" << message.Sender << " - " << message.messageText << "\n";
++i;
}
std::string myMessage{""};
std::cout << "> ";
std::getline(std::cin, myMessage);
/* Exiting, so we need to save the transaction ID. Vim-style keybinds are cool, so we'll use them for this example.
* And, you know, if you have no quit key, bad things will occur and you might have to unplug your computer.
*/
if (!myMessage.compare(":q")) {
#ifndef NO_ENCRYPTION
enc.destroy(); // We're done with encryption now
#endif
std::exit(0);
}
/* Message class, this will contain message information, and the message itself */
leet::Message::Message msg;
msg.messageText = myMessage;
msg.messageType = "m.text";
/* We upload a file if it exists
* Please note that this is a terrible implementation, ideally you
* should check if the file is an audio file, video file, image, and finally a generic file if all else fails.
*
* But for the simplicity of this example, we're going to use m.file, which will tell Matrix that it is a generic file.
* Below is an example of uploading a video, though.
*/
std::filesystem::path file{ myMessage };
if (std::filesystem::exists(file)) {
msg.messageType = "m.file";
msg.messageText = file.filename();
leet::Attachment::Attachment attachment = leet::uploadFile(&resp, myMessage);
msg.attachmentURL = attachment.URL;
if (leet::errorCode != 0) { /* Something went wrong */
continue;
}
}
/* Example of uploading a file embedded as a video.
* The main difference is, when you specify 'm.video' or any other more specific type, clients will
* treat the file differently. For example, on Element a .mp4 file will be displayed as a generic file if 'm.file'
* is used as a type, but if a more specific type such as 'm.video' in this case is used then it will attempt to embed and
* preview the video for users.
*
* Below is an example of a video file with 'm.video' rather than 'm.file'.
*
* msg.messageText = "test.mp4"; // Text, doesn't matter that much but Element does this so we'll copy it
* msg.messageType = "m.video"; // m.audio, m.video, m.image, m.text, m.file, ...
*
* leet::Attachment::Attachment attachment = leet::uploadFile(&resp, "/home/speedie/test.mp4"); // This uploads the file from our computer to the Matrix home server(s).
*
* msg.attachmentURL = attachment.URL; // Now our message has an attachment.
*/
/* Get a new transaction ID */
leet::transID = leet::returnUnixTimestamp();
/* Send the encrypted message
* You can use leet::sendMessage() to send plain text messages. leet::sendEncryptedMessage() should be used if you need to send an encrypted message.
* In a proper client, you'd check events to determine whether or not the room is encrypted or not, but that takes effort and I am a lazy programmer, just like you
* so I will only put in the bare minimum amount of effort into this example.
*/
#ifndef NO_ENCRYPTION
leet::sendEncryptedMessage(&resp, &enc, &room, &msg);
#else
leet::sendMessage(&resp, &room, &msg);
#endif
if (leet::errorCode != 0) {
#ifndef NO_ENCRYPTION
enc.destroy(); // We're done with encryption now
#endif
std::exit(1);
}
}
#ifndef NO_ENCRYPTION
enc.destroy(); // We're done with encryption now
#endif
/* Alright, so now that you've read the source code there are a few things you must keep in mind.
* This is not completely representative of what a fully featured client might look like. This is fine for prototype clients,
* or clients that serve a single purpose such as a Matrix bot, but when writing a proper client you should attempt to
* cache as much data as possible and asynchronously retrieve new data. This is for speed reasons, and because Matrix isn't
* particularly well designed.
*
* As for encryption, it is important to store sessions, both sent and received. But once again, for simplicity we're not doing that.
* Especially considering encryption in libleet is still in early development and not to be considered finalized. Encryption is easily
* the most difficult part of writing a Matrix client, and even with libleet that is no different.
*/
}

View file

@ -1,29 +1,29 @@
project(
'basic-chat-program',
'cpp',
version : '"0.1"',
default_options : ['warning_level=3']
)
cc = meson.get_compiler('cpp')
project_source_files = [
'basic-chat-program.cpp',
]
project_dependencies = [
dependency('libleet'),
]
build_args = [
'-DVERSION=' + meson.project_version(),
]
project_target = executable(
meson.project_name(),
project_source_files, install : true,
dependencies: project_dependencies,
c_args : build_args,
)
test('basic-chat-program', project_target)
project(
'basic-chat-program',
'cpp',
version : '"0.1"',
default_options : ['warning_level=3']
)
cc = meson.get_compiler('cpp')
project_source_files = [
'basic-chat-program.cpp',
]
project_dependencies = [
dependency('libleet'),
]
build_args = [
'-DVERSION=' + meson.project_version(),
]
project_target = executable(
meson.project_name(),
project_source_files, install : true,
dependencies: project_dependencies,
c_args : build_args,
)
test('basic-chat-program', project_target)

View file

@ -1,13 +1,13 @@
[wrap-file]
directory = nlohmann_json-3.11.3
lead_directory_missing = true
source_url = https://github.com/nlohmann/json/releases/download/v3.11.3/include.zip
source_filename = nlohmann_json-3.11.3.zip
source_hash = a22461d13119ac5c78f205d3df1db13403e58ce1bb1794edc9313677313f4a9d
patch_url = https://wrapdb.mesonbuild.com/v1/projects/nlohmann_json/3.9.1/1/get_zip
patch_filename = nlohmann_json-3.9.1-1-wrap.zip
patch_hash = 1774e5506fbe3897d652f67e41973194b948d2ab851cf464a742f35f160a1435
[provide]
nlohmann_json = nlohmann_json_dep
[wrap-file]
directory = nlohmann_json-3.11.3
lead_directory_missing = true
source_url = https://github.com/nlohmann/json/releases/download/v3.11.3/include.zip
source_filename = nlohmann_json-3.11.3.zip
source_hash = a22461d13119ac5c78f205d3df1db13403e58ce1bb1794edc9313677313f4a9d
patch_url = https://wrapdb.mesonbuild.com/v1/projects/nlohmann_json/3.9.1/1/get_zip
patch_filename = nlohmann_json-3.9.1-1-wrap.zip
patch_hash = 1774e5506fbe3897d652f67e41973194b948d2ab851cf464a742f35f160a1435
[provide]
nlohmann_json = nlohmann_json_dep

View file

@ -1,10 +1,10 @@
[wrap-file]
directory = olm-3.2.16
method = cmake
source_url = https://gitlab.matrix.org/matrix-org/olm/-/archive/3.2.16/olm-3.2.16.tar.gz
source_filename = olm-3.2.16.tar.gz
source_hash = 1e90f9891009965fd064be747616da46b232086fe270b77605ec9bda34272a68
wrapdb_version = 3.2.16-1
[provide]
olm = olm_dep
[wrap-file]
directory = olm-3.2.16
method = cmake
source_url = https://gitlab.matrix.org/matrix-org/olm/-/archive/3.2.16/olm-3.2.16.tar.gz
source_filename = olm-3.2.16.tar.gz
source_hash = 1e90f9891009965fd064be747616da46b232086fe270b77605ec9bda34272a68
wrapdb_version = 3.2.16-1
[provide]
olm = olm_dep

View file

@ -1,15 +1,15 @@
[wrap-file]
directory = openssl-3.0.8
source_url = https://www.openssl.org/source/openssl-3.0.8.tar.gz
source_filename = openssl-3.0.8.tar.gz
source_hash = 6c13d2bf38fdf31eac3ce2a347073673f5d63263398f1f69d0df4a41253e4b3e
patch_filename = openssl_3.0.8-2_patch.zip
patch_url = https://wrapdb.mesonbuild.com/v2/openssl_3.0.8-2/get_patch
patch_hash = e84b5fe469e681e3318184157a0c7c43d4cbacd078bb88f506e31569f8f75072
source_fallback_url = https://github.com/mesonbuild/wrapdb/releases/download/openssl_3.0.8-2/openssl-3.0.8.tar.gz
wrapdb_version = 3.0.8-2
[provide]
libcrypto = libcrypto_dep
libssl = libssl_dep
openssl = openssl_dep
[wrap-file]
directory = openssl-3.0.8
source_url = https://www.openssl.org/source/openssl-3.0.8.tar.gz
source_filename = openssl-3.0.8.tar.gz
source_hash = 6c13d2bf38fdf31eac3ce2a347073673f5d63263398f1f69d0df4a41253e4b3e
patch_filename = openssl_3.0.8-2_patch.zip
patch_url = https://wrapdb.mesonbuild.com/v2/openssl_3.0.8-2/get_patch
patch_hash = e84b5fe469e681e3318184157a0c7c43d4cbacd078bb88f506e31569f8f75072
source_fallback_url = https://github.com/mesonbuild/wrapdb/releases/download/openssl_3.0.8-2/openssl-3.0.8.tar.gz
wrapdb_version = 3.0.8-2
[provide]
libcrypto = libcrypto_dep
libssl = libssl_dep
openssl = openssl_dep

View file

@ -1,4 +1,4 @@
subprojects/*-*
subprojects/packagecache
build
decode-mxc-url
subprojects/*-*
subprojects/packagecache
build
decode-mxc-url

View file

@ -1,55 +1,54 @@
#include <iostream>
#include <string>
#include <algorithm>
#include <filesystem>
#include "../../include/libleet.hpp"
#include "../../src/libleet.cpp"
int checkError() {
if (leet::errorCode != 0) {
std::cerr << "Failed. " << leet::friendlyError << " (" << leet::Error << ")\n";
return 1;
}
return 0;
}
int main() {
leet::User::Credentials cred;
leet::Attachment::Attachment attachment;
cred.Identifier = LEET_IDENTIFIER_USERID;
cred.Type = LEET_TYPE_PASSWORD;
std::cout << "\033[2J\033[1;1H";
std::cout << "Enter a Matrix username (@<username>:<home server>)\n> ";
std::getline(std::cin, cred.Username);
std::cout << "\033[2J\033[1;1H";
std::cout << "Enter a Matrix password\n> ";
std::getline(std::cin, cred.Password);
std::cout << "\033[2J\033[1;1H";
std::cout << "Enter a Matrix mxc:// URL\n> ";
std::getline(std::cin, attachment.URL);
cred.deviceID = "libleet test client";
cred.Homeserver = leet::returnServerDiscovery(leet::returnHomeServerFromString(cred.Username));
leet::User::credentialsResponse resp;
resp = leet::loginAccount(&cred);
cred.clearCredentials();
if (checkError() == true) {
return false;
}
leet::transID = leet::returnUnixTimestamp();
std::cout << leet::decodeFile(&resp, &attachment) << "\n";
if (leet::errorCode != 0) {
std::exit(1);
}
}
#include <iostream>
#include <string>
#include <algorithm>
#include <filesystem>
#include <libleet/libleet.hpp>
int checkError() {
if (leet::errorCode != 0) {
std::cerr << "Failed. " << leet::friendlyError << " (" << leet::Error << ")\n";
return 1;
}
return 0;
}
int main() {
leet::User::Credentials cred;
leet::Attachment::Attachment attachment;
cred.Identifier = LEET_IDENTIFIER_USERID;
cred.Type = LEET_TYPE_PASSWORD;
std::cout << "\033[2J\033[1;1H";
std::cout << "Enter a Matrix username (@<username>:<home server>)\n> ";
std::getline(std::cin, cred.Username);
std::cout << "\033[2J\033[1;1H";
std::cout << "Enter a Matrix password\n> ";
std::getline(std::cin, cred.Password);
std::cout << "\033[2J\033[1;1H";
std::cout << "Enter a Matrix mxc:// URL\n> ";
std::getline(std::cin, attachment.URL);
cred.deviceID = "libleet test client";
cred.Homeserver = leet::returnServerDiscovery(leet::returnHomeServerFromString(cred.Username));
leet::User::credentialsResponse resp;
resp = leet::loginAccount(&cred);
cred.clearCredentials();
if (checkError() == true) {
return false;
}
leet::transID = leet::returnUnixTimestamp();
std::cout << leet::decodeFile(&resp, &attachment) << "\n";
if (leet::errorCode != 0) {
std::exit(1);
}
}

View file

@ -1,29 +1,29 @@
project(
'decode-mxc-url',
'cpp',
version : '"0.1"',
default_options : ['warning_level=3']
)
cc = meson.get_compiler('cpp')
project_source_files = [
'decode-mxc-url.cpp',
]
project_dependencies = [
dependency('libleet'),
]
build_args = [
'-DVERSION=' + meson.project_version(),
]
project_target = executable(
meson.project_name(),
project_source_files, install : true,
dependencies: project_dependencies,
c_args : build_args,
)
test('decode-mxc-url', project_target)
project(
'decode-mxc-url',
'cpp',
version : '"0.1"',
default_options : ['warning_level=3']
)
cc = meson.get_compiler('cpp')
project_source_files = [
'decode-mxc-url.cpp',
]
project_dependencies = [
dependency('libleet'),
]
build_args = [
'-DVERSION=' + meson.project_version(),
]
project_target = executable(
meson.project_name(),
project_source_files, install : true,
dependencies: project_dependencies,
c_args : build_args,
)
test('decode-mxc-url', project_target)

View file

@ -1,13 +1,13 @@
[wrap-file]
directory = nlohmann_json-3.11.3
lead_directory_missing = true
source_url = https://github.com/nlohmann/json/releases/download/v3.11.3/include.zip
source_filename = nlohmann_json-3.11.3.zip
source_hash = a22461d13119ac5c78f205d3df1db13403e58ce1bb1794edc9313677313f4a9d
patch_url = https://wrapdb.mesonbuild.com/v1/projects/nlohmann_json/3.9.1/1/get_zip
patch_filename = nlohmann_json-3.9.1-1-wrap.zip
patch_hash = 1774e5506fbe3897d652f67e41973194b948d2ab851cf464a742f35f160a1435
[provide]
nlohmann_json = nlohmann_json_dep
[wrap-file]
directory = nlohmann_json-3.11.3
lead_directory_missing = true
source_url = https://github.com/nlohmann/json/releases/download/v3.11.3/include.zip
source_filename = nlohmann_json-3.11.3.zip
source_hash = a22461d13119ac5c78f205d3df1db13403e58ce1bb1794edc9313677313f4a9d
patch_url = https://wrapdb.mesonbuild.com/v1/projects/nlohmann_json/3.9.1/1/get_zip
patch_filename = nlohmann_json-3.9.1-1-wrap.zip
patch_hash = 1774e5506fbe3897d652f67e41973194b948d2ab851cf464a742f35f160a1435
[provide]
nlohmann_json = nlohmann_json_dep

View file

@ -1,10 +1,10 @@
[wrap-file]
directory = olm-3.2.16
method = cmake
source_url = https://gitlab.matrix.org/matrix-org/olm/-/archive/3.2.16/olm-3.2.16.tar.gz
source_filename = olm-3.2.16.tar.gz
source_hash = 1e90f9891009965fd064be747616da46b232086fe270b77605ec9bda34272a68
wrapdb_version = 3.2.16-1
[provide]
olm = olm_dep
[wrap-file]
directory = olm-3.2.16
method = cmake
source_url = https://gitlab.matrix.org/matrix-org/olm/-/archive/3.2.16/olm-3.2.16.tar.gz
source_filename = olm-3.2.16.tar.gz
source_hash = 1e90f9891009965fd064be747616da46b232086fe270b77605ec9bda34272a68
wrapdb_version = 3.2.16-1
[provide]
olm = olm_dep

View file

@ -1,15 +1,15 @@
[wrap-file]
directory = openssl-3.0.8
source_url = https://www.openssl.org/source/openssl-3.0.8.tar.gz
source_filename = openssl-3.0.8.tar.gz
source_hash = 6c13d2bf38fdf31eac3ce2a347073673f5d63263398f1f69d0df4a41253e4b3e
patch_filename = openssl_3.0.8-2_patch.zip
patch_url = https://wrapdb.mesonbuild.com/v2/openssl_3.0.8-2/get_patch
patch_hash = e84b5fe469e681e3318184157a0c7c43d4cbacd078bb88f506e31569f8f75072
source_fallback_url = https://github.com/mesonbuild/wrapdb/releases/download/openssl_3.0.8-2/openssl-3.0.8.tar.gz
wrapdb_version = 3.0.8-2
[provide]
libcrypto = libcrypto_dep
libssl = libssl_dep
openssl = openssl_dep
[wrap-file]
directory = openssl-3.0.8
source_url = https://www.openssl.org/source/openssl-3.0.8.tar.gz
source_filename = openssl-3.0.8.tar.gz
source_hash = 6c13d2bf38fdf31eac3ce2a347073673f5d63263398f1f69d0df4a41253e4b3e
patch_filename = openssl_3.0.8-2_patch.zip
patch_url = https://wrapdb.mesonbuild.com/v2/openssl_3.0.8-2/get_patch
patch_hash = e84b5fe469e681e3318184157a0c7c43d4cbacd078bb88f506e31569f8f75072
source_fallback_url = https://github.com/mesonbuild/wrapdb/releases/download/openssl_3.0.8-2/openssl-3.0.8.tar.gz
wrapdb_version = 3.0.8-2
[provide]
libcrypto = libcrypto_dep
libssl = libssl_dep
openssl = openssl_dep

View file

@ -1,4 +1,4 @@
subprojects/*-*
subprojects/packagecache
build
download-mxc-url
subprojects/*-*
subprojects/packagecache
build
download-mxc-url

View file

@ -1,62 +1,61 @@
#include <iostream>
#include <string>
#include <algorithm>
#include <filesystem>
#include "../../include/libleet.hpp"
#include "../../src/libleet.cpp"
int checkError() {
if (leet::errorCode != 0) {
std::cerr << "Failed. " << leet::friendlyError << " (" << leet::Error << ")\n";
return 1;
}
return 0;
}
int main() {
leet::User::Credentials cred;
leet::Attachment::Attachment attachment;
std::string outputPath{};
cred.Identifier = LEET_IDENTIFIER_USERID;
cred.Type = LEET_TYPE_PASSWORD;
std::cout << "\033[2J\033[1;1H";
std::cout << "Enter a Matrix username (@<username>:<home server>)\n> ";
std::getline(std::cin, cred.Username);
std::cout << "\033[2J\033[1;1H";
std::cout << "Enter a Matrix password\n> ";
std::getline(std::cin, cred.Password);
std::cout << "\033[2J\033[1;1H";
std::cout << "Enter a Matrix mxc:// URL\n> ";
std::getline(std::cin, attachment.URL);
std::cout << "\033[2J\033[1;1H";
std::cout << "Enter an output file\n> ";
std::getline(std::cin, outputPath);
cred.deviceID = "libleet test client";
cred.Homeserver = leet::returnServerDiscovery(leet::returnHomeServerFromString(cred.Username));
leet::User::credentialsResponse resp;
resp = leet::loginAccount(&cred);
cred.clearCredentials();
if (checkError() == true) {
return false;
}
leet::transID = leet::returnUnixTimestamp();
if (leet::downloadFile(&resp, &attachment, outputPath)) {
std::cout << "File downloaded and saved to '" << outputPath << "'\n";
return 0;
} else {
std::cerr << "Failed to download file.\n";
return 1;
}
}
#include <iostream>
#include <string>
#include <algorithm>
#include <filesystem>
#include <libleet/libleet.hpp>
int checkError() {
if (leet::errorCode != 0) {
std::cerr << "Failed. " << leet::friendlyError << " (" << leet::Error << ")\n";
return 1;
}
return 0;
}
int main() {
leet::User::Credentials cred;
leet::Attachment::Attachment attachment;
std::string outputPath{};
cred.Identifier = LEET_IDENTIFIER_USERID;
cred.Type = LEET_TYPE_PASSWORD;
std::cout << "\033[2J\033[1;1H";
std::cout << "Enter a Matrix username (@<username>:<home server>)\n> ";
std::getline(std::cin, cred.Username);
std::cout << "\033[2J\033[1;1H";
std::cout << "Enter a Matrix password\n> ";
std::getline(std::cin, cred.Password);
std::cout << "\033[2J\033[1;1H";
std::cout << "Enter a Matrix mxc:// URL\n> ";
std::getline(std::cin, attachment.URL);
std::cout << "\033[2J\033[1;1H";
std::cout << "Enter an output file\n> ";
std::getline(std::cin, outputPath);
cred.deviceID = "libleet test client";
cred.Homeserver = leet::returnServerDiscovery(leet::returnHomeServerFromString(cred.Username));
leet::User::credentialsResponse resp;
resp = leet::loginAccount(&cred);
cred.clearCredentials();
if (checkError() == true) {
return false;
}
leet::transID = leet::returnUnixTimestamp();
if (leet::downloadFile(&resp, &attachment, outputPath)) {
std::cout << "File downloaded and saved to '" << outputPath << "'\n";
return 0;
} else {
std::cerr << "Failed to download file.\n";
return 1;
}
}

View file

@ -1,29 +1,29 @@
project(
'download-mxc-url',
'cpp',
version : '"0.1"',
default_options : ['warning_level=3']
)
cc = meson.get_compiler('cpp')
project_source_files = [
'download-mxc-url.cpp',
]
project_dependencies = [
dependency('libleet'),
]
build_args = [
'-DVERSION=' + meson.project_version(),
]
project_target = executable(
meson.project_name(),
project_source_files, install : true,
dependencies: project_dependencies,
c_args : build_args,
)
test('download-mxc-url', project_target)
project(
'download-mxc-url',
'cpp',
version : '"0.1"',
default_options : ['warning_level=3']
)
cc = meson.get_compiler('cpp')
project_source_files = [
'download-mxc-url.cpp',
]
project_dependencies = [
dependency('libleet'),
]
build_args = [
'-DVERSION=' + meson.project_version(),
]
project_target = executable(
meson.project_name(),
project_source_files, install : true,
dependencies: project_dependencies,
c_args : build_args,
)
test('download-mxc-url', project_target)

View file

@ -1,13 +1,13 @@
[wrap-file]
directory = nlohmann_json-3.11.3
lead_directory_missing = true
source_url = https://github.com/nlohmann/json/releases/download/v3.11.3/include.zip
source_filename = nlohmann_json-3.11.3.zip
source_hash = a22461d13119ac5c78f205d3df1db13403e58ce1bb1794edc9313677313f4a9d
patch_url = https://wrapdb.mesonbuild.com/v1/projects/nlohmann_json/3.9.1/1/get_zip
patch_filename = nlohmann_json-3.9.1-1-wrap.zip
patch_hash = 1774e5506fbe3897d652f67e41973194b948d2ab851cf464a742f35f160a1435
[provide]
nlohmann_json = nlohmann_json_dep
[wrap-file]
directory = nlohmann_json-3.11.3
lead_directory_missing = true
source_url = https://github.com/nlohmann/json/releases/download/v3.11.3/include.zip
source_filename = nlohmann_json-3.11.3.zip
source_hash = a22461d13119ac5c78f205d3df1db13403e58ce1bb1794edc9313677313f4a9d
patch_url = https://wrapdb.mesonbuild.com/v1/projects/nlohmann_json/3.9.1/1/get_zip
patch_filename = nlohmann_json-3.9.1-1-wrap.zip
patch_hash = 1774e5506fbe3897d652f67e41973194b948d2ab851cf464a742f35f160a1435
[provide]
nlohmann_json = nlohmann_json_dep

View file

@ -1,10 +1,10 @@
[wrap-file]
directory = olm-3.2.16
method = cmake
source_url = https://gitlab.matrix.org/matrix-org/olm/-/archive/3.2.16/olm-3.2.16.tar.gz
source_filename = olm-3.2.16.tar.gz
source_hash = 1e90f9891009965fd064be747616da46b232086fe270b77605ec9bda34272a68
wrapdb_version = 3.2.16-1
[provide]
olm = olm_dep
[wrap-file]
directory = olm-3.2.16
method = cmake
source_url = https://gitlab.matrix.org/matrix-org/olm/-/archive/3.2.16/olm-3.2.16.tar.gz
source_filename = olm-3.2.16.tar.gz
source_hash = 1e90f9891009965fd064be747616da46b232086fe270b77605ec9bda34272a68
wrapdb_version = 3.2.16-1
[provide]
olm = olm_dep

View file

@ -1,15 +1,15 @@
[wrap-file]
directory = openssl-3.0.8
source_url = https://www.openssl.org/source/openssl-3.0.8.tar.gz
source_filename = openssl-3.0.8.tar.gz
source_hash = 6c13d2bf38fdf31eac3ce2a347073673f5d63263398f1f69d0df4a41253e4b3e
patch_filename = openssl_3.0.8-2_patch.zip
patch_url = https://wrapdb.mesonbuild.com/v2/openssl_3.0.8-2/get_patch
patch_hash = e84b5fe469e681e3318184157a0c7c43d4cbacd078bb88f506e31569f8f75072
source_fallback_url = https://github.com/mesonbuild/wrapdb/releases/download/openssl_3.0.8-2/openssl-3.0.8.tar.gz
wrapdb_version = 3.0.8-2
[provide]
libcrypto = libcrypto_dep
libssl = libssl_dep
openssl = openssl_dep
[wrap-file]
directory = openssl-3.0.8
source_url = https://www.openssl.org/source/openssl-3.0.8.tar.gz
source_filename = openssl-3.0.8.tar.gz
source_hash = 6c13d2bf38fdf31eac3ce2a347073673f5d63263398f1f69d0df4a41253e4b3e
patch_filename = openssl_3.0.8-2_patch.zip
patch_url = https://wrapdb.mesonbuild.com/v2/openssl_3.0.8-2/get_patch
patch_hash = e84b5fe469e681e3318184157a0c7c43d4cbacd078bb88f506e31569f8f75072
source_fallback_url = https://github.com/mesonbuild/wrapdb/releases/download/openssl_3.0.8-2/openssl-3.0.8.tar.gz
wrapdb_version = 3.0.8-2
[provide]
libcrypto = libcrypto_dep
libssl = libssl_dep
openssl = openssl_dep

View file

@ -1,4 +1,4 @@
subprojects/*-*
subprojects/packagecache
build
parse-url
subprojects/*-*
subprojects/packagecache
build
parse-url

View file

@ -1,29 +1,29 @@
project(
'parse-url',
'cpp',
version : '"0.1"',
default_options : ['warning_level=3']
)
cc = meson.get_compiler('cpp')
project_source_files = [
'parse-url.cpp',
]
project_dependencies = [
dependency('libleet'),
]
build_args = [
'-DVERSION=' + meson.project_version(),
]
project_target = executable(
meson.project_name(),
project_source_files, install : true,
dependencies: project_dependencies,
c_args : build_args,
)
test('parse-url', project_target)
project(
'parse-url',
'cpp',
version : '"0.1"',
default_options : ['warning_level=3']
)
cc = meson.get_compiler('cpp')
project_source_files = [
'parse-url.cpp',
]
project_dependencies = [
dependency('libleet'),
]
build_args = [
'-DVERSION=' + meson.project_version(),
]
project_target = executable(
meson.project_name(),
project_source_files, install : true,
dependencies: project_dependencies,
c_args : build_args,
)
test('parse-url', project_target)

View file

@ -1,35 +1,34 @@
/* libleet parse URL
* ======================
* This is a simple libleet example, which allows you to simply parse a URL.
* It is quite useless, and only really serves as a test for the network request
* wrapper.
*/
#include <iostream>
#include <string>
#include <algorithm>
#include <filesystem>
#include "../../include/libleet.hpp"
#include "../../src/libleet.cpp"
int main() {
std::string targetURL{};
std::cout << "Enter a URL to parse:\n> ";
std::getline(std::cin, targetURL);
leetRequest::URL url;
url.parseURLFromString(targetURL);
std::cout << "Host: " << url.Host << "\n";
std::cout << "Endpoint: " << url.Endpoint << "\n";
std::cout << "Query: " << url.Query << "\n";
if (url.Protocol == leetRequest::LEET_REQUEST_PROTOCOL_HTTP) {
std::cout << "Protocol: HTTP\n";
} else {
std::cout << "Protocol: HTTPS\n";
}
std::cout << "Port: " << url.Port << "\n";
return 0;
}
/* libleet parse URL
* ======================
* This is a simple libleet example, which allows you to simply parse a URL.
* It is quite useless, and only really serves as a test for the network request
* wrapper.
*/
#include <iostream>
#include <string>
#include <algorithm>
#include <filesystem>
#include <libleet/libleet.hpp>
int main() {
std::string targetURL{};
std::cout << "Enter a URL to parse:\n> ";
std::getline(std::cin, targetURL);
leetRequest::URL url;
url.parseURLFromString(targetURL);
std::cout << "Host: " << url.Host << "\n";
std::cout << "Endpoint: " << url.Endpoint << "\n";
std::cout << "Query: " << url.Query << "\n";
if (url.Protocol == leetRequest::LEET_REQUEST_PROTOCOL_HTTP) {
std::cout << "Protocol: HTTP\n";
} else {
std::cout << "Protocol: HTTPS\n";
}
std::cout << "Port: " << url.Port << "\n";
return 0;
}

View file

@ -1,13 +1,13 @@
[wrap-file]
directory = nlohmann_json-3.11.3
lead_directory_missing = true
source_url = https://github.com/nlohmann/json/releases/download/v3.11.3/include.zip
source_filename = nlohmann_json-3.11.3.zip
source_hash = a22461d13119ac5c78f205d3df1db13403e58ce1bb1794edc9313677313f4a9d
patch_url = https://wrapdb.mesonbuild.com/v1/projects/nlohmann_json/3.9.1/1/get_zip
patch_filename = nlohmann_json-3.9.1-1-wrap.zip
patch_hash = 1774e5506fbe3897d652f67e41973194b948d2ab851cf464a742f35f160a1435
[provide]
nlohmann_json = nlohmann_json_dep
[wrap-file]
directory = nlohmann_json-3.11.3
lead_directory_missing = true
source_url = https://github.com/nlohmann/json/releases/download/v3.11.3/include.zip
source_filename = nlohmann_json-3.11.3.zip
source_hash = a22461d13119ac5c78f205d3df1db13403e58ce1bb1794edc9313677313f4a9d
patch_url = https://wrapdb.mesonbuild.com/v1/projects/nlohmann_json/3.9.1/1/get_zip
patch_filename = nlohmann_json-3.9.1-1-wrap.zip
patch_hash = 1774e5506fbe3897d652f67e41973194b948d2ab851cf464a742f35f160a1435
[provide]
nlohmann_json = nlohmann_json_dep

View file

@ -1,10 +1,10 @@
[wrap-file]
directory = olm-3.2.16
method = cmake
source_url = https://gitlab.matrix.org/matrix-org/olm/-/archive/3.2.16/olm-3.2.16.tar.gz
source_filename = olm-3.2.16.tar.gz
source_hash = 1e90f9891009965fd064be747616da46b232086fe270b77605ec9bda34272a68
wrapdb_version = 3.2.16-1
[provide]
olm = olm_dep
[wrap-file]
directory = olm-3.2.16
method = cmake
source_url = https://gitlab.matrix.org/matrix-org/olm/-/archive/3.2.16/olm-3.2.16.tar.gz
source_filename = olm-3.2.16.tar.gz
source_hash = 1e90f9891009965fd064be747616da46b232086fe270b77605ec9bda34272a68
wrapdb_version = 3.2.16-1
[provide]
olm = olm_dep

View file

@ -1,15 +1,15 @@
[wrap-file]
directory = openssl-3.0.8
source_url = https://www.openssl.org/source/openssl-3.0.8.tar.gz
source_filename = openssl-3.0.8.tar.gz
source_hash = 6c13d2bf38fdf31eac3ce2a347073673f5d63263398f1f69d0df4a41253e4b3e
patch_filename = openssl_3.0.8-2_patch.zip
patch_url = https://wrapdb.mesonbuild.com/v2/openssl_3.0.8-2/get_patch
patch_hash = e84b5fe469e681e3318184157a0c7c43d4cbacd078bb88f506e31569f8f75072
source_fallback_url = https://github.com/mesonbuild/wrapdb/releases/download/openssl_3.0.8-2/openssl-3.0.8.tar.gz
wrapdb_version = 3.0.8-2
[provide]
libcrypto = libcrypto_dep
libssl = libssl_dep
openssl = openssl_dep
[wrap-file]
directory = openssl-3.0.8
source_url = https://www.openssl.org/source/openssl-3.0.8.tar.gz
source_filename = openssl-3.0.8.tar.gz
source_hash = 6c13d2bf38fdf31eac3ce2a347073673f5d63263398f1f69d0df4a41253e4b3e
patch_filename = openssl_3.0.8-2_patch.zip
patch_url = https://wrapdb.mesonbuild.com/v2/openssl_3.0.8-2/get_patch
patch_hash = e84b5fe469e681e3318184157a0c7c43d4cbacd078bb88f506e31569f8f75072
source_fallback_url = https://github.com/mesonbuild/wrapdb/releases/download/openssl_3.0.8-2/openssl-3.0.8.tar.gz
wrapdb_version = 3.0.8-2
[provide]
libcrypto = libcrypto_dep
libssl = libssl_dep
openssl = openssl_dep

View file

@ -1,4 +1,4 @@
subprojects/*-*
subprojects/packagecache
build
post-image
subprojects/*-*
subprojects/packagecache
build
post-image

View file

@ -1,29 +1,29 @@
project(
'post-image',
'cpp',
version : '"0.1"',
default_options : ['warning_level=3']
)
cc = meson.get_compiler('cpp')
project_source_files = [
'post-image.cpp',
]
project_dependencies = [
dependency('libleet'),
]
build_args = [
'-DVERSION=' + meson.project_version(),
]
project_target = executable(
meson.project_name(),
project_source_files, install : true,
dependencies: project_dependencies,
c_args : build_args,
)
test('post-image', project_target)
project(
'post-image',
'cpp',
version : '"0.1"',
default_options : ['warning_level=3']
)
cc = meson.get_compiler('cpp')
project_source_files = [
'post-image.cpp',
]
project_dependencies = [
dependency('libleet'),
]
build_args = [
'-DVERSION=' + meson.project_version(),
]
project_target = executable(
meson.project_name(),
project_source_files, install : true,
dependencies: project_dependencies,
c_args : build_args,
)
test('post-image', project_target)

View file

@ -1,90 +1,89 @@
#include <iostream>
#include <string>
#include <algorithm>
#include <filesystem>
#include "../../include/libleet.hpp"
#include "../../src/libleet.cpp"
int checkError() {
if (leet::errorCode != 0) {
std::cerr << "Failed. " << leet::friendlyError << " (" << leet::Error << ")\n";
return 1;
}
return 0;
}
int main() {
leet::User::Credentials cred;
cred.Identifier = LEET_IDENTIFIER_USERID;
cred.Type = LEET_TYPE_PASSWORD;
std::cout << "\033[2J\033[1;1H";
std::cout << "Enter a Matrix username (@<username>:<home server>)\n> ";
std::getline(std::cin, cred.Username);
std::cout << "\033[2J\033[1;1H";
std::cout << "Enter a Matrix password\n> ";
std::getline(std::cin, cred.Password);
cred.deviceID = "libleet test client";
cred.Homeserver = leet::returnServerDiscovery(leet::returnHomeServerFromString(cred.Username));
leet::User::credentialsResponse resp;
if (leet::checkIfUsernameIsAvailable(cred.Username)) {
resp = leet::registerAccount(&cred);
} else {
resp = leet::loginAccount(&cred);
}
cred.clearCredentials();
if (checkError() == true) {
return false;
}
leet::transID = leet::returnUnixTimestamp();
std::string myRoom{""};
std::cout << "\033[2J\033[1;1H\n";
std::vector<leet::Room::Room> vector = leet::returnRooms(&resp, 9999);
for (auto& it : vector) {
const std::string Alias = it.Alias.compare("") ? it.Alias : it.roomID;
const std::string Topic = it.Topic.compare("") ? it.Topic : "No room topic specified.";
std::cout << Alias << " - " << Topic << "\n";
}
std::cout << "\n";
std::cout << "Enter a matrix channel:\n> ";
std::getline(std::cin, myRoom);
leet::Room::Room room;
room.roomID = leet::findRoomID(myRoom);
room = leet::returnRoom(&resp, &room);
if (checkError() == true) {
std::cout << "Are you stupid? That isn't a valid channel... I think.\n";
return false;
}
leet::Message::Message msg;
msg.messageText = "test.png";
msg.messageType = "m.image";
leet::Attachment::Attachment attachment = leet::uploadFile(&resp, "test.png");
msg.attachmentURL = attachment.URL;
leet::transID = leet::returnUnixTimestamp();
leet::sendMessage(&resp, &room, &msg);
if (leet::errorCode != 0) {
std::exit(1);
}
}
#include <iostream>
#include <string>
#include <algorithm>
#include <filesystem>
#include <libleet/libleet.hpp>
int checkError() {
if (leet::errorCode != 0) {
std::cerr << "Failed. " << leet::friendlyError << " (" << leet::Error << ")\n";
return 1;
}
return 0;
}
int main() {
leet::User::Credentials cred;
cred.Identifier = LEET_IDENTIFIER_USERID;
cred.Type = LEET_TYPE_PASSWORD;
std::cout << "\033[2J\033[1;1H";
std::cout << "Enter a Matrix username (@<username>:<home server>)\n> ";
std::getline(std::cin, cred.Username);
std::cout << "\033[2J\033[1;1H";
std::cout << "Enter a Matrix password\n> ";
std::getline(std::cin, cred.Password);
cred.deviceID = "libleet test client";
cred.Homeserver = leet::returnServerDiscovery(leet::returnHomeServerFromString(cred.Username));
leet::User::credentialsResponse resp;
if (leet::checkIfUsernameIsAvailable(cred.Username)) {
resp = leet::registerAccount(&cred);
} else {
resp = leet::loginAccount(&cred);
}
cred.clearCredentials();
if (checkError() == true) {
return false;
}
leet::transID = leet::returnUnixTimestamp();
std::string myRoom{""};
std::cout << "\033[2J\033[1;1H\n";
std::vector<leet::Room::Room> vector = leet::returnRooms(&resp, 9999);
for (auto& it : vector) {
const std::string Alias = it.Alias.compare("") ? it.Alias : it.roomID;
const std::string Topic = it.Topic.compare("") ? it.Topic : "No room topic specified.";
std::cout << Alias << " - " << Topic << "\n";
}
std::cout << "\n";
std::cout << "Enter a matrix channel:\n> ";
std::getline(std::cin, myRoom);
leet::Room::Room room;
room.roomID = leet::findRoomID(myRoom);
room = leet::returnRoom(&resp, &room);
if (checkError() == true) {
std::cout << "Are you stupid? That isn't a valid channel... I think.\n";
return false;
}
leet::Message::Message msg;
msg.messageText = "test.png";
msg.messageType = "m.image";
leet::Attachment::Attachment attachment = leet::uploadFile(&resp, "test.png");
msg.attachmentURL = attachment.URL;
leet::transID = leet::returnUnixTimestamp();
leet::sendMessage(&resp, &room, &msg);
if (leet::errorCode != 0) {
std::exit(1);
}
}

View file

@ -1,13 +1,13 @@
[wrap-file]
directory = nlohmann_json-3.11.3
lead_directory_missing = true
source_url = https://github.com/nlohmann/json/releases/download/v3.11.3/include.zip
source_filename = nlohmann_json-3.11.3.zip
source_hash = a22461d13119ac5c78f205d3df1db13403e58ce1bb1794edc9313677313f4a9d
patch_url = https://wrapdb.mesonbuild.com/v1/projects/nlohmann_json/3.9.1/1/get_zip
patch_filename = nlohmann_json-3.9.1-1-wrap.zip
patch_hash = 1774e5506fbe3897d652f67e41973194b948d2ab851cf464a742f35f160a1435
[provide]
nlohmann_json = nlohmann_json_dep
[wrap-file]
directory = nlohmann_json-3.11.3
lead_directory_missing = true
source_url = https://github.com/nlohmann/json/releases/download/v3.11.3/include.zip
source_filename = nlohmann_json-3.11.3.zip
source_hash = a22461d13119ac5c78f205d3df1db13403e58ce1bb1794edc9313677313f4a9d
patch_url = https://wrapdb.mesonbuild.com/v1/projects/nlohmann_json/3.9.1/1/get_zip
patch_filename = nlohmann_json-3.9.1-1-wrap.zip
patch_hash = 1774e5506fbe3897d652f67e41973194b948d2ab851cf464a742f35f160a1435
[provide]
nlohmann_json = nlohmann_json_dep

View file

@ -1,10 +1,10 @@
[wrap-file]
directory = olm-3.2.16
method = cmake
source_url = https://gitlab.matrix.org/matrix-org/olm/-/archive/3.2.16/olm-3.2.16.tar.gz
source_filename = olm-3.2.16.tar.gz
source_hash = 1e90f9891009965fd064be747616da46b232086fe270b77605ec9bda34272a68
wrapdb_version = 3.2.16-1
[provide]
olm = olm_dep
[wrap-file]
directory = olm-3.2.16
method = cmake
source_url = https://gitlab.matrix.org/matrix-org/olm/-/archive/3.2.16/olm-3.2.16.tar.gz
source_filename = olm-3.2.16.tar.gz
source_hash = 1e90f9891009965fd064be747616da46b232086fe270b77605ec9bda34272a68
wrapdb_version = 3.2.16-1
[provide]
olm = olm_dep

View file

@ -1,15 +1,15 @@
[wrap-file]
directory = openssl-3.0.8
source_url = https://www.openssl.org/source/openssl-3.0.8.tar.gz
source_filename = openssl-3.0.8.tar.gz
source_hash = 6c13d2bf38fdf31eac3ce2a347073673f5d63263398f1f69d0df4a41253e4b3e
patch_filename = openssl_3.0.8-2_patch.zip
patch_url = https://wrapdb.mesonbuild.com/v2/openssl_3.0.8-2/get_patch
patch_hash = e84b5fe469e681e3318184157a0c7c43d4cbacd078bb88f506e31569f8f75072
source_fallback_url = https://github.com/mesonbuild/wrapdb/releases/download/openssl_3.0.8-2/openssl-3.0.8.tar.gz
wrapdb_version = 3.0.8-2
[provide]
libcrypto = libcrypto_dep
libssl = libssl_dep
openssl = openssl_dep
[wrap-file]
directory = openssl-3.0.8
source_url = https://www.openssl.org/source/openssl-3.0.8.tar.gz
source_filename = openssl-3.0.8.tar.gz
source_hash = 6c13d2bf38fdf31eac3ce2a347073673f5d63263398f1f69d0df4a41253e4b3e
patch_filename = openssl_3.0.8-2_patch.zip
patch_url = https://wrapdb.mesonbuild.com/v2/openssl_3.0.8-2/get_patch
patch_hash = e84b5fe469e681e3318184157a0c7c43d4cbacd078bb88f506e31569f8f75072
source_fallback_url = https://github.com/mesonbuild/wrapdb/releases/download/openssl_3.0.8-2/openssl-3.0.8.tar.gz
wrapdb_version = 3.0.8-2
[provide]
libcrypto = libcrypto_dep
libssl = libssl_dep
openssl = openssl_dep

View file

@ -1,4 +1,4 @@
subprojects/*-*
subprojects/packagecache
build
rest-api
subprojects/*-*
subprojects/packagecache
build
rest-api

View file

@ -1,31 +1,31 @@
project(
'rest-api',
'cpp',
version : '"0.1"',
default_options : ['warning_level=3']
)
cc = meson.get_compiler('cpp')
project_source_files = [
'rest-api.cpp',
]
project_dependencies = [
dependency('nlohmann_json', fallback : 'nlohmann_json'),
dependency('boost'),
dependency('libleet'),
]
build_args = [
'-DVERSION=' + meson.project_version(),
]
project_target = executable(
meson.project_name(),
project_source_files, install : true,
dependencies: project_dependencies,
c_args : build_args,
)
test('rest-api', project_target)
project(
'rest-api',
'cpp',
version : '"0.1"',
default_options : ['warning_level=3']
)
cc = meson.get_compiler('cpp')
project_source_files = [
'rest-api.cpp',
]
project_dependencies = [
dependency('nlohmann_json', fallback : 'nlohmann_json'),
dependency('boost'),
dependency('libleet'),
]
build_args = [
'-DVERSION=' + meson.project_version(),
]
project_target = executable(
meson.project_name(),
project_source_files, install : true,
dependencies: project_dependencies,
c_args : build_args,
)
test('rest-api', project_target)

View file

@ -1,203 +1,202 @@
#include <iostream>
#include <string>
#include <memory>
#include <vector>
#include <boost/beast/core.hpp>
#include <boost/beast/http.hpp>
#include <boost/asio.hpp>
#include <nlohmann/json.hpp>
#include "../../include/libleet.hpp"
#include "../../src/libleet.cpp"
#include "rest-api.hpp"
const std::string returnRooms(const std::string& Body) {
using json = nlohmann::json;
if (!Body.compare("")) {
json ErrorResponse;
ErrorResponse["error"] = "API_NO_BODY";
return ErrorResponse.dump();
}
json Incoming;
try {
Incoming = { json::parse(Body) };
} catch (const json::parse_error& e) {
json ErrorResponse;
ErrorResponse["error"] = "API_INVALID_UTF8";
return ErrorResponse.dump();
}
leet::User::credentialsResponse resp;
if (json::accept(Body)) {
for (auto& it : Incoming) {
if (it["token"].is_string()) resp.accessToken = it["token"].get<std::string>();
if (it["devid"].is_string()) resp.deviceID = it["devid"].get<std::string>();
if (it["refreshtoken"].is_string()) resp.refreshToken = it["refreshtoken"].get<std::string>();
if (it["userid"].is_string()) resp.userID = it["userid"].get<std::string>();
if (it["homeserver"].is_string()) resp.Homeserver = it["homeserver"].get<std::string>();
}
}
bool Error = false;
std::string theError{""};
if (!resp.accessToken.compare("")) {
Error = true;
theError = "API_NO_ACCESS_TOKEN";
} else if (!resp.deviceID.compare("")) {
Error = true;
theError = "API_NO_DEVICE_ID";
} else if (!resp.userID.compare("")) {
Error = true;
theError = "API_NO_USER_ID";
} else if (!resp.Homeserver.compare("")) {
Error = true;
theError = "API_NO_HOME_SERVER";
}
// return an error
if (Error) {
json ErrorResponse;
ErrorResponse["error"] = theError;
return ErrorResponse.dump();
}
std::vector<leet::Room::Room> vector = leet::returnRooms(&resp, 9999);
if (leet::errorCode != 0 || leet::friendlyError.compare("") || leet::Error.compare("")) {
json ErrorResponse;
ErrorResponse["error"] = "API_FAILED_TO_RETURN_ROOMS";
return ErrorResponse.dump();
}
json roomList;
for (auto& it : vector) {
roomList[it.roomID]["roomid"] = it.roomID;
roomList[it.roomID]["roomtype"] = it.roomType;
roomList[it.roomID]["roomname"] = it.Name;
roomList[it.roomID]["roomavatar"] = it.avatarURL;
roomList[it.roomID]["guestcanjoin"] = it.guestCanJoin;
roomList[it.roomID]["worldreadable"] = it.worldReadable;
roomList[it.roomID]["roomalias"] = it.Alias;
roomList[it.roomID]["roomtopic"] = it.Topic;
roomList[it.roomID]["joinrule"] = it.joinRule;
roomList[it.roomID]["membercount"] = it.memberCount;
}
return roomList.dump();
}
const std::string attemptLogin(const std::string& Body) {
using json = nlohmann::json;
if (!Body.compare("")) {
json ErrorResponse;
ErrorResponse["error"] = "API_NO_BODY";
return ErrorResponse.dump();
}
json Incoming;
try {
Incoming = { json::parse(Body) };
} catch (const json::parse_error& e) {
json ErrorResponse;
ErrorResponse["error"] = "API_INVALID_UTF8";
return ErrorResponse.dump();
}
leet::User::Credentials cred;
if (json::accept(Body)) {
for (auto& output : Incoming) {
if (output["username"].is_string()) cred.Username = output["username"].get<std::string>();
if (output["password"].is_string()) cred.Password = output["password"].get<std::string>();
if (output["devid"].is_string()) cred.deviceID = output["devid"].get<std::string>();
}
}
cred.Homeserver = leet::Homeserver;
bool Error = false;
std::string theError{""};
if (!cred.Username.compare("")) {
Error = true;
theError = "API_NO_USERNAME";
} else if (!cred.Password.compare("")) {
Error = true;
theError = "API_NO_PASSWORD";
}
if (Error) {
json ErrorResponse;
ErrorResponse["error"] = theError;
return ErrorResponse.dump();
}
if (!cred.Username.compare("")) {
cred.Homeserver = leet::returnServerDiscovery(leet::returnHomeServerFromString(cred.Username));
}
leet::User::credentialsResponse resp;
resp = leet::loginAccount(&cred);
json jsonResponse;
if (leet::errorCode != 0 || leet::Error.compare("")) {
jsonResponse["error"] = leet::Error;
jsonResponse["friendlyerror"] = leet::friendlyError;
} else {
jsonResponse["token"] = resp.accessToken;
jsonResponse["refreshtoken"] = resp.refreshToken;
jsonResponse["devid"] = resp.deviceID;
jsonResponse["homeserver"] = resp.Homeserver;
jsonResponse["userid"] = resp.userID;
jsonResponse["expiration"] = resp.Expiration;
}
return jsonResponse.dump();
}
const std::string generateResponseFromEndpoint(const std::string& Endpoint, const std::string& Body) {
using json = nlohmann::json;
if (!Endpoint.compare("")) {
json ErrorResponse;
ErrorResponse["error"] = "API_NO_ENDPOINT_SPECIFIED";
return ErrorResponse.dump();
} else if (!Endpoint.compare("/api/login")) { // login
return attemptLogin(Body);
} else if (!Endpoint.compare("/api/return_rooms")) { // return rooms
return returnRooms(Body);
} else {
json ErrorResponse;
ErrorResponse["error"] = "API_INVALID_ENDPOINT_SPECIFIED";
return ErrorResponse.dump();
}
return "";
}
int main() {
constexpr int Port = 8080;
try {
boost::asio::io_context ioc;
boost::asio::ip::tcp::endpoint Endpoint(boost::asio::ip::tcp::v4(), Port);
std::cerr << "[NOTICE]: rest-api backend is running on port " << Port << ".\n";
Listener listener(ioc, Endpoint);
listener.Run();
ioc.run();
} catch (const std::exception& e) {
std::cerr << "Exception: " << e.what() << "\n";
main();
}
return 0;
}
#include <iostream>
#include <string>
#include <memory>
#include <vector>
#include <boost/beast/core.hpp>
#include <boost/beast/http.hpp>
#include <boost/asio.hpp>
#include <nlohmann/json.hpp>
#include <libleet/libleet.hpp>
#include "rest-api.hpp"
const std::string returnRooms(const std::string& Body) {
using json = nlohmann::json;
if (!Body.compare("")) {
json ErrorResponse;
ErrorResponse["error"] = "API_NO_BODY";
return ErrorResponse.dump();
}
json Incoming;
try {
Incoming = { json::parse(Body) };
} catch (const json::parse_error& e) {
json ErrorResponse;
ErrorResponse["error"] = "API_INVALID_UTF8";
return ErrorResponse.dump();
}
leet::User::credentialsResponse resp;
if (json::accept(Body)) {
for (auto& it : Incoming) {
if (it["token"].is_string()) resp.accessToken = it["token"].get<std::string>();
if (it["devid"].is_string()) resp.deviceID = it["devid"].get<std::string>();
if (it["refreshtoken"].is_string()) resp.refreshToken = it["refreshtoken"].get<std::string>();
if (it["userid"].is_string()) resp.userID = it["userid"].get<std::string>();
if (it["homeserver"].is_string()) resp.Homeserver = it["homeserver"].get<std::string>();
}
}
bool Error = false;
std::string theError{""};
if (!resp.accessToken.compare("")) {
Error = true;
theError = "API_NO_ACCESS_TOKEN";
} else if (!resp.deviceID.compare("")) {
Error = true;
theError = "API_NO_DEVICE_ID";
} else if (!resp.userID.compare("")) {
Error = true;
theError = "API_NO_USER_ID";
} else if (!resp.Homeserver.compare("")) {
Error = true;
theError = "API_NO_HOME_SERVER";
}
// return an error
if (Error) {
json ErrorResponse;
ErrorResponse["error"] = theError;
return ErrorResponse.dump();
}
std::vector<leet::Room::Room> vector = leet::returnRooms(&resp, 9999);
if (leet::errorCode != 0 || leet::friendlyError.compare("") || leet::Error.compare("")) {
json ErrorResponse;
ErrorResponse["error"] = "API_FAILED_TO_RETURN_ROOMS";
return ErrorResponse.dump();
}
json roomList;
for (auto& it : vector) {
roomList[it.roomID]["roomid"] = it.roomID;
roomList[it.roomID]["roomtype"] = it.roomType;
roomList[it.roomID]["roomname"] = it.Name;
roomList[it.roomID]["roomavatar"] = it.avatarURL;
roomList[it.roomID]["guestcanjoin"] = it.guestCanJoin;
roomList[it.roomID]["worldreadable"] = it.worldReadable;
roomList[it.roomID]["roomalias"] = it.Alias;
roomList[it.roomID]["roomtopic"] = it.Topic;
roomList[it.roomID]["joinrule"] = it.joinRule;
roomList[it.roomID]["membercount"] = it.memberCount;
}
return roomList.dump();
}
const std::string attemptLogin(const std::string& Body) {
using json = nlohmann::json;
if (!Body.compare("")) {
json ErrorResponse;
ErrorResponse["error"] = "API_NO_BODY";
return ErrorResponse.dump();
}
json Incoming;
try {
Incoming = { json::parse(Body) };
} catch (const json::parse_error& e) {
json ErrorResponse;
ErrorResponse["error"] = "API_INVALID_UTF8";
return ErrorResponse.dump();
}
leet::User::Credentials cred;
if (json::accept(Body)) {
for (auto& output : Incoming) {
if (output["username"].is_string()) cred.Username = output["username"].get<std::string>();
if (output["password"].is_string()) cred.Password = output["password"].get<std::string>();
if (output["devid"].is_string()) cred.deviceID = output["devid"].get<std::string>();
}
}
cred.Homeserver = leet::Homeserver;
bool Error = false;
std::string theError{""};
if (!cred.Username.compare("")) {
Error = true;
theError = "API_NO_USERNAME";
} else if (!cred.Password.compare("")) {
Error = true;
theError = "API_NO_PASSWORD";
}
if (Error) {
json ErrorResponse;
ErrorResponse["error"] = theError;
return ErrorResponse.dump();
}
if (!cred.Username.compare("")) {
cred.Homeserver = leet::returnServerDiscovery(leet::returnHomeServerFromString(cred.Username));
}
leet::User::credentialsResponse resp;
resp = leet::loginAccount(&cred);
json jsonResponse;
if (leet::errorCode != 0 || leet::Error.compare("")) {
jsonResponse["error"] = leet::Error;
jsonResponse["friendlyerror"] = leet::friendlyError;
} else {
jsonResponse["token"] = resp.accessToken;
jsonResponse["refreshtoken"] = resp.refreshToken;
jsonResponse["devid"] = resp.deviceID;
jsonResponse["homeserver"] = resp.Homeserver;
jsonResponse["userid"] = resp.userID;
jsonResponse["expiration"] = resp.Expiration;
}
return jsonResponse.dump();
}
const std::string generateResponseFromEndpoint(const std::string& Endpoint, const std::string& Body) {
using json = nlohmann::json;
if (!Endpoint.compare("")) {
json ErrorResponse;
ErrorResponse["error"] = "API_NO_ENDPOINT_SPECIFIED";
return ErrorResponse.dump();
} else if (!Endpoint.compare("/api/login")) { // login
return attemptLogin(Body);
} else if (!Endpoint.compare("/api/return_rooms")) { // return rooms
return returnRooms(Body);
} else {
json ErrorResponse;
ErrorResponse["error"] = "API_INVALID_ENDPOINT_SPECIFIED";
return ErrorResponse.dump();
}
return "";
}
int main() {
constexpr int Port = 8080;
try {
boost::asio::io_context ioc;
boost::asio::ip::tcp::endpoint Endpoint(boost::asio::ip::tcp::v4(), Port);
std::cerr << "[NOTICE]: rest-api backend is running on port " << Port << ".\n";
Listener listener(ioc, Endpoint);
listener.Run();
ioc.run();
} catch (const std::exception& e) {
std::cerr << "Exception: " << e.what() << "\n";
main();
}
return 0;
}

View file

@ -1,90 +1,90 @@
const std::string generateResponseFromEndpoint(const std::string& Endpoint, const std::string& Body);
class Session : public std::enable_shared_from_this<Session> {
public:
explicit Session(boost::asio::ip::tcp::socket Socket) : exampleAPISocket(std::move(Socket)) {}
void Start() {
readRequest();
}
private:
boost::asio::ip::tcp::socket exampleAPISocket;
boost::beast::flat_buffer exampleAPIBuffer;
boost::beast::http::request<boost::beast::http::string_body> exampleAPIRequest;
boost::beast::http::response<boost::beast::http::string_body> exampleAPIResponse;
void readRequest() {
auto self = shared_from_this();
boost::beast::http::async_read(
exampleAPISocket,
exampleAPIBuffer,
exampleAPIRequest,
[self](boost::beast::error_code ec, std::size_t transferredBytes) {
self->onRead(ec, transferredBytes);
}
);
}
void onRead(boost::beast::error_code ec, std::size_t transferredBytes) {
if (!ec) {
handleReq();
}
}
void handleReq() {
if (exampleAPIRequest.method() == boost::beast::http::verb::options) {
exampleAPIResponse.result(boost::beast::http::status::no_content);
exampleAPIResponse.set(boost::beast::http::field::allow, "GET, HEAD, OPTIONS");
exampleAPIResponse.set(boost::beast::http::field::access_control_allow_origin, "*");
exampleAPIResponse.set(boost::beast::http::field::access_control_allow_headers, "Content-Type");
} else {
std::string json_response = generateResponseFromEndpoint(exampleAPIRequest.target(), exampleAPIRequest.body());
exampleAPIResponse.result(boost::beast::http::status::ok);
exampleAPIResponse.set(boost::beast::http::field::content_type, "application/json");
exampleAPIResponse.set(boost::beast::http::field::access_control_allow_origin, "*");
exampleAPIResponse.body() = std::move(json_response);
}
auto self = shared_from_this();
boost::beast::http::async_write(
exampleAPISocket,
exampleAPIResponse,
[self](boost::beast::error_code ec, std::size_t transferredBytes) {
self->onWrite(ec);
}
);
}
void onWrite(boost::beast::error_code ec) {
if (!ec) {
boost::beast::error_code close_ec;
exampleAPISocket.shutdown(boost::asio::ip::tcp::socket::shutdown_send, close_ec);
}
}
};
class Listener {
public:
explicit Listener(boost::asio::io_context& ioc, boost::asio::ip::tcp::endpoint Endpoint)
: apiIoc(ioc), apiAcceptor(ioc, Endpoint) {}
void Run() {
acceptReq();
}
private:
boost::asio::io_context& apiIoc;
boost::asio::ip::tcp::acceptor apiAcceptor;
void acceptReq() {
apiAcceptor.async_accept(
[this](boost::beast::error_code ec, boost::asio::ip::tcp::socket Socket) {
if (!ec) {
std::make_shared<Session>(std::move(Socket))->Start();
}
acceptReq();
}
);
}
};
const std::string generateResponseFromEndpoint(const std::string& Endpoint, const std::string& Body);
class Session : public std::enable_shared_from_this<Session> {
public:
explicit Session(boost::asio::ip::tcp::socket Socket) : exampleAPISocket(std::move(Socket)) {}
void Start() {
readRequest();
}
private:
boost::asio::ip::tcp::socket exampleAPISocket;
boost::beast::flat_buffer exampleAPIBuffer;
boost::beast::http::request<boost::beast::http::string_body> exampleAPIRequest;
boost::beast::http::response<boost::beast::http::string_body> exampleAPIResponse;
void readRequest() {
auto self = shared_from_this();
boost::beast::http::async_read(
exampleAPISocket,
exampleAPIBuffer,
exampleAPIRequest,
[self](boost::beast::error_code ec, std::size_t transferredBytes) {
self->onRead(ec, transferredBytes);
}
);
}
void onRead(boost::beast::error_code ec, std::size_t transferredBytes) {
if (!ec) {
handleReq();
}
}
void handleReq() {
if (exampleAPIRequest.method() == boost::beast::http::verb::options) {
exampleAPIResponse.result(boost::beast::http::status::no_content);
exampleAPIResponse.set(boost::beast::http::field::allow, "GET, HEAD, OPTIONS");
exampleAPIResponse.set(boost::beast::http::field::access_control_allow_origin, "*");
exampleAPIResponse.set(boost::beast::http::field::access_control_allow_headers, "Content-Type");
} else {
std::string json_response = generateResponseFromEndpoint(exampleAPIRequest.target(), exampleAPIRequest.body());
exampleAPIResponse.result(boost::beast::http::status::ok);
exampleAPIResponse.set(boost::beast::http::field::content_type, "application/json");
exampleAPIResponse.set(boost::beast::http::field::access_control_allow_origin, "*");
exampleAPIResponse.body() = std::move(json_response);
}
auto self = shared_from_this();
boost::beast::http::async_write(
exampleAPISocket,
exampleAPIResponse,
[self](boost::beast::error_code ec, std::size_t transferredBytes) {
self->onWrite(ec);
}
);
}
void onWrite(boost::beast::error_code ec) {
if (!ec) {
boost::beast::error_code close_ec;
exampleAPISocket.shutdown(boost::asio::ip::tcp::socket::shutdown_send, close_ec);
}
}
};
class Listener {
public:
explicit Listener(boost::asio::io_context& ioc, boost::asio::ip::tcp::endpoint Endpoint)
: apiIoc(ioc), apiAcceptor(ioc, Endpoint) {}
void Run() {
acceptReq();
}
private:
boost::asio::io_context& apiIoc;
boost::asio::ip::tcp::acceptor apiAcceptor;
void acceptReq() {
apiAcceptor.async_accept(
[this](boost::beast::error_code ec, boost::asio::ip::tcp::socket Socket) {
if (!ec) {
std::make_shared<Session>(std::move(Socket))->Start();
}
acceptReq();
}
);
}
};

View file

@ -1,13 +1,13 @@
[wrap-file]
directory = nlohmann_json-3.11.3
lead_directory_missing = true
source_url = https://github.com/nlohmann/json/releases/download/v3.11.3/include.zip
source_filename = nlohmann_json-3.11.3.zip
source_hash = a22461d13119ac5c78f205d3df1db13403e58ce1bb1794edc9313677313f4a9d
patch_url = https://wrapdb.mesonbuild.com/v1/projects/nlohmann_json/3.9.1/1/get_zip
patch_filename = nlohmann_json-3.9.1-1-wrap.zip
patch_hash = 1774e5506fbe3897d652f67e41973194b948d2ab851cf464a742f35f160a1435
[provide]
nlohmann_json = nlohmann_json_dep
[wrap-file]
directory = nlohmann_json-3.11.3
lead_directory_missing = true
source_url = https://github.com/nlohmann/json/releases/download/v3.11.3/include.zip
source_filename = nlohmann_json-3.11.3.zip
source_hash = a22461d13119ac5c78f205d3df1db13403e58ce1bb1794edc9313677313f4a9d
patch_url = https://wrapdb.mesonbuild.com/v1/projects/nlohmann_json/3.9.1/1/get_zip
patch_filename = nlohmann_json-3.9.1-1-wrap.zip
patch_hash = 1774e5506fbe3897d652f67e41973194b948d2ab851cf464a742f35f160a1435
[provide]
nlohmann_json = nlohmann_json_dep

View file

@ -1,10 +1,10 @@
[wrap-file]
directory = olm-3.2.16
method = cmake
source_url = https://gitlab.matrix.org/matrix-org/olm/-/archive/3.2.16/olm-3.2.16.tar.gz
source_filename = olm-3.2.16.tar.gz
source_hash = 1e90f9891009965fd064be747616da46b232086fe270b77605ec9bda34272a68
wrapdb_version = 3.2.16-1
[provide]
olm = olm_dep
[wrap-file]
directory = olm-3.2.16
method = cmake
source_url = https://gitlab.matrix.org/matrix-org/olm/-/archive/3.2.16/olm-3.2.16.tar.gz
source_filename = olm-3.2.16.tar.gz
source_hash = 1e90f9891009965fd064be747616da46b232086fe270b77605ec9bda34272a68
wrapdb_version = 3.2.16-1
[provide]
olm = olm_dep

View file

@ -1,15 +1,15 @@
[wrap-file]
directory = openssl-3.0.8
source_url = https://www.openssl.org/source/openssl-3.0.8.tar.gz
source_filename = openssl-3.0.8.tar.gz
source_hash = 6c13d2bf38fdf31eac3ce2a347073673f5d63263398f1f69d0df4a41253e4b3e
patch_filename = openssl_3.0.8-2_patch.zip
patch_url = https://wrapdb.mesonbuild.com/v2/openssl_3.0.8-2/get_patch
patch_hash = e84b5fe469e681e3318184157a0c7c43d4cbacd078bb88f506e31569f8f75072
source_fallback_url = https://github.com/mesonbuild/wrapdb/releases/download/openssl_3.0.8-2/openssl-3.0.8.tar.gz
wrapdb_version = 3.0.8-2
[provide]
libcrypto = libcrypto_dep
libssl = libssl_dep
openssl = openssl_dep
[wrap-file]
directory = openssl-3.0.8
source_url = https://www.openssl.org/source/openssl-3.0.8.tar.gz
source_filename = openssl-3.0.8.tar.gz
source_hash = 6c13d2bf38fdf31eac3ce2a347073673f5d63263398f1f69d0df4a41253e4b3e
patch_filename = openssl_3.0.8-2_patch.zip
patch_url = https://wrapdb.mesonbuild.com/v2/openssl_3.0.8-2/get_patch
patch_hash = e84b5fe469e681e3318184157a0c7c43d4cbacd078bb88f506e31569f8f75072
source_fallback_url = https://github.com/mesonbuild/wrapdb/releases/download/openssl_3.0.8-2/openssl-3.0.8.tar.gz
wrapdb_version = 3.0.8-2
[provide]
libcrypto = libcrypto_dep
libssl = libssl_dep
openssl = openssl_dep

File diff suppressed because it is too large Load diff

View file

@ -1,122 +1,122 @@
/* libleet
* Matrix client library written in C++
* Licensed under the GNU Affero General Public License version 3.
* See included LICENSE file for more information.
*
* https://git.speedie.site/speedie/libleet
*/
#ifndef REQUEST_HPP
#define REQUEST_HPP
#include <iostream>
#include <string>
#include <boost/beast/core.hpp>
#include <boost/beast/http.hpp>
#include <boost/beast/version.hpp>
#include <boost/beast/ssl.hpp>
#include <boost/asio/connect.hpp>
#include <boost/asio/ip/tcp.hpp>
#include <boost/asio/ssl/error.hpp>
#include <boost/asio/ssl/stream.hpp>
#include <boost/asio/ssl/rfc2818_verification.hpp>
#include <boost/asio/ssl/host_name_verification.hpp>
#include <openssl/ssl.h>
namespace leetRequest {
enum { /* supported protocols */
LEET_REQUEST_PROTOCOL_HTTP,
LEET_REQUEST_PROTOCOL_HTTPS,
};
enum { /* types of supported request types */
LEET_REQUEST_REQTYPE_GET,
LEET_REQUEST_REQTYPE_POST,
LEET_REQUEST_REQTYPE_PUT,
};
/**
* @brief Class representing a parsed URL
*/
class URL { /* useful for parsing a URL */
private:
public:
std::string Host{};
std::string Endpoint{};
std::string Query{};
int Protocol{LEET_REQUEST_PROTOCOL_HTTP};
int Port{80};
/**
* @brief Separate the components of a URL in the form of a string
* @param URL The URL to parse. The components can be accessed from the URL object.
*/
void parseURLFromString(const std::string& URL);
/**
* @brief Assemble a URL from specified parts
* @return Returns a full URL based on the parts
*/
const std::string assembleURLFromParts();
};
/**
* @brief Class representing the response after making a network request
*/
class Response { /* the response */
private:
public:
int statusCode{200};
std::string Body{};
};
/**
* @brief Class representing a network request
*/
class Request { /* the request */
private:
public:
std::string Host{};
std::string Endpoint{};
std::string Query{};
std::string userAgent{"LIBLEET_USER_AGENT"};
std::string Body{};
int Port{80};
int Protocol{LEET_REQUEST_PROTOCOL_HTTP};
int Type{LEET_REQUEST_REQTYPE_GET};
std::vector<std::string> headerName{};
std::vector<std::string> headerData{};
std::string authenticationHeaderData{};
std::string contentTypeHeaderData{};
bool Authentication{false};
std::string Filename{};
std::string outputFile{};
/**
* @brief Set an HTTP header
* @param Header The header to set
* @param Data The data to set the header to
*/
void setHeader(const std::string& Header, const std::string& Data);
/**
* @brief Set the Authentication header
* @param Data The data to set the header to
*/
void setAuthenticationHeader(const std::string& Data);
/**
* @brief Set the Content-Type header
* @param Data The data to set the header to
*/
void setContentTypeHeader(const std::string& Data);
/**
* @brief Make a network request
* @return Returns a Response object
*/
Response makeRequest();
const bool downloadFile();
};
std::string userCert{}; // User-specified root certificate string
const std::string getRootCertificates();
void applyRootCertificates(boost::asio::ssl::context& ctx, const std::string& cert);
}
#endif
/* libleet
* Matrix client library written in C++
* Licensed under the GNU Affero General Public License version 3.
* See included LICENSE file for more information.
*
* https://git.speedie.site/speedie/libleet
*/
#ifndef REQUEST_HPP
#define REQUEST_HPP
#include <iostream>
#include <string>
#include <boost/beast/core.hpp>
#include <boost/beast/http.hpp>
#include <boost/beast/version.hpp>
#include <boost/beast/ssl.hpp>
#include <boost/asio/connect.hpp>
#include <boost/asio/ip/tcp.hpp>
#include <boost/asio/ssl/error.hpp>
#include <boost/asio/ssl/stream.hpp>
#include <boost/asio/ssl/rfc2818_verification.hpp>
#include <boost/asio/ssl/host_name_verification.hpp>
#include <openssl/ssl.h>
namespace leetRequest {
enum { /* supported protocols */
LEET_REQUEST_PROTOCOL_HTTP,
LEET_REQUEST_PROTOCOL_HTTPS,
};
enum { /* types of supported request types */
LEET_REQUEST_REQTYPE_GET,
LEET_REQUEST_REQTYPE_POST,
LEET_REQUEST_REQTYPE_PUT,
};
/**
* @brief Class representing a parsed URL
*/
class URL { /* useful for parsing a URL */
private:
public:
std::string Host{};
std::string Endpoint{};
std::string Query{};
int Protocol{LEET_REQUEST_PROTOCOL_HTTP};
int Port{80};
/**
* @brief Separate the components of a URL in the form of a string
* @param URL The URL to parse. The components can be accessed from the URL object.
*/
void parseURLFromString(const std::string& URL);
/**
* @brief Assemble a URL from specified parts
* @return Returns a full URL based on the parts
*/
const std::string assembleURLFromParts();
};
/**
* @brief Class representing the response after making a network request
*/
class Response { /* the response */
private:
public:
int statusCode{200};
std::string Body{};
};
/**
* @brief Class representing a network request
*/
class Request { /* the request */
private:
public:
std::string Host{};
std::string Endpoint{};
std::string Query{};
std::string userAgent{"LIBLEET_USER_AGENT"};
std::string Body{};
int Port{80};
int Protocol{LEET_REQUEST_PROTOCOL_HTTP};
int Type{LEET_REQUEST_REQTYPE_GET};
std::vector<std::string> headerName{};
std::vector<std::string> headerData{};
std::string authenticationHeaderData{};
std::string contentTypeHeaderData{};
bool Authentication{false};
std::string Filename{};
std::string outputFile{};
/**
* @brief Set an HTTP header
* @param Header The header to set
* @param Data The data to set the header to
*/
void setHeader(const std::string& Header, const std::string& Data);
/**
* @brief Set the Authentication header
* @param Data The data to set the header to
*/
void setAuthenticationHeader(const std::string& Data);
/**
* @brief Set the Content-Type header
* @param Data The data to set the header to
*/
void setContentTypeHeader(const std::string& Data);
/**
* @brief Make a network request
* @return Returns a Response object
*/
Response makeRequest();
const bool downloadFile();
};
std::string userCert{}; // User-specified root certificate string
const std::string getRootCertificates();
void applyRootCertificates(boost::asio::ssl::context& ctx, const std::string& cert);
}
#endif

View file

@ -1,5 +1,7 @@
<?xml version="1.0" encoding="utf-8"?>
<Project DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<Import Project="packages\rmt_openssl.1.1.0.3\build\native\rmt_openssl.props" Condition="Exists('packages\rmt_openssl.1.1.0.3\build\native\rmt_openssl.props')" />
<Import Project="packages\rmt_zlib.1.2.8.7\build\native\rmt_zlib.props" Condition="Exists('packages\rmt_zlib.1.2.8.7\build\native\rmt_zlib.props')" />
<ItemGroup Label="ProjectConfigurations">
<ProjectConfiguration Include="Debug|Win32">
<Configuration>Debug</Configuration>
@ -40,7 +42,7 @@
<CharacterSet>Unicode</CharacterSet>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'" Label="Configuration">
<ConfigurationType>Application</ConfigurationType>
<ConfigurationType>DynamicLibrary</ConfigurationType>
<UseDebugLibraries>true</UseDebugLibraries>
<PlatformToolset>v143</PlatformToolset>
<CharacterSet>Unicode</CharacterSet>
@ -70,6 +72,9 @@
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
</ImportGroup>
<PropertyGroup Label="UserMacros" />
<PropertyGroup Label="Vcpkg">
<VcpkgEnabled>false</VcpkgEnabled>
</PropertyGroup>
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
<ClCompile>
<WarningLevel>Level3</WarningLevel>
@ -80,6 +85,7 @@
<Link>
<SubSystem>Console</SubSystem>
<GenerateDebugInformation>true</GenerateDebugInformation>
<ModuleDefinitionFile>Source.def</ModuleDefinitionFile>
</Link>
</ItemDefinitionGroup>
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
@ -96,6 +102,7 @@
<EnableCOMDATFolding>true</EnableCOMDATFolding>
<OptimizeReferences>true</OptimizeReferences>
<GenerateDebugInformation>true</GenerateDebugInformation>
<ModuleDefinitionFile>Source.def</ModuleDefinitionFile>
</Link>
</ItemDefinitionGroup>
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
@ -104,10 +111,16 @@
<SDLCheck>true</SDLCheck>
<PreprocessorDefinitions>_DEBUG;_CONSOLE;%(PreprocessorDefinitions)</PreprocessorDefinitions>
<ConformanceMode>true</ConformanceMode>
<LanguageStandard>stdcpp20</LanguageStandard>
<Optimization>Disabled</Optimization>
<AdditionalIncludeDirectories>windows-olm\include</AdditionalIncludeDirectories>
</ClCompile>
<Link>
<SubSystem>Console</SubSystem>
<GenerateDebugInformation>true</GenerateDebugInformation>
<ModuleDefinitionFile>Source.def</ModuleDefinitionFile>
<AdditionalLibraryDirectories>windows-olm\lib</AdditionalLibraryDirectories>
<AdditionalDependencies>$(CoreLibraryDependencies);%(AdditionalDependencies);olm.lib</AdditionalDependencies>
</Link>
</ItemDefinitionGroup>
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
@ -118,40 +131,49 @@
<SDLCheck>true</SDLCheck>
<PreprocessorDefinitions>NDEBUG;_CONSOLE;%(PreprocessorDefinitions)</PreprocessorDefinitions>
<ConformanceMode>true</ConformanceMode>
<LanguageStandard>stdcpp20</LanguageStandard>
<AdditionalIncludeDirectories>windows-olm\include</AdditionalIncludeDirectories>
</ClCompile>
<Link>
<SubSystem>Console</SubSystem>
<EnableCOMDATFolding>true</EnableCOMDATFolding>
<OptimizeReferences>true</OptimizeReferences>
<GenerateDebugInformation>true</GenerateDebugInformation>
<ModuleDefinitionFile>Source.def</ModuleDefinitionFile>
<AdditionalLibraryDirectories>windows-olm\lib</AdditionalLibraryDirectories>
<AdditionalDependencies>$(CoreLibraryDependencies);%(AdditionalDependencies);olm.lib</AdditionalDependencies>
</Link>
</ItemDefinitionGroup>
<ItemGroup>
<ClCompile Include="src/libleet.cpp" />
<ClCompile Include="src\Encryption.cpp" />
<ClCompile Include="src\Event.cpp" />
<ClCompile Include="src\File.cpp" />
<ClCompile Include="src\Login.cpp" />
<ClCompile Include="src\Message.cpp" />
<ClCompile Include="src\Request.cpp" />
<ClCompile Include="src\Room.cpp" />
<ClCompile Include="src\User.cpp" />
<ClCompile Include="src\Voip.cpp" />
</ItemGroup>
<ItemGroup>
<ClInclude Include="include\libleet.hpp" />
<ClCompile Include="src\libleet.cpp" />
</ItemGroup>
<ItemGroup>
<None Include=".gitignore" />
<None Include="docs\Doxyfile" />
<None Include="docs\index.css" />
<None Include="LICENSE" />
<None Include="meson.build" />
<None Include="packages.config" />
<None Include="README.md" />
</ItemGroup>
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" />
<ImportGroup Label="ExtensionTargets">
<Import Project="packages\nlohmann.json.3.11.2\build\native\nlohmann.json.targets" Condition="Exists('packages\nlohmann.json.3.11.2\build\native\nlohmann.json.targets')" />
<Import Project="packages\boost.1.83.0\build\boost.targets" Condition="Exists('packages\boost.1.83.0\build\boost.targets')" />
<Import Project="packages\rmt_zlib.1.2.8.7\build\native\rmt_zlib.targets" Condition="Exists('packages\rmt_zlib.1.2.8.7\build\native\rmt_zlib.targets')" />
<Import Project="packages\rmt_openssl.1.1.0.3\build\native\rmt_openssl.targets" Condition="Exists('packages\rmt_openssl.1.1.0.3\build\native\rmt_openssl.targets')" />
<Import Project="packages\openssl-vc141-static-x86_64.1.1.0\build\native\openssl-vc141-static-x86_64.targets" Condition="Exists('packages\openssl-vc141-static-x86_64.1.1.0\build\native\openssl-vc141-static-x86_64.targets')" />
</ImportGroup>
<Target Name="EnsureNuGetPackageBuildImports" BeforeTargets="PrepareForBuild">
<PropertyGroup>
<ErrorText>This project references NuGet package(s) that are missing on this computer. Use NuGet Package Restore to download them. For more information, see http://go.microsoft.com/fwlink/?LinkID=322105. The missing file is {0}.</ErrorText>
</PropertyGroup>
<Error Condition="!Exists('packages\nlohmann.json.3.11.2\build\native\nlohmann.json.targets')" Text="$([System.String]::Format('$(ErrorText)', 'packages\nlohmann.json.3.11.2\build\native\nlohmann.json.targets'))" />
<Error Condition="!Exists('packages\boost.1.83.0\build\boost.targets')" Text="$([System.String]::Format('$(ErrorText)', 'packages\boost.1.83.0\build\boost.targets'))" />
<Error Condition="!Exists('packages\rmt_zlib.1.2.8.7\build\native\rmt_zlib.props')" Text="$([System.String]::Format('$(ErrorText)', 'packages\rmt_zlib.1.2.8.7\build\native\rmt_zlib.props'))" />
<Error Condition="!Exists('packages\rmt_zlib.1.2.8.7\build\native\rmt_zlib.targets')" Text="$([System.String]::Format('$(ErrorText)', 'packages\rmt_zlib.1.2.8.7\build\native\rmt_zlib.targets'))" />
<Error Condition="!Exists('packages\rmt_openssl.1.1.0.3\build\native\rmt_openssl.props')" Text="$([System.String]::Format('$(ErrorText)', 'packages\rmt_openssl.1.1.0.3\build\native\rmt_openssl.props'))" />
<Error Condition="!Exists('packages\rmt_openssl.1.1.0.3\build\native\rmt_openssl.targets')" Text="$([System.String]::Format('$(ErrorText)', 'packages\rmt_openssl.1.1.0.3\build\native\rmt_openssl.targets'))" />
<Error Condition="!Exists('packages\openssl-vc141-static-x86_64.1.1.0\build\native\openssl-vc141-static-x86_64.targets')" Text="$([System.String]::Format('$(ErrorText)', 'packages\openssl-vc141-static-x86_64.1.1.0\build\native\openssl-vc141-static-x86_64.targets'))" />
</Target>
</Project>

View file

@ -15,43 +15,17 @@
</Filter>
</ItemGroup>
<ItemGroup>
<ClCompile Include="src/libleet.cpp">
<ClCompile Include="src\libleet.cpp">
<Filter>Source Files</Filter>
</ClCompile>
<ClCompile Include="src\Encryption.cpp">
<Filter>Source Files</Filter>
</ClCompile>
<ClCompile Include="src\Event.cpp">
<Filter>Source Files</Filter>
</ClCompile>
<ClCompile Include="src\File.cpp">
<Filter>Source Files</Filter>
</ClCompile>
<ClCompile Include="src\Login.cpp">
<Filter>Source Files</Filter>
</ClCompile>
<ClCompile Include="src\Message.cpp">
<Filter>Source Files</Filter>
</ClCompile>
<ClCompile Include="src\Request.cpp">
<Filter>Source Files</Filter>
</ClCompile>
<ClCompile Include="src\Room.cpp">
<Filter>Source Files</Filter>
</ClCompile>
<ClCompile Include="src\User.cpp">
<Filter>Source Files</Filter>
</ClCompile>
<ClCompile Include="src\Voip.cpp">
<Filter>Source Files</Filter>
</ClCompile>
</ItemGroup>
<ItemGroup>
<ClInclude Include="include\libleet.hpp">
<Filter>Header Files</Filter>
</ClInclude>
</ItemGroup>
<ItemGroup>
<None Include="packages.config" />
<None Include="README.md" />
<None Include="meson.build" />
<None Include=".gitignore" />
<None Include="LICENSE" />
<None Include="docs\Doxyfile" />
<None Include="docs\index.css" />
</ItemGroup>
</Project>

View file

@ -1,44 +1,44 @@
project(
'libleet',
'cpp',
version : '0.1',
license : 'AGPL',
)
cc = meson.get_compiler('cpp')
project_source_files = [
'src/libleet.cpp',
]
project_dependencies = [
dependency('nlohmann_json', fallback : 'nlohmann_json'),
dependency('openssl', fallback : 'openssl'),
dependency('olm', fallback : 'olm'),
dependency('boost'),
]
build_args = [
'-DLLEET_VERSION=' + meson.project_version(),
]
so_version = meson.project_version()
install_headers('include/libleet.hpp', subdir : 'libleet')
install_headers('include/net/Request.hpp', subdir : 'libleet')
lib = static_library('leet',
project_source_files,
dependencies : project_dependencies,
install : true
)
lib_shared = shared_library('leet',
project_source_files,
dependencies : project_dependencies,
version : so_version,
install : true
)
pkgconfig = import('pkgconfig')
pkgconfig.generate(libraries : '-lleet', subdirs : 'libleet', version : so_version, name : meson.project_name(), filebase : meson.project_name(), description : 'Matrix client library')
project(
'libleet',
'cpp',
version : '0.1',
license : 'AGPL',
)
cc = meson.get_compiler('cpp')
project_source_files = [
'src/libleet.cpp',
]
project_dependencies = [
dependency('nlohmann_json', fallback : 'nlohmann_json'),
dependency('openssl', fallback : 'openssl'),
dependency('olm', fallback : 'olm'),
dependency('boost'),
]
build_args = [
'-DLLEET_VERSION=' + meson.project_version(),
]
so_version = meson.project_version()
install_headers('include/libleet.hpp', subdir : 'libleet')
install_headers('include/net/Request.hpp', subdir : 'libleet')
lib = static_library('leet',
project_source_files,
dependencies : project_dependencies,
install : true
)
lib_shared = shared_library('leet',
project_source_files,
dependencies : project_dependencies,
version : so_version,
install : true
)
pkgconfig = import('pkgconfig')
pkgconfig.generate(libraries : '-lleet', subdirs : 'libleet', version : so_version, name : meson.project_name(), filebase : meson.project_name(), description : 'Matrix client library')

View file

@ -1,4 +1,7 @@
<?xml version="1.0" encoding="utf-8"?>
<packages>
<package id="boost" version="1.83.0" targetFramework="native" />
<package id="nlohmann.json" version="3.11.2" targetFramework="native" />
<package id="openssl-vc141-static-x86_64" version="1.1.0" targetFramework="native" />
<package id="rmt_zlib" version="1.2.8.7" targetFramework="native" />
</packages>

File diff suppressed because it is too large Load diff

View file

@ -1,157 +1,157 @@
/* libleet
* Matrix client library written in C++
* Licensed under the GNU Affero General Public License version 3.
* See included LICENSE file for more information.
*
* https://git.speedie.site/speedie/libleet
*/
const int32_t leet::returnUnixTimestamp() {
return std::chrono::duration_cast<std::chrono::seconds>(std::chrono::system_clock::now().time_since_epoch()).count();
}
leet::Event::Event leet::returnEventFromTimestamp(leet::User::credentialsResponse* resp, leet::Room::Room* room, const int32_t Timestamp, const bool Direction) {
using json = nlohmann::json;
leet::Event::Event event;
std::string Dir = Direction ? "f" : "b";
const std::string Output = leet::invokeRequest_Get(leet::getAPI("/_matrix/client/v1/rooms/" + room->roomID + "/timestamp_to_event" + "?ts=" + std::to_string(Timestamp) + "&dir=" + Dir), resp->accessToken);
json reqOutput;
try {
reqOutput = { json::parse(Output) };
} catch (const json::parse_error& e) {
return event;
}
for (auto& output : reqOutput) {
leet::errorCode = 0;
if (output["event_id"].is_string()) event.eventID = output["event_id"].get<std::string>();
if (output["origin_server_ts"].is_number_integer()) event.Age = output["origin_server_ts"].get<int>();
if (output["errcode"].is_string()) {
leet::errorCode = 1;
leet::Error = output["errcode"].get<std::string>();
if (output["error"].is_string()) leet::friendlyError = output["error"].get<std::string>();
break;
}
}
return event;
}
leet::Event::Event leet::returnLatestEvent(leet::User::credentialsResponse* resp, leet::Room::Room* room) {
return leet::returnEventFromTimestamp(resp, room, leet::returnUnixTimestamp(), true);
}
leet::Sync::Sync leet::returnSync(leet::User::credentialsResponse* resp) {
using json = nlohmann::json;
leet::Sync::Sync sync;
const std::string Output = leet::invokeRequest_Get(leet::getAPI("/_matrix/client/v3/sync"), resp->accessToken);
json theOutput;
try {
theOutput = json::parse(Output);
} catch (const json::parse_error& e) {
return sync;
}
sync.theRequest = theOutput.dump();
auto& reqOutput = theOutput["to_device"]["events"];
for (auto& output : reqOutput) {
leet::errorCode = 0;
leet::Sync::megolmSession megolmSession;
if (!output["content"]["sender_key"].is_null()) {
megolmSession.senderKey = output["content"]["sender_key"];
}
if (!output["content"]["algorithm"].is_null()) {
megolmSession.Algorithm = output["content"]["algorithm"];
}
if (megolmSession.senderKey.compare("")) {
if (!output["content"]["ciphertext"][megolmSession.senderKey]["body"].is_null()) {
megolmSession.cipherText = output["content"]["ciphertext"][megolmSession.senderKey]["body"];
}
if (!output["content"]["ciphertext"][megolmSession.senderKey]["type"].is_null()) {
megolmSession.cipherType = output["content"]["ciphertext"][megolmSession.senderKey]["type"];
}
}
if (!output["sender"].is_null()) {
megolmSession.Sender = output["sender"];
}
if (!output["type"].is_null()) {
megolmSession.Type = output["type"];
}
sync.megolmSessions.push_back(megolmSession);
}
return sync;
}
void leet::redactEvent(leet::User::credentialsResponse* resp, leet::Room::Room* room, leet::Event::Event* event, const std::string& Reason) {
using json = nlohmann::json;
json body;
if (Reason.compare("")) {
body["reason"] = Reason;
}
const std::string Output { leet::invokeRequest_Put(leet::getAPI("/_matrix/client/v3/rooms/" + room->roomID + "/redact/" + event->eventID + "/" + std::to_string(leet::transID)), body.dump(), resp->accessToken) };
json reqOutput;
try {
reqOutput = { json::parse(Output) };
} catch (const json::parse_error& e) {
return;
}
for (auto& output : reqOutput) {
leet::errorCode = 0;
if (output["errcode"].is_string()) {
leet::errorCode = 1;
leet::Error = output["errcode"].get<std::string>();
if (output["error"].is_string()) leet::friendlyError = output["error"].get<std::string>();
}
}
}
void leet::reportEvent(leet::User::credentialsResponse* resp, leet::Room::Room* room, leet::Event::Event* event, const std::string& Reason, const int Score) {
using json = nlohmann::json;
const std::string APIUrl { "/_matrix/client/v3/rooms/" + room->roomID + "/report/" + event->eventID };
json body;
body["reason"] = Reason;
if (Score > 0 || Score < -100) {
body["score"] = 0;
} else {
body["score"] = Score;
}
const std::string Output { leet::invokeRequest_Post(leet::getAPI(APIUrl), body.dump(), resp->accessToken) };
json reqOutput;
try {
reqOutput = { json::parse(Output) };
} catch (const json::parse_error& e) {
return;
}
for (auto& output : reqOutput) {
leet::errorCode = 0;
if (output["errcode"].is_string()) leet::Error = output["errcode"].get<std::string>();
if (output["error"].is_string()) leet::friendlyError = output["error"].get<std::string>();
}
}
/* libleet
* Matrix client library written in C++
* Licensed under the GNU Affero General Public License version 3.
* See included LICENSE file for more information.
*
* https://git.speedie.site/speedie/libleet
*/
const int32_t leet::returnUnixTimestamp() {
return std::chrono::duration_cast<std::chrono::seconds>(std::chrono::system_clock::now().time_since_epoch()).count();
}
leet::Event::Event leet::returnEventFromTimestamp(leet::User::credentialsResponse* resp, leet::Room::Room* room, const int32_t Timestamp, const bool Direction) {
using json = nlohmann::json;
leet::Event::Event event;
std::string Dir = Direction ? "f" : "b";
const std::string Output = leet::invokeRequest_Get(leet::getAPI("/_matrix/client/v1/rooms/" + room->roomID + "/timestamp_to_event" + "?ts=" + std::to_string(Timestamp) + "&dir=" + Dir), resp->accessToken);
json reqOutput;
try {
reqOutput = { json::parse(Output) };
} catch (const json::parse_error& e) {
return event;
}
for (auto& output : reqOutput) {
leet::errorCode = 0;
if (output["event_id"].is_string()) event.eventID = output["event_id"].get<std::string>();
if (output["origin_server_ts"].is_number_integer()) event.Age = output["origin_server_ts"].get<int>();
if (output["errcode"].is_string()) {
leet::errorCode = 1;
leet::Error = output["errcode"].get<std::string>();
if (output["error"].is_string()) leet::friendlyError = output["error"].get<std::string>();
break;
}
}
return event;
}
leet::Event::Event leet::returnLatestEvent(leet::User::credentialsResponse* resp, leet::Room::Room* room) {
return leet::returnEventFromTimestamp(resp, room, leet::returnUnixTimestamp(), true);
}
leet::Sync::Sync leet::returnSync(leet::User::credentialsResponse* resp) {
using json = nlohmann::json;
leet::Sync::Sync sync;
const std::string Output = leet::invokeRequest_Get(leet::getAPI("/_matrix/client/v3/sync"), resp->accessToken);
json theOutput;
try {
theOutput = json::parse(Output);
} catch (const json::parse_error& e) {
return sync;
}
sync.theRequest = theOutput.dump();
auto& reqOutput = theOutput["to_device"]["events"];
for (auto& output : reqOutput) {
leet::errorCode = 0;
leet::Sync::megolmSession megolmSession;
if (!output["content"]["sender_key"].is_null()) {
megolmSession.senderKey = output["content"]["sender_key"];
}
if (!output["content"]["algorithm"].is_null()) {
megolmSession.Algorithm = output["content"]["algorithm"];
}
if (megolmSession.senderKey.compare("")) {
if (!output["content"]["ciphertext"][megolmSession.senderKey]["body"].is_null()) {
megolmSession.cipherText = output["content"]["ciphertext"][megolmSession.senderKey]["body"];
}
if (!output["content"]["ciphertext"][megolmSession.senderKey]["type"].is_null()) {
megolmSession.cipherType = output["content"]["ciphertext"][megolmSession.senderKey]["type"];
}
}
if (!output["sender"].is_null()) {
megolmSession.Sender = output["sender"];
}
if (!output["type"].is_null()) {
megolmSession.Type = output["type"];
}
sync.megolmSessions.push_back(megolmSession);
}
return sync;
}
void leet::redactEvent(leet::User::credentialsResponse* resp, leet::Room::Room* room, leet::Event::Event* event, const std::string& Reason) {
using json = nlohmann::json;
json body;
if (Reason.compare("")) {
body["reason"] = Reason;
}
const std::string Output { leet::invokeRequest_Put(leet::getAPI("/_matrix/client/v3/rooms/" + room->roomID + "/redact/" + event->eventID + "/" + std::to_string(leet::transID)), body.dump(), resp->accessToken) };
json reqOutput;
try {
reqOutput = { json::parse(Output) };
} catch (const json::parse_error& e) {
return;
}
for (auto& output : reqOutput) {
leet::errorCode = 0;
if (output["errcode"].is_string()) {
leet::errorCode = 1;
leet::Error = output["errcode"].get<std::string>();
if (output["error"].is_string()) leet::friendlyError = output["error"].get<std::string>();
}
}
}
void leet::reportEvent(leet::User::credentialsResponse* resp, leet::Room::Room* room, leet::Event::Event* event, const std::string& Reason, const int Score) {
using json = nlohmann::json;
const std::string APIUrl { "/_matrix/client/v3/rooms/" + room->roomID + "/report/" + event->eventID };
json body;
body["reason"] = Reason;
if (Score > 0 || Score < -100) {
body["score"] = 0;
} else {
body["score"] = Score;
}
const std::string Output { leet::invokeRequest_Post(leet::getAPI(APIUrl), body.dump(), resp->accessToken) };
json reqOutput;
try {
reqOutput = { json::parse(Output) };
} catch (const json::parse_error& e) {
return;
}
for (auto& output : reqOutput) {
leet::errorCode = 0;
if (output["errcode"].is_string()) leet::Error = output["errcode"].get<std::string>();
if (output["error"].is_string()) leet::friendlyError = output["error"].get<std::string>();
}
}

View file

@ -1,160 +1,160 @@
/* libleet
* Matrix client library written in C++
* Licensed under the GNU Affero General Public License version 3.
* See included LICENSE file for more information.
*
* https://git.speedie.site/speedie/libleet
*/
template <typename T> T leet::saveToFile(const std::string& File, T Data) {
std::filesystem::path file{ File };
std::ofstream outputFile;
if (!std::filesystem::create_directories(file.parent_path()) && !std::filesystem::is_directory(file.parent_path())) {
throw("Failed to create directory");
}
outputFile.open(File);
outputFile << Data;
outputFile.close();
return T();
}
template <typename T> T leet::loadFromFile(const std::string& File) {
std::filesystem::path file{ File };
std::string line;
if (std::filesystem::exists(file)) {
std::ifstream inputFile(File);
if (!inputFile.is_open()) {
return false;
}
while (std::getline(inputFile, line)) {
T ret = std::stoi(line);
inputFile.close();
return ret;
}
inputFile.close();
}
return false;
}
const bool leet::saveTransID(const std::string& File) {
leet::saveToFile<int>(File, leet::transID);
return true;
}
const bool leet::loadTransID(const std::string& File) {
return (leet::transID = leet::loadFromFile<int>(File));
}
leet::Attachment::Attachment leet::uploadFile(leet::User::credentialsResponse* resp, const std::string& File) {
using json = nlohmann::json;
leet::Attachment::Attachment theAttachment;
const std::string Output = leet::invokeRequest_Post_File(leet::getAPI("/_matrix/media/v3/upload"), File, resp->accessToken);
json returnOutput;
try {
returnOutput = { json::parse(Output) };
} catch (const json::parse_error& e) {
return theAttachment;
}
for (auto& output : returnOutput) {
leet::errorCode = 0;
leet::Error = "";
if (output["content_uri"].is_string()) {
theAttachment.URL = output["content_uri"].get<std::string>();
return theAttachment;
}
if (output["errcode"].is_string()) {
leet::errorCode = 1;
leet::Error = output["errcode"].get<std::string>();
if (output["error"].is_string()) leet::friendlyError = output["error"].get<std::string>();
return theAttachment;
}
}
return theAttachment;
}
const std::string leet::decodeFile(leet::User::credentialsResponse* resp, leet::Attachment::Attachment* Attachment) {
std::string Server{};
std::string ID{};
std::string File{Attachment->URL};
std::size_t it = File.find("mxc://");
if (it != std::string::npos) {
it += 6;
std::size_t nextSlash = File.find("/", it);
if (nextSlash != std::string::npos) {
Server = File.substr(it, nextSlash - it);
ID = File.substr(nextSlash + 1);
} else {
leet::errorCode = 1;
return "";
}
}
return leet::getAPI("/_matrix/media/v3/download/" + Server + "/" + ID + "?allow_redirect=false");
}
const bool leet::downloadFile(leet::User::credentialsResponse* resp, leet::Attachment::Attachment* Attachment, const std::string& outputFile) {
std::string Server{};
std::string ID{};
std::string File{Attachment->URL};
std::size_t it = File.find("mxc://");
if (it != std::string::npos) {
it += 6;
std::size_t nextSlash = File.find("/", it);
if (nextSlash != std::string::npos) {
Server = File.substr(it, nextSlash - it);
ID = File.substr(nextSlash + 1);
} else {
leet::errorCode = 1;
return false;
}
}
// Now that we have what we need, let's make a request
const std::string API { leet::getAPI("/_matrix/media/v3/download/" + Server + "/" + ID + "?allow_redirect=false") };
std::filesystem::path file{ outputFile };
if (!std::filesystem::create_directories(file.parent_path()) && !std::filesystem::is_directory(file.parent_path())) {
leet::errorCode = 1;
return false;
}
/*
std::ofstream of(outputFile, std::ios::binary);
cpr::Response response = cpr::Download(of, cpr::Url{API});
if (response.status_code == 200) {
return true;
}
*/
leetRequest::URL url;
leetRequest::Request request;
url.parseURLFromString(API);
request.Host = url.Host;
request.Endpoint = url.Endpoint;
request.Query = url.Query;
request.Port = url.Port;
request.Protocol = url.Protocol;
request.Type = leetRequest::LEET_REQUEST_REQTYPE_GET;
request.userAgent = "LIBLEET_USER_AGENT";
request.outputFile = outputFile;
return request.downloadFile();
}
/* libleet
* Matrix client library written in C++
* Licensed under the GNU Affero General Public License version 3.
* See included LICENSE file for more information.
*
* https://git.speedie.site/speedie/libleet
*/
template <typename T> T leet::saveToFile(const std::string& File, T Data) {
std::filesystem::path file{ File };
std::ofstream outputFile;
if (!std::filesystem::create_directories(file.parent_path()) && !std::filesystem::is_directory(file.parent_path())) {
throw("Failed to create directory");
}
outputFile.open(File);
outputFile << Data;
outputFile.close();
return T();
}
template <typename T> T leet::loadFromFile(const std::string& File) {
std::filesystem::path file{ File };
std::string line;
if (std::filesystem::exists(file)) {
std::ifstream inputFile(File);
if (!inputFile.is_open()) {
return false;
}
while (std::getline(inputFile, line)) {
T ret = std::stoi(line);
inputFile.close();
return ret;
}
inputFile.close();
}
return false;
}
const bool leet::saveTransID(const std::string& File) {
leet::saveToFile<int>(File, leet::transID);
return true;
}
const bool leet::loadTransID(const std::string& File) {
return (leet::transID = leet::loadFromFile<int>(File));
}
leet::Attachment::Attachment leet::uploadFile(leet::User::credentialsResponse* resp, const std::string& File) {
using json = nlohmann::json;
leet::Attachment::Attachment theAttachment;
const std::string Output = leet::invokeRequest_Post_File(leet::getAPI("/_matrix/media/v3/upload"), File, resp->accessToken);
json returnOutput;
try {
returnOutput = { json::parse(Output) };
} catch (const json::parse_error& e) {
return theAttachment;
}
for (auto& output : returnOutput) {
leet::errorCode = 0;
leet::Error = "";
if (output["content_uri"].is_string()) {
theAttachment.URL = output["content_uri"].get<std::string>();
return theAttachment;
}
if (output["errcode"].is_string()) {
leet::errorCode = 1;
leet::Error = output["errcode"].get<std::string>();
if (output["error"].is_string()) leet::friendlyError = output["error"].get<std::string>();
return theAttachment;
}
}
return theAttachment;
}
const std::string leet::decodeFile(leet::User::credentialsResponse* resp, leet::Attachment::Attachment* Attachment) {
std::string Server{};
std::string ID{};
std::string File{Attachment->URL};
std::size_t it = File.find("mxc://");
if (it != std::string::npos) {
it += 6;
std::size_t nextSlash = File.find("/", it);
if (nextSlash != std::string::npos) {
Server = File.substr(it, nextSlash - it);
ID = File.substr(nextSlash + 1);
} else {
leet::errorCode = 1;
return "";
}
}
return leet::getAPI("/_matrix/media/v3/download/" + Server + "/" + ID + "?allow_redirect=false");
}
const bool leet::downloadFile(leet::User::credentialsResponse* resp, leet::Attachment::Attachment* Attachment, const std::string& outputFile) {
std::string Server{};
std::string ID{};
std::string File{Attachment->URL};
std::size_t it = File.find("mxc://");
if (it != std::string::npos) {
it += 6;
std::size_t nextSlash = File.find("/", it);
if (nextSlash != std::string::npos) {
Server = File.substr(it, nextSlash - it);
ID = File.substr(nextSlash + 1);
} else {
leet::errorCode = 1;
return false;
}
}
// Now that we have what we need, let's make a request
const std::string API { leet::getAPI("/_matrix/media/v3/download/" + Server + "/" + ID + "?allow_redirect=false") };
std::filesystem::path file{ outputFile };
if (!std::filesystem::create_directories(file.parent_path()) && !std::filesystem::is_directory(file.parent_path())) {
leet::errorCode = 1;
return false;
}
/*
std::ofstream of(outputFile, std::ios::binary);
cpr::Response response = cpr::Download(of, cpr::Url{API});
if (response.status_code == 200) {
return true;
}
*/
leetRequest::URL url;
leetRequest::Request request;
url.parseURLFromString(API);
request.Host = url.Host;
request.Endpoint = url.Endpoint;
request.Query = url.Query;
request.Port = url.Port;
request.Protocol = url.Protocol;
request.Type = leetRequest::LEET_REQUEST_REQTYPE_GET;
request.userAgent = "LIBLEET_USER_AGENT";
request.outputFile = outputFile;
return request.downloadFile();
}

View file

@ -1,206 +1,206 @@
/* libleet
* Matrix client library written in C++
* Licensed under the GNU Affero General Public License version 3.
* See included LICENSE file for more information.
*
* https://git.speedie.site/speedie/libleet
*/
std::vector<std::string> leet::returnSupportedLoginTypes() {
using json = nlohmann::json;
std::vector<std::string> vector;
const std::string APIUrl { "/_matrix/client/v3/login" };
std::string Output { leet::invokeRequest_Get(leet::getAPI(APIUrl)) };
json reqOutput;
try {
reqOutput = json::parse(Output);
} catch (const json::parse_error& e) {
return vector;
}
auto& messages = reqOutput["flows"];
for (auto it = messages.begin(); it != messages.end(); ++it) {
std::string theString{};
if (it.value().contains("/type"_json_pointer)) theString = it.value()["type"];
vector.push_back(theString);
}
return vector;
}
leet::User::credentialsResponse leet::refreshAccessToken(leet::User::credentialsResponse* resp) {
using json = nlohmann::json;
leet::User::credentialsResponse newResponse = *resp;
if (!newResponse.refreshToken.compare("")) {
return newResponse;
}
json body;
body["refresh_token"] = newResponse.refreshToken;
json refreshOutput;
try {
refreshOutput = { json::parse(leet::invokeRequest_Post(leet::getAPI("/_matrix/client/v3/refresh"), body.dump())) };
} catch (const json::parse_error& e) {
return newResponse;
}
for (auto& output : refreshOutput) {
leet::errorCode = 0;
if (output["access_token"].is_string()) newResponse.accessToken = output["access_token"].get<std::string>();
if (output["refresh_token"].is_string()) newResponse.refreshToken = output["refresh_token"].get<std::string>();
if (output["expires_in_ms"].is_number_integer()) newResponse.Expiration = output["expires_in_ms"].get<int>();
if (output["errcode"].is_string()) {
leet::errorCode = 1;
leet::Error = output["errcode"].get<std::string>();
if (output["error"].is_string()) leet::friendlyError = output["error"].get<std::string>();
}
}
return newResponse;
}
bool leet::checkRegistrationTokenValidity(const std::string& Token) {
using json = nlohmann::json;
json body;
try {
body = { json::parse(leet::invokeRequest_Get(leet::getAPI("/_matrix/client/v1/register/m.login.registration_token/validity?token=" + Token))) };
} catch (const json::parse_error& e) {
return false;
}
for (auto& output : body) {
leet::errorCode = 0;
if (output["valid"].is_boolean()) {
bool theBool = output["valid"].get<bool>();
return theBool;
}
if (output["errcode"].is_string()) {
leet::errorCode = 1;
leet::Error = output["errcode"].get<std::string>();
if (output["error"].is_string()) leet::friendlyError = output["error"].get<std::string>();
}
}
return false;
}
leet::User::credentialsResponse leet::registerAccount(leet::User::Credentials* cred) {
leet::User::credentialsResponse resp;
using json = nlohmann::json;
std::string theUsername = cred->Username;
if (cred->Username[0] == '@') {
theUsername = leet::returnUserName(cred->Username);
if (theUsername[0] == '@' || !theUsername.compare("")) {
return resp;
leet::errorCode = 1;
}
}
json body;
if (cred->deviceID.compare("")) {
body["device_id"] = cred->deviceID;
}
body["inhibit_login"] = false;
body["initial_device_display_name"] = cred->displayName;
body["username"] = theUsername;
body["password"] = cred->Password;
body["refresh_token"] = cred->refreshToken;
json registerOutput;
try {
registerOutput = { json::parse(leet::invokeRequest_Post(leet::getAPI("/_matrix/client/v3/register"), body.dump())) };
} catch (const json::parse_error& e) {
return resp;
}
for (auto& output : registerOutput) {
leet::errorCode = 0;
resp.Homeserver = leet::Homeserver = cred->Homeserver;
if (output["access_token"].is_string()) resp.accessToken = output["access_token"].get<std::string>();
if (output["device_id"].is_string()) resp.deviceID = output["device_id"].get<std::string>();
if (output["refresh_token"].is_string()) resp.refreshToken = output["refresh_token"].get<std::string>();
if (output["user_id"].is_string()) resp.userID = output["user_id"].get<std::string>();
if (output["expires_in_ms"].is_number_integer()) resp.Expiration = output["expires_in_ms"].get<int>();
if (output["errcode"].is_string()) {
leet::errorCode = 1;
leet::Error = output["errcode"].get<std::string>();
if (output["error"].is_string()) leet::friendlyError = output["error"].get<std::string>();
}
}
return resp;
}
leet::User::credentialsResponse leet::loginAccount(leet::User::Credentials* cred) {
leet::User::credentialsResponse resp;
using json = nlohmann::json;
json list;
std::string actualType{};
if (cred->Type == LEET_TYPE_TOKEN) {
actualType = "m.login.token";
} else {
actualType = "m.login.password";
}
if (cred->deviceID.compare("")) {
list["device_id"] = cred->deviceID;
}
list["identifier"]["type"] = "m.id.user"; // Currently only supported method
list["identifier"]["user"] = cred->Username;
list["initial_device_display_name"] = cred->displayName;
if (cred->Type == LEET_TYPE_TOKEN) {
list["token"] = cred->Token;
} else {
list["password"] = cred->Password;
}
list["refresh_token"] = cred->refreshToken;
list["type"] = actualType;
json loginOutput = { json::parse(leet::invokeRequest_Post(leet::getAPI("/_matrix/client/v3/login"), list.dump())) };
for (auto& output : loginOutput) {
leet::errorCode = 0;
resp.Homeserver = leet::Homeserver = cred->Homeserver;
if (output["access_token"].is_string()) resp.accessToken = output["access_token"].get<std::string>();
if (output["device_id"].is_string()) resp.deviceID = output["device_id"].get<std::string>();
if (output["refresh_token"].is_string()) resp.refreshToken = output["refresh_token"].get<std::string>();
if (output["user_id"].is_string()) resp.userID = output["user_id"].get<std::string>();
if (output["expires_in_ms"].is_number_integer()) resp.Expiration = output["expires_in_ms"].get<int>();
if (output["errcode"].is_string()) {
leet::errorCode = 1;
leet::Error = output["errcode"].get<std::string>();
if (output["error"].is_string()) leet::friendlyError = output["error"].get<std::string>();
}
}
return resp;
}
/* libleet
* Matrix client library written in C++
* Licensed under the GNU Affero General Public License version 3.
* See included LICENSE file for more information.
*
* https://git.speedie.site/speedie/libleet
*/
std::vector<std::string> leet::returnSupportedLoginTypes() {
using json = nlohmann::json;
std::vector<std::string> vector;
const std::string APIUrl { "/_matrix/client/v3/login" };
std::string Output { leet::invokeRequest_Get(leet::getAPI(APIUrl)) };
json reqOutput;
try {
reqOutput = json::parse(Output);
} catch (const json::parse_error& e) {
return vector;
}
auto& messages = reqOutput["flows"];
for (auto it = messages.begin(); it != messages.end(); ++it) {
std::string theString{};
if (it.value().contains("/type"_json_pointer)) theString = it.value()["type"];
vector.push_back(theString);
}
return vector;
}
leet::User::credentialsResponse leet::refreshAccessToken(leet::User::credentialsResponse* resp) {
using json = nlohmann::json;
leet::User::credentialsResponse newResponse = *resp;
if (!newResponse.refreshToken.compare("")) {
return newResponse;
}
json body;
body["refresh_token"] = newResponse.refreshToken;
json refreshOutput;
try {
refreshOutput = { json::parse(leet::invokeRequest_Post(leet::getAPI("/_matrix/client/v3/refresh"), body.dump())) };
} catch (const json::parse_error& e) {
return newResponse;
}
for (auto& output : refreshOutput) {
leet::errorCode = 0;
if (output["access_token"].is_string()) newResponse.accessToken = output["access_token"].get<std::string>();
if (output["refresh_token"].is_string()) newResponse.refreshToken = output["refresh_token"].get<std::string>();
if (output["expires_in_ms"].is_number_integer()) newResponse.Expiration = output["expires_in_ms"].get<int>();
if (output["errcode"].is_string()) {
leet::errorCode = 1;
leet::Error = output["errcode"].get<std::string>();
if (output["error"].is_string()) leet::friendlyError = output["error"].get<std::string>();
}
}
return newResponse;
}
bool leet::checkRegistrationTokenValidity(const std::string& Token) {
using json = nlohmann::json;
json body;
try {
body = { json::parse(leet::invokeRequest_Get(leet::getAPI("/_matrix/client/v1/register/m.login.registration_token/validity?token=" + Token))) };
} catch (const json::parse_error& e) {
return false;
}
for (auto& output : body) {
leet::errorCode = 0;
if (output["valid"].is_boolean()) {
bool theBool = output["valid"].get<bool>();
return theBool;
}
if (output["errcode"].is_string()) {
leet::errorCode = 1;
leet::Error = output["errcode"].get<std::string>();
if (output["error"].is_string()) leet::friendlyError = output["error"].get<std::string>();
}
}
return false;
}
leet::User::credentialsResponse leet::registerAccount(leet::User::Credentials* cred) {
leet::User::credentialsResponse resp;
using json = nlohmann::json;
std::string theUsername = cred->Username;
if (cred->Username[0] == '@') {
theUsername = leet::returnUserName(cred->Username);
if (theUsername[0] == '@' || !theUsername.compare("")) {
return resp;
leet::errorCode = 1;
}
}
json body;
if (cred->deviceID.compare("")) {
body["device_id"] = cred->deviceID;
}
body["inhibit_login"] = false;
body["initial_device_display_name"] = cred->displayName;
body["username"] = theUsername;
body["password"] = cred->Password;
body["refresh_token"] = cred->refreshToken;
json registerOutput;
try {
registerOutput = { json::parse(leet::invokeRequest_Post(leet::getAPI("/_matrix/client/v3/register"), body.dump())) };
} catch (const json::parse_error& e) {
return resp;
}
for (auto& output : registerOutput) {
leet::errorCode = 0;
resp.Homeserver = leet::Homeserver = cred->Homeserver;
if (output["access_token"].is_string()) resp.accessToken = output["access_token"].get<std::string>();
if (output["device_id"].is_string()) resp.deviceID = output["device_id"].get<std::string>();
if (output["refresh_token"].is_string()) resp.refreshToken = output["refresh_token"].get<std::string>();
if (output["user_id"].is_string()) resp.userID = output["user_id"].get<std::string>();
if (output["expires_in_ms"].is_number_integer()) resp.Expiration = output["expires_in_ms"].get<int>();
if (output["errcode"].is_string()) {
leet::errorCode = 1;
leet::Error = output["errcode"].get<std::string>();
if (output["error"].is_string()) leet::friendlyError = output["error"].get<std::string>();
}
}
return resp;
}
leet::User::credentialsResponse leet::loginAccount(leet::User::Credentials* cred) {
leet::User::credentialsResponse resp;
using json = nlohmann::json;
json list;
std::string actualType{};
if (cred->Type == LEET_TYPE_TOKEN) {
actualType = "m.login.token";
} else {
actualType = "m.login.password";
}
if (cred->deviceID.compare("")) {
list["device_id"] = cred->deviceID;
}
list["identifier"]["type"] = "m.id.user"; // Currently only supported method
list["identifier"]["user"] = cred->Username;
list["initial_device_display_name"] = cred->displayName;
if (cred->Type == LEET_TYPE_TOKEN) {
list["token"] = cred->Token;
} else {
list["password"] = cred->Password;
}
list["refresh_token"] = cred->refreshToken;
list["type"] = actualType;
json loginOutput = { json::parse(leet::invokeRequest_Post(leet::getAPI("/_matrix/client/v3/login"), list.dump())) };
for (auto& output : loginOutput) {
leet::errorCode = 0;
resp.Homeserver = leet::Homeserver = cred->Homeserver;
if (output["access_token"].is_string()) resp.accessToken = output["access_token"].get<std::string>();
if (output["device_id"].is_string()) resp.deviceID = output["device_id"].get<std::string>();
if (output["refresh_token"].is_string()) resp.refreshToken = output["refresh_token"].get<std::string>();
if (output["user_id"].is_string()) resp.userID = output["user_id"].get<std::string>();
if (output["expires_in_ms"].is_number_integer()) resp.Expiration = output["expires_in_ms"].get<int>();
if (output["errcode"].is_string()) {
leet::errorCode = 1;
leet::Error = output["errcode"].get<std::string>();
if (output["error"].is_string()) leet::friendlyError = output["error"].get<std::string>();
}
}
return resp;
}

View file

@ -1,199 +1,199 @@
/* libleet
* Matrix client library written in C++
* Licensed under the GNU Affero General Public License version 3.
* See included LICENSE file for more information.
*
* https://git.speedie.site/speedie/libleet
*/
void leet::sendMessage(leet::User::credentialsResponse* resp, leet::Room::Room* room, leet::Message::Message* msg) {
using json = nlohmann::json;
const int transID { leet::transID };
const std::string eventType { "m.room.message" };
const std::string APIUrl { "/_matrix/client/v3/rooms/" + room->roomID + "/send/" + eventType + "/" + std::to_string(transID) };
json list;
if (!msg->messageType.compare("m.image") || !msg->messageType.compare("m.audio") || !msg->messageType.compare("m.video") || !msg->messageType.compare("m.file")) {
if (msg->attachmentURL[0] != 'm' || msg->attachmentURL[1] != 'x' || msg->attachmentURL[2] != 'c') {
leet::errorCode = 1;
return;
}
list["type"] = "m.room.message";
list["room_id"] = room->roomID;
list["body"] = msg->messageText;
list["msgtype"] = msg->messageType;
list["url"] = msg->attachmentURL;
} else {
list["type"] = "m.room.message";
list["room_id"] = room->roomID;
list["body"] = msg->messageText;
list["msgtype"] = msg->messageType;
}
const std::string Output { leet::invokeRequest_Put(leet::getAPI(APIUrl), list.dump(), resp->accessToken) };
json reqOutput;
try {
reqOutput = { json::parse(Output) };
} catch (const json::parse_error& e) {
return;
}
for (auto& output : reqOutput) {
leet::errorCode = 0;
if (output["errcode"].is_string()) {
leet::errorCode = 1;
leet::Error = output["errcode"].get<std::string>();
if (output["error"].is_string()) leet::friendlyError = output["error"].get<std::string>();
}
}
}
#ifndef LEET_NO_ENCRYPTION
void leet::sendEncryptedMessage(leet::User::credentialsResponse* resp, leet::Encryption* enc, leet::Room::Room* room, leet::Message::Message* msg) {
using json = nlohmann::json;
const int transID { leet::transID };
const std::string eventType { "m.room.encrypted" };
const std::string APIUrl { "/_matrix/client/v3/rooms/" + room->roomID + "/send/" + eventType + "/" + std::to_string(transID) };
json Body;
Body["type"] = "m.room.message";
Body["room_id"] = room->roomID;
Body["content"]["body"] = msg->messageText;
Body["content"]["msgtype"] = "m.text";
const std::string Output { leet::invokeRequest_Put(leet::getAPI(APIUrl), enc->account.encryptMessage(resp, Body.dump()), resp->accessToken) };
json reqOutput;
try {
reqOutput = { json::parse(Output) };
} catch (const json::parse_error& e) {
return;
}
for (auto& output : reqOutput) {
leet::errorCode = 0;
if (output["errcode"].is_string()) {
leet::errorCode = 1;
leet::Error = output["errcode"].get<std::string>();
if (output["error"].is_string()) leet::friendlyError = output["error"].get<std::string>();
}
}
}
#endif
const std::vector<leet::Message::Message> leet::returnMessages(leet::User::credentialsResponse* resp, leet::Room::Room* room, const int messageCount) {
using json = nlohmann::json;
std::vector<leet::Message::Message> vector;
const std::string APIUrl { "/_matrix/client/v3/rooms/" + room->roomID + "/messages?dir=b&limit=" + std::to_string(messageCount) };
std::string Output { leet::invokeRequest_Get(leet::getAPI(APIUrl), resp->accessToken) };
json reqOutput;
try {
reqOutput = json::parse(Output);
} catch (const json::parse_error& e) {
return vector;
}
auto& messages = reqOutput["chunk"];
for (auto it = messages.begin(); it != messages.end(); ++it) {
leet::Message::Message message;
message.Encrypted = false;
if (it.value().contains("/type"_json_pointer)) message.Type = it.value()["type"];
// Encrypted message
if (!message.Type.compare("m.room.encrypted")) {
message.Encrypted = true;
message.megolm = false;
if (it.value().contains("/content/ciphertext"_json_pointer)) message.cipherText = it.value()["content"]["ciphertext"];
if (it.value().contains("/content/sender_key"_json_pointer)) message.senderKey = it.value()["content"]["sender_key"];
if (it.value().contains("/content/device_id"_json_pointer)) message.deviceID = it.value()["content"]["device_id"];
if (it.value().contains("/content/session_id"_json_pointer)) message.sessionID = it.value()["content"]["session_id"];
if (it.value().contains("/content/algorithm"_json_pointer)) if (it.value()["content"]["algorithm"] == "m.megolm.v1.aes-sha2") message.megolm = true;
}
if (it.value().contains("/content/msgtype"_json_pointer)) message.messageType = it.value()["content"]["msgtype"];
if (it.value().contains("/sender"_json_pointer)) message.Sender = it.value()["sender"];
if (it.value().contains("/content/body"_json_pointer)) message.messageText = it.value()["content"]["body"];
if (it.value().contains("/content/formatted_body"_json_pointer)) message.formattedText = it.value()["content"]["formatted_body"];
if (it.value().contains("/content/format"_json_pointer)) message.Format = it.value()["content"]["format"];
if (it.value().contains("/content/info/mimetype"_json_pointer)) message.mimeType = it.value()["content"]["info"]["mimetype"];
if (it.value().contains("/event_id"_json_pointer)) message.eventID = it.value()["event_id"];
if (it.value().contains("/origin_server_ts"_json_pointer)) message.Age = it.value()["origin_server_ts"];
// Attachments
if (it.value().contains("/content/info/size"_json_pointer)) message.attachmentSize = it.value()["content"]["info"]["size"];
if (it.value().contains("/content/info/duration"_json_pointer)) message.attachmentLength = it.value()["content"]["info"]["duration"];
if (it.value().contains("/content/info/w"_json_pointer)) message.attachmentWidth = it.value()["content"]["info"]["w"];
if (it.value().contains("/content/info/h"_json_pointer)) message.attachmentHeight = it.value()["content"]["info"]["h"];
if (it.value().contains("/content/url"_json_pointer)) message.attachmentURL = it.value()["content"]["url"];
// Handle thumbnails
if (!message.messageType.compare("m.video")) {
if (it.value().contains("/content/info/thumbnail_info/w"_json_pointer)) message.thumbnailWidth = it.value()["content"]["info"]["thumbnail_info"]["w"];
if (it.value().contains("/content/info/thumbnail_info/h"_json_pointer)) message.thumbnailHeight = it.value()["content"]["info"]["thumbnail_info"]["h"];
if (it.value().contains("/content/info/thumbnail_info/size"_json_pointer)) message.thumbnailSize = it.value()["content"]["info"]["thumbnail_info"]["size"];
if (it.value().contains("/content/info/thumbnail_info/mimetype"_json_pointer)) message.thumbnailMimeType = it.value()["content"]["info"]["thumbnail_info"]["mimetype"];
if (it.value().contains("/content/info/thumbnail_url"_json_pointer)) message.thumbnailURL = it.value()["content"]["info"]["thumbnail_url"];
}
vector.push_back(message);
}
return vector;
}
const std::string leet::returnFilter(leet::User::credentialsResponse* resp, leet::Filter::Filter *filter) {
using json = nlohmann::json;
const std::string APIUrl { "/_matrix/client/v3/user/" + resp->userID + "/filter" };
json list;
list["event_format"] = "client";
list["event_fields"] = filter->Fields;
list["presence"]["senders"] = filter->Senders;
list["presence"]["not_senders"] = filter->notSenders;
list["room"]["ephemeral"]["rooms"] = filter->Rooms;
list["room"]["ephemeral"]["not_rooms"] = filter->notRooms;
list["room"]["ephemeral"]["senders"] = filter->Senders;
list["room"]["ephemeral"]["not_senders"] = filter->notSenders;
list["room"]["state"]["rooms"] = filter->Rooms;
list["room"]["state"]["not_rooms"] = filter->notRooms;
if (filter->Limit != 0) {
list["room"]["timeline"]["limit"] = filter->Limit;
}
list["room"]["timeline"]["not_rooms"] = filter->notRooms;
list["room"]["timeline"]["not_senders"] = filter->notSenders;
std::string Output { leet::invokeRequest_Post(leet::getAPI(APIUrl), list.dump(), resp->accessToken) };
json reqOutput;
try {
reqOutput = json::parse(Output);
} catch (const json::parse_error& e) {
return "";
}
for (auto& output : reqOutput) {
leet::errorCode = 0;
if (output["filter_id"].is_string()) {
return output["filter_id"].get<std::string>();
}
}
return "";
}
/* libleet
* Matrix client library written in C++
* Licensed under the GNU Affero General Public License version 3.
* See included LICENSE file for more information.
*
* https://git.speedie.site/speedie/libleet
*/
void leet::sendMessage(leet::User::credentialsResponse* resp, leet::Room::Room* room, leet::Message::Message* msg) {
using json = nlohmann::json;
const int transID { leet::transID };
const std::string eventType { "m.room.message" };
const std::string APIUrl { "/_matrix/client/v3/rooms/" + room->roomID + "/send/" + eventType + "/" + std::to_string(transID) };
json list;
if (!msg->messageType.compare("m.image") || !msg->messageType.compare("m.audio") || !msg->messageType.compare("m.video") || !msg->messageType.compare("m.file")) {
if (msg->attachmentURL[0] != 'm' || msg->attachmentURL[1] != 'x' || msg->attachmentURL[2] != 'c') {
leet::errorCode = 1;
return;
}
list["type"] = "m.room.message";
list["room_id"] = room->roomID;
list["body"] = msg->messageText;
list["msgtype"] = msg->messageType;
list["url"] = msg->attachmentURL;
} else {
list["type"] = "m.room.message";
list["room_id"] = room->roomID;
list["body"] = msg->messageText;
list["msgtype"] = msg->messageType;
}
const std::string Output { leet::invokeRequest_Put(leet::getAPI(APIUrl), list.dump(), resp->accessToken) };
json reqOutput;
try {
reqOutput = { json::parse(Output) };
} catch (const json::parse_error& e) {
return;
}
for (auto& output : reqOutput) {
leet::errorCode = 0;
if (output["errcode"].is_string()) {
leet::errorCode = 1;
leet::Error = output["errcode"].get<std::string>();
if (output["error"].is_string()) leet::friendlyError = output["error"].get<std::string>();
}
}
}
#ifndef LEET_NO_ENCRYPTION
void leet::sendEncryptedMessage(leet::User::credentialsResponse* resp, leet::Encryption* enc, leet::Room::Room* room, leet::Message::Message* msg) {
using json = nlohmann::json;
const int transID { leet::transID };
const std::string eventType { "m.room.encrypted" };
const std::string APIUrl { "/_matrix/client/v3/rooms/" + room->roomID + "/send/" + eventType + "/" + std::to_string(transID) };
json Body;
Body["type"] = "m.room.message";
Body["room_id"] = room->roomID;
Body["content"]["body"] = msg->messageText;
Body["content"]["msgtype"] = "m.text";
const std::string Output { leet::invokeRequest_Put(leet::getAPI(APIUrl), enc->account.encryptMessage(resp, Body.dump()), resp->accessToken) };
json reqOutput;
try {
reqOutput = { json::parse(Output) };
} catch (const json::parse_error& e) {
return;
}
for (auto& output : reqOutput) {
leet::errorCode = 0;
if (output["errcode"].is_string()) {
leet::errorCode = 1;
leet::Error = output["errcode"].get<std::string>();
if (output["error"].is_string()) leet::friendlyError = output["error"].get<std::string>();
}
}
}
#endif
const std::vector<leet::Message::Message> leet::returnMessages(leet::User::credentialsResponse* resp, leet::Room::Room* room, const int messageCount) {
using json = nlohmann::json;
std::vector<leet::Message::Message> vector;
const std::string APIUrl { "/_matrix/client/v3/rooms/" + room->roomID + "/messages?dir=b&limit=" + std::to_string(messageCount) };
std::string Output { leet::invokeRequest_Get(leet::getAPI(APIUrl), resp->accessToken) };
json reqOutput;
try {
reqOutput = json::parse(Output);
} catch (const json::parse_error& e) {
return vector;
}
auto& messages = reqOutput["chunk"];
for (auto it = messages.begin(); it != messages.end(); ++it) {
leet::Message::Message message;
message.Encrypted = false;
if (it.value().contains("/type"_json_pointer)) message.Type = it.value()["type"];
// Encrypted message
if (!message.Type.compare("m.room.encrypted")) {
message.Encrypted = true;
message.megolm = false;
if (it.value().contains("/content/ciphertext"_json_pointer)) message.cipherText = it.value()["content"]["ciphertext"];
if (it.value().contains("/content/sender_key"_json_pointer)) message.senderKey = it.value()["content"]["sender_key"];
if (it.value().contains("/content/device_id"_json_pointer)) message.deviceID = it.value()["content"]["device_id"];
if (it.value().contains("/content/session_id"_json_pointer)) message.sessionID = it.value()["content"]["session_id"];
if (it.value().contains("/content/algorithm"_json_pointer)) if (it.value()["content"]["algorithm"] == "m.megolm.v1.aes-sha2") message.megolm = true;
}
if (it.value().contains("/content/msgtype"_json_pointer)) message.messageType = it.value()["content"]["msgtype"];
if (it.value().contains("/sender"_json_pointer)) message.Sender = it.value()["sender"];
if (it.value().contains("/content/body"_json_pointer)) message.messageText = it.value()["content"]["body"];
if (it.value().contains("/content/formatted_body"_json_pointer)) message.formattedText = it.value()["content"]["formatted_body"];
if (it.value().contains("/content/format"_json_pointer)) message.Format = it.value()["content"]["format"];
if (it.value().contains("/content/info/mimetype"_json_pointer)) message.mimeType = it.value()["content"]["info"]["mimetype"];
if (it.value().contains("/event_id"_json_pointer)) message.eventID = it.value()["event_id"];
if (it.value().contains("/origin_server_ts"_json_pointer)) message.Age = it.value()["origin_server_ts"];
// Attachments
if (it.value().contains("/content/info/size"_json_pointer)) message.attachmentSize = it.value()["content"]["info"]["size"];
if (it.value().contains("/content/info/duration"_json_pointer)) message.attachmentLength = it.value()["content"]["info"]["duration"];
if (it.value().contains("/content/info/w"_json_pointer)) message.attachmentWidth = it.value()["content"]["info"]["w"];
if (it.value().contains("/content/info/h"_json_pointer)) message.attachmentHeight = it.value()["content"]["info"]["h"];
if (it.value().contains("/content/url"_json_pointer)) message.attachmentURL = it.value()["content"]["url"];
// Handle thumbnails
if (!message.messageType.compare("m.video")) {
if (it.value().contains("/content/info/thumbnail_info/w"_json_pointer)) message.thumbnailWidth = it.value()["content"]["info"]["thumbnail_info"]["w"];
if (it.value().contains("/content/info/thumbnail_info/h"_json_pointer)) message.thumbnailHeight = it.value()["content"]["info"]["thumbnail_info"]["h"];
if (it.value().contains("/content/info/thumbnail_info/size"_json_pointer)) message.thumbnailSize = it.value()["content"]["info"]["thumbnail_info"]["size"];
if (it.value().contains("/content/info/thumbnail_info/mimetype"_json_pointer)) message.thumbnailMimeType = it.value()["content"]["info"]["thumbnail_info"]["mimetype"];
if (it.value().contains("/content/info/thumbnail_url"_json_pointer)) message.thumbnailURL = it.value()["content"]["info"]["thumbnail_url"];
}
vector.push_back(message);
}
return vector;
}
const std::string leet::returnFilter(leet::User::credentialsResponse* resp, leet::Filter::Filter *filter) {
using json = nlohmann::json;
const std::string APIUrl { "/_matrix/client/v3/user/" + resp->userID + "/filter" };
json list;
list["event_format"] = "client";
list["event_fields"] = filter->Fields;
list["presence"]["senders"] = filter->Senders;
list["presence"]["not_senders"] = filter->notSenders;
list["room"]["ephemeral"]["rooms"] = filter->Rooms;
list["room"]["ephemeral"]["not_rooms"] = filter->notRooms;
list["room"]["ephemeral"]["senders"] = filter->Senders;
list["room"]["ephemeral"]["not_senders"] = filter->notSenders;
list["room"]["state"]["rooms"] = filter->Rooms;
list["room"]["state"]["not_rooms"] = filter->notRooms;
if (filter->Limit != 0) {
list["room"]["timeline"]["limit"] = filter->Limit;
}
list["room"]["timeline"]["not_rooms"] = filter->notRooms;
list["room"]["timeline"]["not_senders"] = filter->notSenders;
std::string Output { leet::invokeRequest_Post(leet::getAPI(APIUrl), list.dump(), resp->accessToken) };
json reqOutput;
try {
reqOutput = json::parse(Output);
} catch (const json::parse_error& e) {
return "";
}
for (auto& output : reqOutput) {
leet::errorCode = 0;
if (output["filter_id"].is_string()) {
return output["filter_id"].get<std::string>();
}
}
return "";
}

View file

@ -1,218 +1,218 @@
/* libleet
* Matrix client library written in C++
* Licensed under the GNU Affero General Public License version 3.
* See included LICENSE file for more information.
*
* https://git.speedie.site/speedie/libleet
*/
const std::string leet::invokeRequest_Get(const std::string& URL) {
/*
auto ret = cpr::Get(cpr::Url{ URL });
leet::networkStatusCode = ret.status_code;
return ret.text;
*/
leetRequest::URL url;
leetRequest::Request request;
url.parseURLFromString(URL);
request.Host = url.Host;
request.Endpoint = url.Endpoint;
request.Query = url.Query;
request.Port = url.Port;
request.Protocol = url.Protocol;
request.Type = leetRequest::LEET_REQUEST_REQTYPE_GET;
request.userAgent = "LIBLEET_USER_AGENT";
leetRequest::Response response = request.makeRequest();
leet::networkStatusCode = response.statusCode;
return response.Body;
}
const std::string leet::invokeRequest_Put(const std::string& URL, const std::string& Data) {
/*
auto ret = cpr::Put(cpr::Url{URL}, cpr::Body{Data});
leet::networkStatusCode = ret.status_code;
return ret.text;
*/
leetRequest::URL url;
leetRequest::Request request;
url.parseURLFromString(URL);
request.Host = url.Host;
request.Endpoint = url.Endpoint;
request.Query = url.Query;
request.Port = url.Port;
request.Protocol = url.Protocol;
request.Type = leetRequest::LEET_REQUEST_REQTYPE_PUT;
request.userAgent = "LIBLEET_USER_AGENT";
request.Body = Data;
leetRequest::Response response = request.makeRequest();
leet::networkStatusCode = response.statusCode;
return response.Body;
}
const std::string leet::invokeRequest_Post(const std::string& URL, const std::string& Data) {
/*
auto ret = cpr::Post(cpr::Url{URL}, cpr::Body{Data});
leet::networkStatusCode = ret.status_code;
return ret.text;
*/
leetRequest::URL url;
leetRequest::Request request;
url.parseURLFromString(URL);
request.Host = url.Host;
request.Endpoint = url.Endpoint;
request.Query = url.Query;
request.Port = url.Port;
request.Protocol = url.Protocol;
request.Type = leetRequest::LEET_REQUEST_REQTYPE_POST;
request.userAgent = "LIBLEET_USER_AGENT";
request.Body = Data;
leetRequest::Response response = request.makeRequest();
leet::networkStatusCode = response.statusCode;
return response.Body;
}
const std::string leet::invokeRequest_Get(const std::string& URL, const std::string& Authentication) {
/*
auto ret = cpr::Get(cpr::Url{ URL }, cpr::Header{{ "Authorization", "Bearer " + Authentication }});
leet::networkStatusCode = ret.status_code;
return ret.text;
*/
leetRequest::URL url;
leetRequest::Request request;
url.parseURLFromString(URL);
request.Host = url.Host;
request.Endpoint = url.Endpoint;
request.Query = url.Query;
request.Port = url.Port;
request.Protocol = url.Protocol;
request.Type = leetRequest::LEET_REQUEST_REQTYPE_GET;
request.userAgent = "LIBLEET_USER_AGENT";
request.setAuthenticationHeader("Bearer " + Authentication);
leetRequest::Response response = request.makeRequest();
leet::networkStatusCode = response.statusCode;
return response.Body;
}
const std::string leet::invokeRequest_Put(const std::string& URL, const std::string& Data, const std::string& Authentication) {
/*
auto ret = cpr::Put(cpr::Url{URL}, cpr::Body{Data}, cpr::Header{{ "Authorization", "Bearer " + Authentication }});
leet::networkStatusCode = ret.status_code;
return ret.text;
*/
leetRequest::URL url;
leetRequest::Request request;
url.parseURLFromString(URL);
request.Host = url.Host;
request.Endpoint = url.Endpoint;
request.Query = url.Query;
request.Port = url.Port;
request.Protocol = url.Protocol;
request.Type = leetRequest::LEET_REQUEST_REQTYPE_PUT;
request.userAgent = "LIBLEET_USER_AGENT";
request.Body = Data;
request.setAuthenticationHeader("Bearer " + Authentication);
leetRequest::Response response = request.makeRequest();
leet::networkStatusCode = response.statusCode;
return response.Body;
}
const std::string leet::invokeRequest_Post(const std::string& URL, const std::string& Data, const std::string& Authentication) {
/*
auto ret = cpr::Post(cpr::Url{URL}, cpr::Body{Data}, cpr::Header{{ "Authorization", "Bearer " + Authentication }});
leet::networkStatusCode = ret.status_code;
return ret.text;
*/
leetRequest::URL url;
leetRequest::Request request;
url.parseURLFromString(URL);
request.Host = url.Host;
request.Endpoint = url.Endpoint;
request.Query = url.Query;
request.Port = url.Port;
request.Protocol = url.Protocol;
request.Type = leetRequest::LEET_REQUEST_REQTYPE_POST;
request.userAgent = "LIBLEET_USER_AGENT";
request.Body = Data;
request.setAuthenticationHeader("Bearer " + Authentication);
leetRequest::Response response = request.makeRequest();
leet::networkStatusCode = response.statusCode;
return response.Body;
}
const std::string leet::invokeRequest_Post_File(const std::string& URL, const std::string& File, const std::string& Authentication) {
/*
std::filesystem::path file{ File }; if (!std::filesystem::exists(file)) return "";
auto ret = cpr::Post(cpr::Url{URL}, cpr::Body{ cpr::File{File} }, cpr::Header{{ "Authorization", "Bearer " + Authentication }, {"Content-Type", "application/octet-stream"}});
leet::networkStatusCode = ret.status_code;
return ret.text;
*/
std::filesystem::path file{ File }; if (!std::filesystem::exists(file)) return "";
leetRequest::URL url;
leetRequest::Request request;
url.parseURLFromString(URL);
request.Host = url.Host;
request.Endpoint = url.Endpoint;
request.Query = url.Query;
request.Port = url.Port;
request.Protocol = url.Protocol;
request.Type = leetRequest::LEET_REQUEST_REQTYPE_POST;
request.userAgent = "LIBLEET_USER_AGENT";
request.Filename = File;
request.setAuthenticationHeader("Bearer " + Authentication);
request.setContentTypeHeader("application/octet-stream");
leetRequest::Response response = request.makeRequest();
leet::networkStatusCode = response.statusCode;
return response.Body;
}
const std::string leet::invokeRequest_Post_File(const std::string& URL, const std::string& File) {
/*
std::filesystem::path file{ File }; if (!std::filesystem::exists(file)) return "";
auto ret = cpr::Post(cpr::Url{URL}, cpr::Body{ cpr::File{File} }, cpr::Header{{"Content-Type", "application/octet-stream"}});
leet::networkStatusCode = ret.status_code;
return ret.text;
*/
std::filesystem::path file{ File }; if (!std::filesystem::exists(file)) return "";
leetRequest::URL url;
leetRequest::Request request;
url.parseURLFromString(URL);
request.Host = url.Host;
request.Endpoint = url.Endpoint;
request.Query = url.Query;
request.Port = url.Port;
request.Protocol = url.Protocol;
request.Type = leetRequest::LEET_REQUEST_REQTYPE_POST;
request.userAgent = "LIBLEET_USER_AGENT";
request.Filename = File;
request.setContentTypeHeader("application/octet-stream");
leetRequest::Response response = request.makeRequest();
leet::networkStatusCode = response.statusCode;
return response.Body;
}
/* libleet
* Matrix client library written in C++
* Licensed under the GNU Affero General Public License version 3.
* See included LICENSE file for more information.
*
* https://git.speedie.site/speedie/libleet
*/
const std::string leet::invokeRequest_Get(const std::string& URL) {
/*
auto ret = cpr::Get(cpr::Url{ URL });
leet::networkStatusCode = ret.status_code;
return ret.text;
*/
leetRequest::URL url;
leetRequest::Request request;
url.parseURLFromString(URL);
request.Host = url.Host;
request.Endpoint = url.Endpoint;
request.Query = url.Query;
request.Port = url.Port;
request.Protocol = url.Protocol;
request.Type = leetRequest::LEET_REQUEST_REQTYPE_GET;
request.userAgent = "LIBLEET_USER_AGENT";
leetRequest::Response response = request.makeRequest();
leet::networkStatusCode = response.statusCode;
return response.Body;
}
const std::string leet::invokeRequest_Put(const std::string& URL, const std::string& Data) {
/*
auto ret = cpr::Put(cpr::Url{URL}, cpr::Body{Data});
leet::networkStatusCode = ret.status_code;
return ret.text;
*/
leetRequest::URL url;
leetRequest::Request request;
url.parseURLFromString(URL);
request.Host = url.Host;
request.Endpoint = url.Endpoint;
request.Query = url.Query;
request.Port = url.Port;
request.Protocol = url.Protocol;
request.Type = leetRequest::LEET_REQUEST_REQTYPE_PUT;
request.userAgent = "LIBLEET_USER_AGENT";
request.Body = Data;
leetRequest::Response response = request.makeRequest();
leet::networkStatusCode = response.statusCode;
return response.Body;
}
const std::string leet::invokeRequest_Post(const std::string& URL, const std::string& Data) {
/*
auto ret = cpr::Post(cpr::Url{URL}, cpr::Body{Data});
leet::networkStatusCode = ret.status_code;
return ret.text;
*/
leetRequest::URL url;
leetRequest::Request request;
url.parseURLFromString(URL);
request.Host = url.Host;
request.Endpoint = url.Endpoint;
request.Query = url.Query;
request.Port = url.Port;
request.Protocol = url.Protocol;
request.Type = leetRequest::LEET_REQUEST_REQTYPE_POST;
request.userAgent = "LIBLEET_USER_AGENT";
request.Body = Data;
leetRequest::Response response = request.makeRequest();
leet::networkStatusCode = response.statusCode;
return response.Body;
}
const std::string leet::invokeRequest_Get(const std::string& URL, const std::string& Authentication) {
/*
auto ret = cpr::Get(cpr::Url{ URL }, cpr::Header{{ "Authorization", "Bearer " + Authentication }});
leet::networkStatusCode = ret.status_code;
return ret.text;
*/
leetRequest::URL url;
leetRequest::Request request;
url.parseURLFromString(URL);
request.Host = url.Host;
request.Endpoint = url.Endpoint;
request.Query = url.Query;
request.Port = url.Port;
request.Protocol = url.Protocol;
request.Type = leetRequest::LEET_REQUEST_REQTYPE_GET;
request.userAgent = "LIBLEET_USER_AGENT";
request.setAuthenticationHeader("Bearer " + Authentication);
leetRequest::Response response = request.makeRequest();
leet::networkStatusCode = response.statusCode;
return response.Body;
}
const std::string leet::invokeRequest_Put(const std::string& URL, const std::string& Data, const std::string& Authentication) {
/*
auto ret = cpr::Put(cpr::Url{URL}, cpr::Body{Data}, cpr::Header{{ "Authorization", "Bearer " + Authentication }});
leet::networkStatusCode = ret.status_code;
return ret.text;
*/
leetRequest::URL url;
leetRequest::Request request;
url.parseURLFromString(URL);
request.Host = url.Host;
request.Endpoint = url.Endpoint;
request.Query = url.Query;
request.Port = url.Port;
request.Protocol = url.Protocol;
request.Type = leetRequest::LEET_REQUEST_REQTYPE_PUT;
request.userAgent = "LIBLEET_USER_AGENT";
request.Body = Data;
request.setAuthenticationHeader("Bearer " + Authentication);
leetRequest::Response response = request.makeRequest();
leet::networkStatusCode = response.statusCode;
return response.Body;
}
const std::string leet::invokeRequest_Post(const std::string& URL, const std::string& Data, const std::string& Authentication) {
/*
auto ret = cpr::Post(cpr::Url{URL}, cpr::Body{Data}, cpr::Header{{ "Authorization", "Bearer " + Authentication }});
leet::networkStatusCode = ret.status_code;
return ret.text;
*/
leetRequest::URL url;
leetRequest::Request request;
url.parseURLFromString(URL);
request.Host = url.Host;
request.Endpoint = url.Endpoint;
request.Query = url.Query;
request.Port = url.Port;
request.Protocol = url.Protocol;
request.Type = leetRequest::LEET_REQUEST_REQTYPE_POST;
request.userAgent = "LIBLEET_USER_AGENT";
request.Body = Data;
request.setAuthenticationHeader("Bearer " + Authentication);
leetRequest::Response response = request.makeRequest();
leet::networkStatusCode = response.statusCode;
return response.Body;
}
const std::string leet::invokeRequest_Post_File(const std::string& URL, const std::string& File, const std::string& Authentication) {
/*
std::filesystem::path file{ File }; if (!std::filesystem::exists(file)) return "";
auto ret = cpr::Post(cpr::Url{URL}, cpr::Body{ cpr::File{File} }, cpr::Header{{ "Authorization", "Bearer " + Authentication }, {"Content-Type", "application/octet-stream"}});
leet::networkStatusCode = ret.status_code;
return ret.text;
*/
std::filesystem::path file{ File }; if (!std::filesystem::exists(file)) return "";
leetRequest::URL url;
leetRequest::Request request;
url.parseURLFromString(URL);
request.Host = url.Host;
request.Endpoint = url.Endpoint;
request.Query = url.Query;
request.Port = url.Port;
request.Protocol = url.Protocol;
request.Type = leetRequest::LEET_REQUEST_REQTYPE_POST;
request.userAgent = "LIBLEET_USER_AGENT";
request.Filename = File;
request.setAuthenticationHeader("Bearer " + Authentication);
request.setContentTypeHeader("application/octet-stream");
leetRequest::Response response = request.makeRequest();
leet::networkStatusCode = response.statusCode;
return response.Body;
}
const std::string leet::invokeRequest_Post_File(const std::string& URL, const std::string& File) {
/*
std::filesystem::path file{ File }; if (!std::filesystem::exists(file)) return "";
auto ret = cpr::Post(cpr::Url{URL}, cpr::Body{ cpr::File{File} }, cpr::Header{{"Content-Type", "application/octet-stream"}});
leet::networkStatusCode = ret.status_code;
return ret.text;
*/
std::filesystem::path file{ File }; if (!std::filesystem::exists(file)) return "";
leetRequest::URL url;
leetRequest::Request request;
url.parseURLFromString(URL);
request.Host = url.Host;
request.Endpoint = url.Endpoint;
request.Query = url.Query;
request.Port = url.Port;
request.Protocol = url.Protocol;
request.Type = leetRequest::LEET_REQUEST_REQTYPE_POST;
request.userAgent = "LIBLEET_USER_AGENT";
request.Filename = File;
request.setContentTypeHeader("application/octet-stream");
leetRequest::Response response = request.makeRequest();
leet::networkStatusCode = response.statusCode;
return response.Body;
}

File diff suppressed because it is too large Load diff

View file

@ -1,214 +1,214 @@
/* libleet
* Matrix client library written in C++
* Licensed under the GNU Affero General Public License version 3.
* See included LICENSE file for more information.
*
* https://git.speedie.site/speedie/libleet
*/
/* Converts a username to a proper user ID if necessary (i.e. speedie -> @speedie:matrix.org) */
const std::string leet::findUserID(const std::string& Alias, const std::string& Homeserver) {
if (Alias[0] != '@')
return "@" + Alias + ":" + Homeserver;
return Alias;
}
/* leet::findUserID in reverse */
const std::string leet::returnUserName(const std::string& userID) {
std::string str;
std::regex pattern{"@([^:]+):"};
std::smatch reg;
if (std::regex_search(userID, reg, pattern)) return reg[1].str();
return str;
}
/* Returns a leet::User::Profile class containing things such as display name and avatar URL */
leet::User::Profile leet::getUserData(leet::User::credentialsResponse* resp, const std::string& userID) {
using json = nlohmann::json;
leet::errorCode = 0;
leet::User::Profile profile;
if (userID[0] != '@') {
return profile;
}
profile.userID = leet::findUserID(userID, resp->Homeserver);
if (profile.userID.empty()) {
leet::errorCode = 1;
leet::friendlyError = "Failed to get User ID";
return profile;
}
const std::string API { leet::getAPI("/_matrix/client/v3/profile/" + profile.userID) };
const std::string Output = invokeRequest_Get(API);
json reqOutput;
try {
reqOutput = { json::parse(Output) };
} catch (const json::parse_error& e) {
return profile;
}
for (auto& output : reqOutput) {
if (output["avatar_url"].is_string()) profile.avatarURL = output["avatar_url"].get<std::string>();
if (output["displayname"].is_string()) profile.displayName = output["displayname"].get<std::string>();
if (output["errcode"].is_string()) {
leet::errorCode = 1;
leet::Error = output["errcode"].get<std::string>();
if (output["error"].is_string()) leet::friendlyError = output["error"].get<std::string>();
}
}
leet::User::Profile userProfile;
userProfile.userID = userID;
std::vector<leet::User::Profile> User = { userProfile };
profile.Devices = leet::returnDevicesFromUser(resp, User);
return profile;
}
/* Returns an array of all devices for a user */
const std::vector<leet::User::Device> leet::returnDevicesFromUser(leet::User::credentialsResponse* resp, const std::vector<leet::User::Profile>& user) {
std::vector<leet::User::Device> devices;
using json = nlohmann::json;
json Body;
json deviceKeys;
for (auto& theUser : user) {
deviceKeys[theUser.userID] = json::array();
Body["device_keys"] = deviceKeys;
Body["timeout"] = 10000;
}
const std::string Output = leet::invokeRequest_Post(leet::getAPI("/_matrix/client/v3/keys/query"), Body.dump(), resp->accessToken);
json returnOutput;
try {
returnOutput = json::parse(Output);
} catch (const json::parse_error& e) {
return devices;
}
for (auto& userID : user) {
auto& deviceList = returnOutput["device_keys"][userID.userID];
for (auto it = deviceList.begin(); it != deviceList.end(); ++it) {
leet::User::Device device;
device.userID = userID.userID;
device.deviceID = it.key();
json::json_pointer curve25519Pointer("/keys/curve25519:" + device.deviceID);
if (it.value().contains(curve25519Pointer)) {
device.curve25519Key = it.value()["keys"]["curve25519:" + device.deviceID];
}
json::json_pointer ed25519Pointer("/keys/ed25519:" + device.deviceID);
if (it.value().contains(ed25519Pointer)) {
device.ed25519Key = it.value()["keys"]["ed25519:" + device.deviceID];
}
json::json_pointer ed25519SigPointer("/signatures/" + userID.userID + "/ed25519:" + device.deviceID);
if (it.value().contains(ed25519SigPointer)) {
device.ed25519Signature = it.value()["signatures"][userID.userID]["ed25519:" + device.deviceID];
}
if (it.value().contains("/unsigned/device_display_name"_json_pointer)) {
device.deviceDisplayName = it.value()["unsigned"]["device_display_name"];
}
device.olm = false;
device.megolm = false;
if (std::find(it.value()["algorithms"].begin(), it.value()["algorithms"].end(), "m.olm.v1.curve25519-aes-sha2") != it.value()["algorithms"].end())
device.olm = true;
if (std::find(it.value()["algorithms"].begin(), it.value()["algorithms"].end(), "m.megolm.v1.aes-sha2") != it.value()["algorithms"].end())
device.megolm = true;
devices.push_back(device);
}
}
return devices;
}
/* Returns true if username is valid and available for registering */
const bool leet::checkIfUsernameIsAvailable(const std::string& Username) {
using json = nlohmann::json;
leet::errorCode = 0;
std::string theUsername = Username;
if (Username[0] == '@') {
theUsername = leet::returnUserName(Username);
if (theUsername[0] == '@' || !theUsername.compare("")) {
return false;
leet::errorCode = 1;
}
}
const std::string API { leet::getAPI("/_matrix/client/v3/register/available?username=" + theUsername) };
const std::string Output = invokeRequest_Get(API);
json reqOutput;
try {
reqOutput = { json::parse(Output) };
} catch (const json::parse_error& e) {
return false; // fallback to false is probably safest?
}
for (auto& output : reqOutput) {
if (output["errcode"].is_string()) {
leet::errorCode = 1;
leet::Error = output["errcode"].get<std::string>();
if (output["error"].is_string()) leet::friendlyError = output["error"].get<std::string>();
return false;
}
if (output["available"].is_boolean()) {
return output["available"].get<bool>();
}
}
return false;
}
/* Returns an array of all users in a room */
const std::vector<leet::User::Profile> leet::returnUsersInRoom(leet::User::credentialsResponse* resp, leet::Room::Room* room) {
using json = nlohmann::json;
std::vector<leet::User::Profile> vector;
const std::string Output = leet::invokeRequest_Get(leet::getAPI("/_matrix/client/v3/rooms/" + room->roomID + "/joined_members"), resp->accessToken);
json returnOutput;
try {
returnOutput = json::parse(Output);
} catch (const json::parse_error& e) {
return vector;
}
auto& users = returnOutput["joined"];
for (auto it = users.begin(); it != users.end(); ++it) {
leet::User::Profile profile;
if (it.value().contains("avatar_url") && !it.value()["avatar_url"].is_null()) profile.avatarURL = it.value()["avatar_url"];
if (it.value().contains("display_name") && !it.value()["display_name"].is_null()) profile.displayName = it.value()["display_name"];
profile.userID = it.key();
leet::User::Profile userProfile;
userProfile.userID = it.key();
std::vector<leet::User::Profile> User = { userProfile };
profile.Devices = leet::returnDevicesFromUser(resp, User);
vector.push_back(profile);
}
return vector;
}
/* libleet
* Matrix client library written in C++
* Licensed under the GNU Affero General Public License version 3.
* See included LICENSE file for more information.
*
* https://git.speedie.site/speedie/libleet
*/
/* Converts a username to a proper user ID if necessary (i.e. speedie -> @speedie:matrix.org) */
const std::string leet::findUserID(const std::string& Alias, const std::string& Homeserver) {
if (Alias[0] != '@')
return "@" + Alias + ":" + Homeserver;
return Alias;
}
/* leet::findUserID in reverse */
const std::string leet::returnUserName(const std::string& userID) {
std::string str;
std::regex pattern{"@([^:]+):"};
std::smatch reg;
if (std::regex_search(userID, reg, pattern)) return reg[1].str();
return str;
}
/* Returns a leet::User::Profile class containing things such as display name and avatar URL */
leet::User::Profile leet::getUserData(leet::User::credentialsResponse* resp, const std::string& userID) {
using json = nlohmann::json;
leet::errorCode = 0;
leet::User::Profile profile;
if (userID[0] != '@') {
return profile;
}
profile.userID = leet::findUserID(userID, resp->Homeserver);
if (profile.userID.empty()) {
leet::errorCode = 1;
leet::friendlyError = "Failed to get User ID";
return profile;
}
const std::string API { leet::getAPI("/_matrix/client/v3/profile/" + profile.userID) };
const std::string Output = invokeRequest_Get(API);
json reqOutput;
try {
reqOutput = { json::parse(Output) };
} catch (const json::parse_error& e) {
return profile;
}
for (auto& output : reqOutput) {
if (output["avatar_url"].is_string()) profile.avatarURL = output["avatar_url"].get<std::string>();
if (output["displayname"].is_string()) profile.displayName = output["displayname"].get<std::string>();
if (output["errcode"].is_string()) {
leet::errorCode = 1;
leet::Error = output["errcode"].get<std::string>();
if (output["error"].is_string()) leet::friendlyError = output["error"].get<std::string>();
}
}
leet::User::Profile userProfile;
userProfile.userID = userID;
std::vector<leet::User::Profile> User = { userProfile };
profile.Devices = leet::returnDevicesFromUser(resp, User);
return profile;
}
/* Returns an array of all devices for a user */
const std::vector<leet::User::Device> leet::returnDevicesFromUser(leet::User::credentialsResponse* resp, const std::vector<leet::User::Profile>& user) {
std::vector<leet::User::Device> devices;
using json = nlohmann::json;
json Body;
json deviceKeys;
for (auto& theUser : user) {
deviceKeys[theUser.userID] = json::array();
Body["device_keys"] = deviceKeys;
Body["timeout"] = 10000;
}
const std::string Output = leet::invokeRequest_Post(leet::getAPI("/_matrix/client/v3/keys/query"), Body.dump(), resp->accessToken);
json returnOutput;
try {
returnOutput = json::parse(Output);
} catch (const json::parse_error& e) {
return devices;
}
for (auto& userID : user) {
auto& deviceList = returnOutput["device_keys"][userID.userID];
for (auto it = deviceList.begin(); it != deviceList.end(); ++it) {
leet::User::Device device;
device.userID = userID.userID;
device.deviceID = it.key();
json::json_pointer curve25519Pointer("/keys/curve25519:" + device.deviceID);
if (it.value().contains(curve25519Pointer)) {
device.curve25519Key = it.value()["keys"]["curve25519:" + device.deviceID];
}
json::json_pointer ed25519Pointer("/keys/ed25519:" + device.deviceID);
if (it.value().contains(ed25519Pointer)) {
device.ed25519Key = it.value()["keys"]["ed25519:" + device.deviceID];
}
json::json_pointer ed25519SigPointer("/signatures/" + userID.userID + "/ed25519:" + device.deviceID);
if (it.value().contains(ed25519SigPointer)) {
device.ed25519Signature = it.value()["signatures"][userID.userID]["ed25519:" + device.deviceID];
}
if (it.value().contains("/unsigned/device_display_name"_json_pointer)) {
device.deviceDisplayName = it.value()["unsigned"]["device_display_name"];
}
device.olm = false;
device.megolm = false;
if (std::find(it.value()["algorithms"].begin(), it.value()["algorithms"].end(), "m.olm.v1.curve25519-aes-sha2") != it.value()["algorithms"].end())
device.olm = true;
if (std::find(it.value()["algorithms"].begin(), it.value()["algorithms"].end(), "m.megolm.v1.aes-sha2") != it.value()["algorithms"].end())
device.megolm = true;
devices.push_back(device);
}
}
return devices;
}
/* Returns true if username is valid and available for registering */
const bool leet::checkIfUsernameIsAvailable(const std::string& Username) {
using json = nlohmann::json;
leet::errorCode = 0;
std::string theUsername = Username;
if (Username[0] == '@') {
theUsername = leet::returnUserName(Username);
if (theUsername[0] == '@' || !theUsername.compare("")) {
return false;
leet::errorCode = 1;
}
}
const std::string API { leet::getAPI("/_matrix/client/v3/register/available?username=" + theUsername) };
const std::string Output = invokeRequest_Get(API);
json reqOutput;
try {
reqOutput = { json::parse(Output) };
} catch (const json::parse_error& e) {
return false; // fallback to false is probably safest?
}
for (auto& output : reqOutput) {
if (output["errcode"].is_string()) {
leet::errorCode = 1;
leet::Error = output["errcode"].get<std::string>();
if (output["error"].is_string()) leet::friendlyError = output["error"].get<std::string>();
return false;
}
if (output["available"].is_boolean()) {
return output["available"].get<bool>();
}
}
return false;
}
/* Returns an array of all users in a room */
const std::vector<leet::User::Profile> leet::returnUsersInRoom(leet::User::credentialsResponse* resp, leet::Room::Room* room) {
using json = nlohmann::json;
std::vector<leet::User::Profile> vector;
const std::string Output = leet::invokeRequest_Get(leet::getAPI("/_matrix/client/v3/rooms/" + room->roomID + "/joined_members"), resp->accessToken);
json returnOutput;
try {
returnOutput = json::parse(Output);
} catch (const json::parse_error& e) {
return vector;
}
auto& users = returnOutput["joined"];
for (auto it = users.begin(); it != users.end(); ++it) {
leet::User::Profile profile;
if (it.value().contains("avatar_url") && !it.value()["avatar_url"].is_null()) profile.avatarURL = it.value()["avatar_url"];
if (it.value().contains("display_name") && !it.value()["display_name"].is_null()) profile.displayName = it.value()["display_name"];
profile.userID = it.key();
leet::User::Profile userProfile;
userProfile.userID = it.key();
std::vector<leet::User::Profile> User = { userProfile };
profile.Devices = leet::returnDevicesFromUser(resp, User);
vector.push_back(profile);
}
return vector;
}

View file

@ -1,37 +1,37 @@
/* libleet
* Matrix client library written in C++
* Licensed under the GNU Affero General Public License version 3.
* See included LICENSE file for more information.
*
* https://git.speedie.site/speedie/libleet
*/
leet::VOIP::Credentials leet::returnTurnCredentials(leet::User::credentialsResponse* resp) {
leet::VOIP::Credentials cred;
using json = nlohmann::json;
const std::string APIUrl { "/_matrix/client/v3/voip/turnServer" };
const std::string Output { leet::invokeRequest_Get(leet::getAPI(APIUrl), resp->accessToken) };
json reqOutput;
try {
reqOutput = { json::parse(Output) };
} catch (const json::parse_error& e) {
return cred;
}
for (auto& output : reqOutput) {
leet::errorCode = 0;
if (output["uris"].is_array()) cred.URI = output["uris"];
if (output["username"].is_string()) cred.Username = output["username"].get<std::string>();
if (output["password"].is_string()) cred.Password = output["password"].get<std::string>();
if (output["ttl"].is_number_integer()) cred.timeToLiveIn = output["ttl"].get<int>();
if (output["errcode"].is_string()) leet::Error = output["errcode"].get<std::string>();
if (output["error"].is_string()) leet::friendlyError = output["error"].get<std::string>();
}
return cred;
}
/* libleet
* Matrix client library written in C++
* Licensed under the GNU Affero General Public License version 3.
* See included LICENSE file for more information.
*
* https://git.speedie.site/speedie/libleet
*/
leet::VOIP::Credentials leet::returnTurnCredentials(leet::User::credentialsResponse* resp) {
leet::VOIP::Credentials cred;
using json = nlohmann::json;
const std::string APIUrl { "/_matrix/client/v3/voip/turnServer" };
const std::string Output { leet::invokeRequest_Get(leet::getAPI(APIUrl), resp->accessToken) };
json reqOutput;
try {
reqOutput = { json::parse(Output) };
} catch (const json::parse_error& e) {
return cred;
}
for (auto& output : reqOutput) {
leet::errorCode = 0;
if (output["uris"].is_array()) cred.URI = output["uris"];
if (output["username"].is_string()) cred.Username = output["username"].get<std::string>();
if (output["password"].is_string()) cred.Password = output["password"].get<std::string>();
if (output["ttl"].is_number_integer()) cred.timeToLiveIn = output["ttl"].get<int>();
if (output["errcode"].is_string()) leet::Error = output["errcode"].get<std::string>();
if (output["error"].is_string()) leet::friendlyError = output["error"].get<std::string>();
}
return cred;
}

View file

@ -1,141 +1,141 @@
/* libleet
* Matrix client library written in C++
* Licensed under the GNU Affero General Public License version 3.
* See included LICENSE file for more information.
*
* https://git.speedie.site/speedie/libleet
*/
#include <iostream>
#include <fstream>
#include <sstream>
#include <future>
#include <vector>
#include <regex>
#include <filesystem>
#include <chrono>
#include <nlohmann/json.hpp>
#ifndef LEET_NO_ENCRYPTION
#include <olm/error.h>
#include <olm/olm.h>
#include <olm/sas.h>
#endif
#include "../include/libleet.hpp"
#include "net/Request.cpp"
#include "Encryption.cpp"
#include "Login.cpp"
#include "Request.cpp"
#include "User.cpp"
#include "Room.cpp"
#include "Message.cpp"
#include "File.cpp"
#include "Event.cpp"
#include "Voip.cpp"
const std::string leet::getAPI(const std::string& API) {
return leet::Homeserver + API;
}
const int leet::generateTransID() {
return ++leet::transID;
}
const std::string leet::returnServerDiscovery(std::string Server) {
using json = nlohmann::json;
leet::errorCode = 0;
if (Server[0] != 'h' || Server[1] != 't' || Server[2] != 't' || Server[3] != 'p') {
Server = "https://" + Server;
}
const std::string Output = leet::invokeRequest_Get(Server + "/.well-known/matrix/client");
if (json::accept(Output)) {
json reqOutput;
try {
reqOutput = { json::parse(Output) };
} catch (const json::parse_error& e) {
return Server;
}
for (auto& output : reqOutput)
if (output["m.homeserver"]["base_url"].is_string())
return output["m.homeserver"]["base_url"].get<std::string>();
}
return Server;
}
const std::string leet::returnHomeServerFromString(const std::string& userID) {
std::string uid{userID};
if (uid[0] != '@') {
leet::errorCode = 1;
return "";
}
std::size_t colonPosition = uid.find(':');
if (colonPosition != std::string::npos) return uid.substr(colonPosition + 1);
return "";
}
std::vector<std::string> leet::returnSupportedSpecs() {
using json = nlohmann::json;
std::vector<std::string> vector;
const std::string APIUrl { "/_matrix/client/versions" };
std::string Output { leet::invokeRequest_Get(leet::getAPI(APIUrl)) };
json reqOutput;
try {
reqOutput = { json::parse(Output) };
} catch (const json::parse_error& e) {
return vector;
}
for (auto& output : reqOutput) {
leet::errorCode = 0;
if (output["versions"].is_array()) {
vector = output["versions"];
break;
}
}
return vector;
}
const int leet::returnMaxUploadLimit(leet::User::credentialsResponse* resp) {
using json = nlohmann::json;
const std::string APIUrl { "/_matrix/media/v3/config" };
const std::string Output { leet::invokeRequest_Get(leet::getAPI(APIUrl), resp->accessToken) };
json reqOutput;
try {
reqOutput = { json::parse(Output) };
} catch (const json::parse_error& e) {
return 0;
}
for (auto& output : reqOutput) {
leet::errorCode = 0;
if (output["m.upload.size"].is_number_integer()) return output["m.upload.size"].get<int>();
if (output["errcode"].is_string()) leet::Error = output["errcode"].get<std::string>();
if (output["error"].is_string()) leet::friendlyError = output["error"].get<std::string>();
}
return 0;
}
const bool leet::checkError() {
if (leet::errorCode != 0 || leet::Error.compare("")) {
return false;
}
return true;
}
/* libleet
* Matrix client library written in C++
* Licensed under the GNU Affero General Public License version 3.
* See included LICENSE file for more information.
*
* https://git.speedie.site/speedie/libleet
*/
#include <iostream>
#include <fstream>
#include <sstream>
#include <future>
#include <vector>
#include <regex>
#include <filesystem>
#include <chrono>
#include <nlohmann/json.hpp>
#ifndef LEET_NO_ENCRYPTION
#include <olm/error.h>
#include <olm/olm.h>
#include <olm/sas.h>
#endif
#include "../include/libleet.hpp"
#include "net/Request.cpp"
#include "Encryption.cpp"
#include "Login.cpp"
#include "Request.cpp"
#include "User.cpp"
#include "Room.cpp"
#include "Message.cpp"
#include "File.cpp"
#include "Event.cpp"
#include "Voip.cpp"
const std::string leet::getAPI(const std::string& API) {
return leet::Homeserver + API;
}
const int leet::generateTransID() {
return ++leet::transID;
}
const std::string leet::returnServerDiscovery(std::string Server) {
using json = nlohmann::json;
leet::errorCode = 0;
if (Server[0] != 'h' || Server[1] != 't' || Server[2] != 't' || Server[3] != 'p') {
Server = "https://" + Server;
}
const std::string Output = leet::invokeRequest_Get(Server + "/.well-known/matrix/client");
if (json::accept(Output)) {
json reqOutput;
try {
reqOutput = { json::parse(Output) };
} catch (const json::parse_error& e) {
return Server;
}
for (auto& output : reqOutput)
if (output["m.homeserver"]["base_url"].is_string())
return output["m.homeserver"]["base_url"].get<std::string>();
}
return Server;
}
const std::string leet::returnHomeServerFromString(const std::string& userID) {
std::string uid{userID};
if (uid[0] != '@') {
leet::errorCode = 1;
return "";
}
std::size_t colonPosition = uid.find(':');
if (colonPosition != std::string::npos) return uid.substr(colonPosition + 1);
return "";
}
std::vector<std::string> leet::returnSupportedSpecs() {
using json = nlohmann::json;
std::vector<std::string> vector;
const std::string APIUrl { "/_matrix/client/versions" };
std::string Output { leet::invokeRequest_Get(leet::getAPI(APIUrl)) };
json reqOutput;
try {
reqOutput = { json::parse(Output) };
} catch (const json::parse_error& e) {
return vector;
}
for (auto& output : reqOutput) {
leet::errorCode = 0;
if (output["versions"].is_array()) {
vector = output["versions"];
break;
}
}
return vector;
}
const int leet::returnMaxUploadLimit(leet::User::credentialsResponse* resp) {
using json = nlohmann::json;
const std::string APIUrl { "/_matrix/media/v3/config" };
const std::string Output { leet::invokeRequest_Get(leet::getAPI(APIUrl), resp->accessToken) };
json reqOutput;
try {
reqOutput = { json::parse(Output) };
} catch (const json::parse_error& e) {
return 0;
}
for (auto& output : reqOutput) {
leet::errorCode = 0;
if (output["m.upload.size"].is_number_integer()) return output["m.upload.size"].get<int>();
if (output["errcode"].is_string()) leet::Error = output["errcode"].get<std::string>();
if (output["error"].is_string()) leet::friendlyError = output["error"].get<std::string>();
}
return 0;
}
const bool leet::checkError() {
if (leet::errorCode != 0 || leet::Error.compare("")) {
return false;
}
return true;
}

File diff suppressed because it is too large Load diff

View file

@ -1,210 +1,210 @@
/* libleet
* Matrix client library written in C++
* Licensed under the GNU Affero General Public License version 3.
* See included LICENSE file for more information.
*
* https://git.speedie.site/speedie/libleet
*/
#include <iostream>
#include <string>
#include <regex>
#include <filesystem>
#include <fstream>
#include <sstream>
#include "../../include/net/Request.hpp"
#include "Cert.cpp"
void leetRequest::URL::parseURLFromString(const std::string& URL) {
std::regex urlReg("(http|https)://([^/ :]+):?([^/ ]*)(/?[^ #?]*)\\x3f?([^ #]*)#?([^ ]*)");
std::smatch Match;
if (std::regex_match(URL, Match, urlReg)) {
if (!Match[1].str().compare("https")) {
Protocol = leetRequest::LEET_REQUEST_PROTOCOL_HTTPS;
Port = 443;
} else {
Protocol = leetRequest::LEET_REQUEST_PROTOCOL_HTTP;
Port = 80;
}
Host = Match[2].str();
if (Match[3].str().compare("")) {
Port = std::stoi(Match[3].str());
}
Endpoint = Match[4].str();
if (Match[5].str().compare("")) {
Query = "?" + Match[5].str();
}
}
}
const std::string leetRequest::URL::assembleURLFromParts() {
std::string ret{};
if (Protocol == leetRequest::LEET_REQUEST_PROTOCOL_HTTPS) {
ret += "https://" + Host;
} else {
ret += "http://" + Host;
}
if (!(Protocol == leetRequest::LEET_REQUEST_PROTOCOL_HTTPS && Port == 443) &&
!(Protocol == leetRequest::LEET_REQUEST_PROTOCOL_HTTP && Port == 80)) {
ret += ":" + std::to_string(Port);
}
ret += Endpoint + Query;
return ret;
}
void leetRequest::Request::setHeader(const std::string& Header, const std::string& Data) {
headerName.push_back(Header);
headerData.push_back(Data);
}
void leetRequest::Request::setAuthenticationHeader(const std::string& Data) {
authenticationHeaderData = Data;
Authentication = true;
}
void leetRequest::Request::setContentTypeHeader(const std::string& Data) {
contentTypeHeaderData = Data;
}
leetRequest::Response leetRequest::Request::makeRequest() {
leetRequest::Response resp;
try {
boost::asio::ssl::context ctx(boost::asio::ssl::context::tlsv12_client);
leetRequest::applyRootCertificates(ctx, leetRequest::getRootCertificates());
boost::asio::io_context ioc;
boost::asio::ip::tcp::resolver resolver(ioc);
ctx.set_verify_mode(boost::asio::ssl::verify_peer);
ctx.set_verify_callback(boost::asio::ssl::host_name_verification(Host));
boost::beast::ssl_stream<boost::beast::tcp_stream> stream(ioc, ctx);
if (!SSL_set_tlsext_host_name(stream.native_handle(), Host.c_str())) {
boost::beast::error_code ec{static_cast<int>(::ERR_get_error()), boost::asio::error::get_ssl_category()};
throw boost::beast::system_error{ec};
}
const auto results { resolver.resolve(Host, std::to_string(Port)) };
boost::beast::get_lowest_layer(stream).connect(results);
stream.handshake(boost::asio::ssl::stream_base::client);
boost::beast::http::verb theVerb;
switch (Type) {
case leetRequest::LEET_REQUEST_REQTYPE_GET:
theVerb = boost::beast::http::verb::get;
break;
case leetRequest::LEET_REQUEST_REQTYPE_POST:
theVerb = boost::beast::http::verb::post;
break;
case leetRequest::LEET_REQUEST_REQTYPE_PUT:
theVerb = boost::beast::http::verb::put;
break;
default:
break;
}
boost::beast::http::request<boost::beast::http::string_body> httpRequest{theVerb, Host + std::to_string(Port), 11};
httpRequest.set(boost::beast::http::field::host, Host);
if (userAgent.compare("")) httpRequest.set(boost::beast::http::field::user_agent, userAgent);
if (contentTypeHeaderData.compare("")) httpRequest.set(boost::beast::http::field::content_type, contentTypeHeaderData);
if (Body.compare("")) httpRequest.body() = Body;
if (Authentication) httpRequest.set(boost::beast::http::field::authorization, authenticationHeaderData);
for (int it{0}; it < static_cast<int>(headerName.size()); ++it) {
if (!headerName[it].compare("") || !headerData[it].compare("")) {
continue;
}
httpRequest.set(headerName[it], headerData[it]);
}
if (Filename.compare("")) {
std::filesystem::path fileName = Filename;
if (std::filesystem::exists(fileName)) {
std::ostringstream fileBody;
fileBody << std::ifstream(fileName, std::ios::binary).rdbuf();
std::string theBody{ std::move(fileBody).str() };
httpRequest.body() = theBody;
httpRequest.set(boost::beast::http::field::content_length, std::to_string(theBody.size()));
}
}
httpRequest.target(Endpoint + Query);
httpRequest.prepare_payload();
boost::beast::http::write(stream, httpRequest);
boost::beast::flat_buffer flat_buffer;
boost::beast::http::response<boost::beast::http::dynamic_body> res;
boost::beast::http::read(stream, flat_buffer, res);
resp.statusCode = res.result_int();
resp.Body = boost::beast::buffers_to_string(res.body().data());
boost::beast::error_code ec;
stream.next_layer().cancel();
stream.shutdown(ec);
stream.next_layer().close();
if (ec == boost::asio::error::eof) {
ec = {};
}
if (ec == boost::asio::ssl::error::stream_truncated) {
return resp;
}
if (ec) {
throw boost::beast::system_error{ec};
}
return resp;
} catch (boost::wrapexcept<boost::system::system_error> const &e) {
std::cout << e.what();
}
return resp;
}
const bool leetRequest::Request::downloadFile() {
if (!outputFile.compare("")) return false;
leetRequest::Response resp = makeRequest();
std::ofstream of(outputFile, std::ios::binary);
of << resp.Body;
if (resp.statusCode == 200) {
return true;
}
return false;
}
void leetRequest::applyRootCertificates(boost::asio::ssl::context& ctx, const std::string& cert) {
boost::system::error_code ec;
ctx.add_certificate_authority(boost::asio::buffer(cert.data(), cert.size()), ec);
if (ec) {
throw boost::system::system_error{ec};
}
}
/* libleet
* Matrix client library written in C++
* Licensed under the GNU Affero General Public License version 3.
* See included LICENSE file for more information.
*
* https://git.speedie.site/speedie/libleet
*/
#include <iostream>
#include <string>
#include <regex>
#include <filesystem>
#include <fstream>
#include <sstream>
#include "../../include/net/Request.hpp"
#include "Cert.cpp"
void leetRequest::URL::parseURLFromString(const std::string& URL) {
std::regex urlReg("(http|https)://([^/ :]+):?([^/ ]*)(/?[^ #?]*)\\x3f?([^ #]*)#?([^ ]*)");
std::smatch Match;
if (std::regex_match(URL, Match, urlReg)) {
if (!Match[1].str().compare("https")) {
Protocol = leetRequest::LEET_REQUEST_PROTOCOL_HTTPS;
Port = 443;
} else {
Protocol = leetRequest::LEET_REQUEST_PROTOCOL_HTTP;
Port = 80;
}
Host = Match[2].str();
if (Match[3].str().compare("")) {
Port = std::stoi(Match[3].str());
}
Endpoint = Match[4].str();
if (Match[5].str().compare("")) {
Query = "?" + Match[5].str();
}
}
}
const std::string leetRequest::URL::assembleURLFromParts() {
std::string ret{};
if (Protocol == leetRequest::LEET_REQUEST_PROTOCOL_HTTPS) {
ret += "https://" + Host;
} else {
ret += "http://" + Host;
}
if (!(Protocol == leetRequest::LEET_REQUEST_PROTOCOL_HTTPS && Port == 443) &&
!(Protocol == leetRequest::LEET_REQUEST_PROTOCOL_HTTP && Port == 80)) {
ret += ":" + std::to_string(Port);
}
ret += Endpoint + Query;
return ret;
}
void leetRequest::Request::setHeader(const std::string& Header, const std::string& Data) {
headerName.push_back(Header);
headerData.push_back(Data);
}
void leetRequest::Request::setAuthenticationHeader(const std::string& Data) {
authenticationHeaderData = Data;
Authentication = true;
}
void leetRequest::Request::setContentTypeHeader(const std::string& Data) {
contentTypeHeaderData = Data;
}
leetRequest::Response leetRequest::Request::makeRequest() {
leetRequest::Response resp;
try {
boost::asio::ssl::context ctx(boost::asio::ssl::context::tlsv12_client);
leetRequest::applyRootCertificates(ctx, leetRequest::getRootCertificates());
boost::asio::io_context ioc;
boost::asio::ip::tcp::resolver resolver(ioc);
ctx.set_verify_mode(boost::asio::ssl::verify_peer);
ctx.set_verify_callback(boost::asio::ssl::host_name_verification(Host));
boost::beast::ssl_stream<boost::beast::tcp_stream> stream(ioc, ctx);
if (!SSL_set_tlsext_host_name(stream.native_handle(), Host.c_str())) {
boost::beast::error_code ec{static_cast<int>(::ERR_get_error()), boost::asio::error::get_ssl_category()};
throw boost::beast::system_error{ec};
}
const auto results { resolver.resolve(Host, std::to_string(Port)) };
boost::beast::get_lowest_layer(stream).connect(results);
stream.handshake(boost::asio::ssl::stream_base::client);
boost::beast::http::verb theVerb;
switch (Type) {
case leetRequest::LEET_REQUEST_REQTYPE_GET:
theVerb = boost::beast::http::verb::get;
break;
case leetRequest::LEET_REQUEST_REQTYPE_POST:
theVerb = boost::beast::http::verb::post;
break;
case leetRequest::LEET_REQUEST_REQTYPE_PUT:
theVerb = boost::beast::http::verb::put;
break;
default:
break;
}
boost::beast::http::request<boost::beast::http::string_body> httpRequest{theVerb, Host + std::to_string(Port), 11};
httpRequest.set(boost::beast::http::field::host, Host);
if (userAgent.compare("")) httpRequest.set(boost::beast::http::field::user_agent, userAgent);
if (contentTypeHeaderData.compare("")) httpRequest.set(boost::beast::http::field::content_type, contentTypeHeaderData);
if (Body.compare("")) httpRequest.body() = Body;
if (Authentication) httpRequest.set(boost::beast::http::field::authorization, authenticationHeaderData);
for (int it{0}; it < static_cast<int>(headerName.size()); ++it) {
if (!headerName[it].compare("") || !headerData[it].compare("")) {
continue;
}
httpRequest.set(headerName[it], headerData[it]);
}
if (Filename.compare("")) {
std::filesystem::path fileName = Filename;
if (std::filesystem::exists(fileName)) {
std::ostringstream fileBody;
fileBody << std::ifstream(fileName, std::ios::binary).rdbuf();
std::string theBody{ std::move(fileBody).str() };
httpRequest.body() = theBody;
httpRequest.set(boost::beast::http::field::content_length, std::to_string(theBody.size()));
}
}
httpRequest.target(Endpoint + Query);
httpRequest.prepare_payload();
boost::beast::http::write(stream, httpRequest);
boost::beast::flat_buffer flat_buffer;
boost::beast::http::response<boost::beast::http::dynamic_body> res;
boost::beast::http::read(stream, flat_buffer, res);
resp.statusCode = res.result_int();
resp.Body = boost::beast::buffers_to_string(res.body().data());
boost::beast::error_code ec;
stream.next_layer().cancel();
stream.shutdown(ec);
stream.next_layer().close();
if (ec == boost::asio::error::eof) {
ec = {};
}
if (ec == boost::asio::ssl::error::stream_truncated) {
return resp;
}
if (ec) {
throw boost::beast::system_error{ec};
}
return resp;
} catch (boost::wrapexcept<boost::system::system_error> const &e) {
std::cout << e.what();
}
return resp;
}
const bool leetRequest::Request::downloadFile() {
if (!outputFile.compare("")) return false;
leetRequest::Response resp = makeRequest();
std::ofstream of(outputFile, std::ios::binary);
of << resp.Body;
if (resp.statusCode == 200) {
return true;
}
return false;
}
void leetRequest::applyRootCertificates(boost::asio::ssl::context& ctx, const std::string& cert) {
boost::system::error_code ec;
ctx.add_certificate_authority(boost::asio::buffer(cert.data(), cert.size()), ec);
if (ec) {
throw boost::system::system_error{ec};
}
}

View file

@ -1,13 +1,13 @@
[wrap-file]
directory = nlohmann_json-3.11.3
lead_directory_missing = true
source_url = https://github.com/nlohmann/json/releases/download/v3.11.3/include.zip
source_filename = nlohmann_json-3.11.3.zip
source_hash = a22461d13119ac5c78f205d3df1db13403e58ce1bb1794edc9313677313f4a9d
patch_url = https://wrapdb.mesonbuild.com/v1/projects/nlohmann_json/3.9.1/1/get_zip
patch_filename = nlohmann_json-3.9.1-1-wrap.zip
patch_hash = 1774e5506fbe3897d652f67e41973194b948d2ab851cf464a742f35f160a1435
[provide]
nlohmann_json = nlohmann_json_dep
[wrap-file]
directory = nlohmann_json-3.11.3
lead_directory_missing = true
source_url = https://github.com/nlohmann/json/releases/download/v3.11.3/include.zip
source_filename = nlohmann_json-3.11.3.zip
source_hash = a22461d13119ac5c78f205d3df1db13403e58ce1bb1794edc9313677313f4a9d
patch_url = https://wrapdb.mesonbuild.com/v1/projects/nlohmann_json/3.9.1/1/get_zip
patch_filename = nlohmann_json-3.9.1-1-wrap.zip
patch_hash = 1774e5506fbe3897d652f67e41973194b948d2ab851cf464a742f35f160a1435
[provide]
nlohmann_json = nlohmann_json_dep

View file

@ -1,10 +1,10 @@
[wrap-file]
directory = olm-3.2.16
method = cmake
source_url = https://gitlab.matrix.org/matrix-org/olm/-/archive/3.2.16/olm-3.2.16.tar.gz
source_filename = olm-3.2.16.tar.gz
source_hash = 1e90f9891009965fd064be747616da46b232086fe270b77605ec9bda34272a68
wrapdb_version = 3.2.16-1
[provide]
olm = olm_dep
[wrap-file]
directory = olm-3.2.16
method = cmake
source_url = https://gitlab.matrix.org/matrix-org/olm/-/archive/3.2.16/olm-3.2.16.tar.gz
source_filename = olm-3.2.16.tar.gz
source_hash = 1e90f9891009965fd064be747616da46b232086fe270b77605ec9bda34272a68
wrapdb_version = 3.2.16-1
[provide]
olm = olm_dep

View file

@ -1,15 +1,15 @@
[wrap-file]
directory = openssl-3.0.8
source_url = https://www.openssl.org/source/openssl-3.0.8.tar.gz
source_filename = openssl-3.0.8.tar.gz
source_hash = 6c13d2bf38fdf31eac3ce2a347073673f5d63263398f1f69d0df4a41253e4b3e
patch_filename = openssl_3.0.8-2_patch.zip
patch_url = https://wrapdb.mesonbuild.com/v2/openssl_3.0.8-2/get_patch
patch_hash = e84b5fe469e681e3318184157a0c7c43d4cbacd078bb88f506e31569f8f75072
source_fallback_url = https://github.com/mesonbuild/wrapdb/releases/download/openssl_3.0.8-2/openssl-3.0.8.tar.gz
wrapdb_version = 3.0.8-2
[provide]
libcrypto = libcrypto_dep
libssl = libssl_dep
openssl = openssl_dep
[wrap-file]
directory = openssl-3.0.8
source_url = https://www.openssl.org/source/openssl-3.0.8.tar.gz
source_filename = openssl-3.0.8.tar.gz
source_hash = 6c13d2bf38fdf31eac3ce2a347073673f5d63263398f1f69d0df4a41253e4b3e
patch_filename = openssl_3.0.8-2_patch.zip
patch_url = https://wrapdb.mesonbuild.com/v2/openssl_3.0.8-2/get_patch
patch_hash = e84b5fe469e681e3318184157a0c7c43d4cbacd078bb88f506e31569f8f75072
source_fallback_url = https://github.com/mesonbuild/wrapdb/releases/download/openssl_3.0.8-2/openssl-3.0.8.tar.gz
wrapdb_version = 3.0.8-2
[provide]
libcrypto = libcrypto_dep
libssl = libssl_dep
openssl = openssl_dep

6
windows-olm/README.md Normal file
View file

@ -0,0 +1,6 @@
This directory contains headers and a prebuilt binary for libolm.
The binary is built for AMD64 without debug symbols and statically linked.
It's only really here for convenience.
Source code: https://gitlab.matrix.org/matrix-org/olm
License: Apache 2.0

View file

@ -0,0 +1,80 @@
/* Copyright 2015-2016 OpenMarket Ltd
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#ifndef OLM_ERROR_H_
#define OLM_ERROR_H_
#include "olm/olm_export.h"
#ifdef __cplusplus
extern "C" {
#endif
enum OlmErrorCode {
OLM_SUCCESS = 0, /*!< There wasn't an error */
OLM_NOT_ENOUGH_RANDOM = 1, /*!< Not enough entropy was supplied */
OLM_OUTPUT_BUFFER_TOO_SMALL = 2, /*!< Supplied output buffer is too small */
OLM_BAD_MESSAGE_VERSION = 3, /*!< The message version is unsupported */
OLM_BAD_MESSAGE_FORMAT = 4, /*!< The message couldn't be decoded */
OLM_BAD_MESSAGE_MAC = 5, /*!< The message couldn't be decrypted */
OLM_BAD_MESSAGE_KEY_ID = 6, /*!< The message references an unknown key id */
OLM_INVALID_BASE64 = 7, /*!< The input base64 was invalid */
OLM_BAD_ACCOUNT_KEY = 8, /*!< The supplied account key is invalid */
OLM_UNKNOWN_PICKLE_VERSION = 9, /*!< The pickled object is too new */
OLM_CORRUPTED_PICKLE = 10, /*!< The pickled object couldn't be decoded */
OLM_BAD_SESSION_KEY = 11, /*!< Attempt to initialise an inbound group
session from an invalid session key */
OLM_UNKNOWN_MESSAGE_INDEX = 12, /*!< Attempt to decode a message whose
* index is earlier than our earliest
* known session key.
*/
/**
* Attempt to unpickle an account which uses pickle version 1 (which did
* not save enough space for the Ed25519 key; the key should be considered
* compromised. We don't let the user reload the account.
*/
OLM_BAD_LEGACY_ACCOUNT_PICKLE = 13,
/**
* Received message had a bad signature
*/
OLM_BAD_SIGNATURE = 14,
OLM_INPUT_BUFFER_TOO_SMALL = 15,
/**
* SAS doesn't have their key set.
*/
OLM_SAS_THEIR_KEY_NOT_SET = 16,
/**
* The pickled object was successfully decoded, but the unpickling still failed
* because it had some extraneous junk data at the end.
*/
OLM_PICKLE_EXTRA_DATA = 17,
/* remember to update the list of string constants in error.c when updating
* this list. */
};
/** get a string representation of the given error code. */
OLM_EXPORT const char * _olm_error_to_string(enum OlmErrorCode error);
#ifdef __cplusplus
} // extern "C"
#endif
#endif /* OLM_ERROR_H_ */

View file

@ -0,0 +1,246 @@
/* Copyright 2016 OpenMarket Ltd
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#ifndef OLM_INBOUND_GROUP_SESSION_H_
#define OLM_INBOUND_GROUP_SESSION_H_
#include <stddef.h>
#include <stdint.h>
#include "olm/error.h"
#include "olm/olm_export.h"
#ifdef __cplusplus
extern "C" {
#endif
typedef struct OlmInboundGroupSession OlmInboundGroupSession;
/** get the size of an inbound group session, in bytes. */
OLM_EXPORT size_t olm_inbound_group_session_size(void);
/**
* Initialise an inbound group session object using the supplied memory
* The supplied memory should be at least olm_inbound_group_session_size()
* bytes.
*/
OLM_EXPORT OlmInboundGroupSession * olm_inbound_group_session(
void *memory
);
/**
* A null terminated string describing the most recent error to happen to a
* group session */
OLM_EXPORT const char *olm_inbound_group_session_last_error(
const OlmInboundGroupSession *session
);
/**
* An error code describing the most recent error to happen to a group
* session */
OLM_EXPORT enum OlmErrorCode olm_inbound_group_session_last_error_code(
const OlmInboundGroupSession *session
);
/** Clears the memory used to back this group session */
OLM_EXPORT size_t olm_clear_inbound_group_session(
OlmInboundGroupSession *session
);
/** Returns the number of bytes needed to store an inbound group session */
OLM_EXPORT size_t olm_pickle_inbound_group_session_length(
const OlmInboundGroupSession *session
);
/**
* Stores a group session as a base64 string. Encrypts the session using the
* supplied key. Returns the length of the session on success.
*
* Returns olm_error() on failure. If the pickle output buffer
* is smaller than olm_pickle_inbound_group_session_length() then
* olm_inbound_group_session_last_error() will be "OUTPUT_BUFFER_TOO_SMALL"
*/
OLM_EXPORT size_t olm_pickle_inbound_group_session(
OlmInboundGroupSession *session,
void const * key, size_t key_length,
void * pickled, size_t pickled_length
);
/**
* Loads a group session from a pickled base64 string. Decrypts the session
* using the supplied key.
*
* Returns olm_error() on failure. If the key doesn't match the one used to
* encrypt the account then olm_inbound_group_session_last_error() will be
* "BAD_ACCOUNT_KEY". If the base64 couldn't be decoded then
* olm_inbound_group_session_last_error() will be "INVALID_BASE64". The input
* pickled buffer is destroyed
*/
OLM_EXPORT size_t olm_unpickle_inbound_group_session(
OlmInboundGroupSession *session,
void const * key, size_t key_length,
void * pickled, size_t pickled_length
);
/**
* Start a new inbound group session, from a key exported from
* olm_outbound_group_session_key
*
* Returns olm_error() on failure. On failure last_error will be set with an
* error code. The last_error will be:
*
* * OLM_INVALID_BASE64 if the session_key is not valid base64
* * OLM_BAD_SESSION_KEY if the session_key is invalid
*/
OLM_EXPORT size_t olm_init_inbound_group_session(
OlmInboundGroupSession *session,
/* base64-encoded keys */
uint8_t const * session_key, size_t session_key_length
);
/**
* Import an inbound group session, from a previous export.
*
* Returns olm_error() on failure. On failure last_error will be set with an
* error code. The last_error will be:
*
* * OLM_INVALID_BASE64 if the session_key is not valid base64
* * OLM_BAD_SESSION_KEY if the session_key is invalid
*/
OLM_EXPORT size_t olm_import_inbound_group_session(
OlmInboundGroupSession *session,
/* base64-encoded keys; note that it will be overwritten with the base64-decoded
data. */
uint8_t const * session_key, size_t session_key_length
);
/**
* Get an upper bound on the number of bytes of plain-text the decrypt method
* will write for a given input message length. The actual size could be
* different due to padding.
*
* The input message buffer is destroyed.
*
* Returns olm_error() on failure.
*/
OLM_EXPORT size_t olm_group_decrypt_max_plaintext_length(
OlmInboundGroupSession *session,
uint8_t * message, size_t message_length
);
/**
* Decrypt a message.
*
* The input message buffer is destroyed.
*
* Returns the length of the decrypted plain-text, or olm_error() on failure.
*
* On failure last_error will be set with an error code. The last_error will
* be:
* * OLM_OUTPUT_BUFFER_TOO_SMALL if the plain-text buffer is too small
* * OLM_INVALID_BASE64 if the message is not valid base-64
* * OLM_BAD_MESSAGE_VERSION if the message was encrypted with an unsupported
* version of the protocol
* * OLM_BAD_MESSAGE_FORMAT if the message headers could not be decoded
* * OLM_BAD_MESSAGE_MAC if the message could not be verified
* * OLM_UNKNOWN_MESSAGE_INDEX if we do not have a session key corresponding to the
* message's index (ie, it was sent before the session key was shared with
* us)
*/
OLM_EXPORT size_t olm_group_decrypt(
OlmInboundGroupSession *session,
/* input; note that it will be overwritten with the base64-decoded
message. */
uint8_t * message, size_t message_length,
/* output */
uint8_t * plaintext, size_t max_plaintext_length,
uint32_t * message_index
);
/**
* Get the number of bytes returned by olm_inbound_group_session_id()
*/
OLM_EXPORT size_t olm_inbound_group_session_id_length(
const OlmInboundGroupSession *session
);
/**
* Get a base64-encoded identifier for this session.
*
* Returns the length of the session id on success or olm_error() on
* failure. On failure last_error will be set with an error code. The
* last_error will be OUTPUT_BUFFER_TOO_SMALL if the id buffer was too
* small.
*/
OLM_EXPORT size_t olm_inbound_group_session_id(
OlmInboundGroupSession *session,
uint8_t * id, size_t id_length
);
/**
* Get the first message index we know how to decrypt.
*/
OLM_EXPORT uint32_t olm_inbound_group_session_first_known_index(
const OlmInboundGroupSession *session
);
/**
* Check if the session has been verified as a valid session.
*
* (A session is verified either because the original session share was signed,
* or because we have subsequently successfully decrypted a message.)
*
* This is mainly intended for the unit tests, currently.
*/
OLM_EXPORT int olm_inbound_group_session_is_verified(
const OlmInboundGroupSession *session
);
/**
* Get the number of bytes returned by olm_export_inbound_group_session()
*/
OLM_EXPORT size_t olm_export_inbound_group_session_length(
const OlmInboundGroupSession *session
);
/**
* Export the base64-encoded ratchet key for this session, at the given index,
* in a format which can be used by olm_import_inbound_group_session
*
* Returns the length of the ratchet key on success or olm_error() on
* failure. On failure last_error will be set with an error code. The
* last_error will be:
* * OUTPUT_BUFFER_TOO_SMALL if the buffer was too small
* * OLM_UNKNOWN_MESSAGE_INDEX if we do not have a session key corresponding to the
* given index (ie, it was sent before the session key was shared with
* us)
*/
OLM_EXPORT size_t olm_export_inbound_group_session(
OlmInboundGroupSession *session,
uint8_t * key, size_t key_length, uint32_t message_index
);
#ifdef __cplusplus
} // extern "C"
#endif
#endif /* OLM_INBOUND_GROUP_SESSION_H_ */

View file

@ -0,0 +1,527 @@
/* Copyright 2015, 2016 OpenMarket Ltd
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#ifndef OLM_H_
#define OLM_H_
#include <stddef.h>
#include <stdint.h>
#include "olm/error.h"
#include "olm/inbound_group_session.h"
#include "olm/outbound_group_session.h"
#include "olm/olm_export.h"
#ifdef __cplusplus
extern "C" {
#endif
static const size_t OLM_MESSAGE_TYPE_PRE_KEY = 0;
static const size_t OLM_MESSAGE_TYPE_MESSAGE = 1;
typedef struct OlmAccount OlmAccount;
typedef struct OlmSession OlmSession;
typedef struct OlmUtility OlmUtility;
/** Get the version number of the library.
* Arguments will be updated if non-null.
*/
OLM_EXPORT void olm_get_library_version(uint8_t *major, uint8_t *minor, uint8_t *patch);
/** The size of an account object in bytes */
OLM_EXPORT size_t olm_account_size(void);
/** The size of a session object in bytes */
OLM_EXPORT size_t olm_session_size(void);
/** The size of a utility object in bytes */
OLM_EXPORT size_t olm_utility_size(void);
/** Initialise an account object using the supplied memory
* The supplied memory must be at least olm_account_size() bytes */
OLM_EXPORT OlmAccount * olm_account(
void * memory
);
/** Initialise a session object using the supplied memory
* The supplied memory must be at least olm_session_size() bytes */
OLM_EXPORT OlmSession * olm_session(
void * memory
);
/** Initialise a utility object using the supplied memory
* The supplied memory must be at least olm_utility_size() bytes */
OLM_EXPORT OlmUtility * olm_utility(
void * memory
);
/** The value that olm will return from a function if there was an error */
OLM_EXPORT size_t olm_error(void);
/** A null terminated string describing the most recent error to happen to an
* account */
OLM_EXPORT const char * olm_account_last_error(
OlmAccount const * account
);
/** An error code describing the most recent error to happen to an account */
OLM_EXPORT enum OlmErrorCode olm_account_last_error_code(
OlmAccount const * account
);
/** A null terminated string describing the most recent error to happen to a
* session */
OLM_EXPORT const char * olm_session_last_error(
OlmSession const * session
);
/** An error code describing the most recent error to happen to a session */
OLM_EXPORT enum OlmErrorCode olm_session_last_error_code(
OlmSession const * session
);
/** A null terminated string describing the most recent error to happen to a
* utility */
OLM_EXPORT const char * olm_utility_last_error(
OlmUtility const * utility
);
/** An error code describing the most recent error to happen to a utility */
OLM_EXPORT enum OlmErrorCode olm_utility_last_error_code(
OlmUtility const * utility
);
/** Clears the memory used to back this account */
OLM_EXPORT size_t olm_clear_account(
OlmAccount * account
);
/** Clears the memory used to back this session */
OLM_EXPORT size_t olm_clear_session(
OlmSession * session
);
/** Clears the memory used to back this utility */
OLM_EXPORT size_t olm_clear_utility(
OlmUtility * utility
);
/** Returns the number of bytes needed to store an account */
OLM_EXPORT size_t olm_pickle_account_length(
OlmAccount const * account
);
/** Returns the number of bytes needed to store a session */
OLM_EXPORT size_t olm_pickle_session_length(
OlmSession const * session
);
/** Stores an account as a base64 string. Encrypts the account using the
* supplied key. Returns the length of the pickled account on success.
* Returns olm_error() on failure. If the pickle output buffer
* is smaller than olm_pickle_account_length() then
* olm_account_last_error() will be "OUTPUT_BUFFER_TOO_SMALL" */
OLM_EXPORT size_t olm_pickle_account(
OlmAccount * account,
void const * key, size_t key_length,
void * pickled, size_t pickled_length
);
/** Stores a session as a base64 string. Encrypts the session using the
* supplied key. Returns the length of the pickled session on success.
* Returns olm_error() on failure. If the pickle output buffer
* is smaller than olm_pickle_session_length() then
* olm_session_last_error() will be "OUTPUT_BUFFER_TOO_SMALL" */
OLM_EXPORT size_t olm_pickle_session(
OlmSession * session,
void const * key, size_t key_length,
void * pickled, size_t pickled_length
);
/** Loads an account from a pickled base64 string. Decrypts the account using
* the supplied key. Returns olm_error() on failure. If the key doesn't
* match the one used to encrypt the account then olm_account_last_error()
* will be "BAD_ACCOUNT_KEY". If the base64 couldn't be decoded then
* olm_account_last_error() will be "INVALID_BASE64". The input pickled
* buffer is destroyed */
OLM_EXPORT size_t olm_unpickle_account(
OlmAccount * account,
void const * key, size_t key_length,
void * pickled, size_t pickled_length
);
/** Loads a session from a pickled base64 string. Decrypts the session using
* the supplied key. Returns olm_error() on failure. If the key doesn't
* match the one used to encrypt the account then olm_session_last_error()
* will be "BAD_ACCOUNT_KEY". If the base64 couldn't be decoded then
* olm_session_last_error() will be "INVALID_BASE64". The input pickled
* buffer is destroyed */
OLM_EXPORT size_t olm_unpickle_session(
OlmSession * session,
void const * key, size_t key_length,
void * pickled, size_t pickled_length
);
/** The number of random bytes needed to create an account.*/
OLM_EXPORT size_t olm_create_account_random_length(
OlmAccount const * account
);
/** Creates a new account. Returns olm_error() on failure. If there weren't
* enough random bytes then olm_account_last_error() will be
* "NOT_ENOUGH_RANDOM" */
OLM_EXPORT size_t olm_create_account(
OlmAccount * account,
void * random, size_t random_length
);
/** The size of the output buffer needed to hold the identity keys */
OLM_EXPORT size_t olm_account_identity_keys_length(
OlmAccount const * account
);
/** Writes the public parts of the identity keys for the account into the
* identity_keys output buffer. Returns olm_error() on failure. If the
* identity_keys buffer was too small then olm_account_last_error() will be
* "OUTPUT_BUFFER_TOO_SMALL". */
OLM_EXPORT size_t olm_account_identity_keys(
OlmAccount * account,
void * identity_keys, size_t identity_key_length
);
/** The length of an ed25519 signature encoded as base64. */
OLM_EXPORT size_t olm_account_signature_length(
OlmAccount const * account
);
/** Signs a message with the ed25519 key for this account. Returns olm_error()
* on failure. If the signature buffer was too small then
* olm_account_last_error() will be "OUTPUT_BUFFER_TOO_SMALL" */
OLM_EXPORT size_t olm_account_sign(
OlmAccount * account,
void const * message, size_t message_length,
void * signature, size_t signature_length
);
/** The size of the output buffer needed to hold the one time keys */
OLM_EXPORT size_t olm_account_one_time_keys_length(
OlmAccount const * account
);
/** Writes the public parts of the unpublished one time keys for the account
* into the one_time_keys output buffer.
* <p>
* The returned data is a JSON-formatted object with the single property
* <tt>curve25519</tt>, which is itself an object mapping key id to
* base64-encoded Curve25519 key. For example:
* <pre>
* {
* curve25519: {
* "AAAAAA": "wo76WcYtb0Vk/pBOdmduiGJ0wIEjW4IBMbbQn7aSnTo",
* "AAAAAB": "LRvjo46L1X2vx69sS9QNFD29HWulxrmW11Up5AfAjgU"
* }
* }
* </pre>
* Returns olm_error() on failure.
* <p>
* If the one_time_keys buffer was too small then olm_account_last_error()
* will be "OUTPUT_BUFFER_TOO_SMALL". */
OLM_EXPORT size_t olm_account_one_time_keys(
OlmAccount * account,
void * one_time_keys, size_t one_time_keys_length
);
/** Marks the current set of one time keys and fallback key as being published
* Once marked as published, the one time keys will no longer be returned by
* olm_account_one_time_keys(), and the fallback key will no longer be returned
* by olm_account_unpublished_fallback_key().
*
* Returns the number of one-time keys that were marked as published. Note that
* this count does not include the fallback key. */
OLM_EXPORT size_t olm_account_mark_keys_as_published(
OlmAccount * account
);
/** The largest number of one time keys this account can store. */
OLM_EXPORT size_t olm_account_max_number_of_one_time_keys(
OlmAccount const * account
);
/** The number of random bytes needed to generate a given number of new one
* time keys. */
OLM_EXPORT size_t olm_account_generate_one_time_keys_random_length(
OlmAccount const * account,
size_t number_of_keys
);
/** Generates a number of new one time keys. If the total number of keys stored
* by this account exceeds max_number_of_one_time_keys() then the old keys are
* discarded. Returns olm_error() on error. If the number of random bytes is
* too small then olm_account_last_error() will be "NOT_ENOUGH_RANDOM". */
OLM_EXPORT size_t olm_account_generate_one_time_keys(
OlmAccount * account,
size_t number_of_keys,
void * random, size_t random_length
);
/** The number of random bytes needed to generate a fallback key. */
OLM_EXPORT size_t olm_account_generate_fallback_key_random_length(
OlmAccount const * account
);
/** Generates a new fallback key. Only one previous fallback key is
* stored. Returns olm_error() on error. If the number of random bytes is too
* small then olm_account_last_error() will be "NOT_ENOUGH_RANDOM". */
OLM_EXPORT size_t olm_account_generate_fallback_key(
OlmAccount * account,
void * random, size_t random_length
);
/** The number of bytes needed to hold the fallback key as returned by
* olm_account_fallback_key. */
OLM_EXPORT size_t olm_account_fallback_key_length(
OlmAccount const * account
);
/** Deprecated: use olm_account_unpublished_fallback_key instead */
OLM_EXPORT size_t olm_account_fallback_key(
OlmAccount * account,
void * fallback_key, size_t fallback_key_size
);
/** The number of bytes needed to hold the unpublished fallback key as returned
* by olm_account_unpublished fallback_key. */
OLM_EXPORT size_t olm_account_unpublished_fallback_key_length(
OlmAccount const * account
);
/** Returns the fallback key (if present, and if unpublished) into the
* fallback_key buffer */
OLM_EXPORT size_t olm_account_unpublished_fallback_key(
OlmAccount * account,
void * fallback_key, size_t fallback_key_size
);
/** Forget about the old fallback key. This should be called once you are
* reasonably certain that you will not receive any more messages that use
* the old fallback key (e.g. 5 minutes after the new fallback key has been
* published).
*/
OLM_EXPORT void olm_account_forget_old_fallback_key(
OlmAccount * account
);
/** The number of random bytes needed to create an outbound session */
OLM_EXPORT size_t olm_create_outbound_session_random_length(
OlmSession const * session
);
/** Creates a new out-bound session for sending messages to a given identity_key
* and one_time_key. Returns olm_error() on failure. If the keys couldn't be
* decoded as base64 then olm_session_last_error() will be "INVALID_BASE64"
* If there weren't enough random bytes then olm_session_last_error() will
* be "NOT_ENOUGH_RANDOM". */
OLM_EXPORT size_t olm_create_outbound_session(
OlmSession * session,
OlmAccount const * account,
void const * their_identity_key, size_t their_identity_key_length,
void const * their_one_time_key, size_t their_one_time_key_length,
void * random, size_t random_length
);
/** Create a new in-bound session for sending/receiving messages from an
* incoming PRE_KEY message. Returns olm_error() on failure. If the base64
* couldn't be decoded then olm_session_last_error will be "INVALID_BASE64".
* If the message was for an unsupported protocol version then
* olm_session_last_error() will be "BAD_MESSAGE_VERSION". If the message
* couldn't be decoded then olm_session_last_error() will be
* "BAD_MESSAGE_FORMAT". If the message refers to an unknown one time
* key then olm_session_last_error() will be "BAD_MESSAGE_KEY_ID". */
OLM_EXPORT size_t olm_create_inbound_session(
OlmSession * session,
OlmAccount * account,
void * one_time_key_message, size_t message_length
);
/** Same as olm_create_inbound_session, but ensures that the identity key
* in the pre-key message matches the expected identity key, supplied via the
* `their_identity_key` parameter. Fails early if there is no match. */
OLM_EXPORT size_t olm_create_inbound_session_from(
OlmSession * session,
OlmAccount * account,
void const * their_identity_key, size_t their_identity_key_length,
void * one_time_key_message, size_t message_length
);
/** The length of the buffer needed to return the id for this session. */
OLM_EXPORT size_t olm_session_id_length(
OlmSession const * session
);
/** An identifier for this session. Will be the same for both ends of the
* conversation. If the id buffer is too small then olm_session_last_error()
* will be "OUTPUT_BUFFER_TOO_SMALL". */
OLM_EXPORT size_t olm_session_id(
OlmSession * session,
void * id, size_t id_length
);
OLM_EXPORT int olm_session_has_received_message(
OlmSession const *session
);
/**
* Write a null-terminated string describing the internal state of an olm
* session to the buffer provided for debugging and logging purposes. If the
* buffer is not large enough to hold the entire string, it will be truncated
* and will end with "...". A buffer length of 600 will be enough to hold any
* output.
*/
OLM_EXPORT void olm_session_describe(OlmSession * session, char *buf, size_t buflen);
/** Checks if the PRE_KEY message is for this in-bound session. This can happen
* if multiple messages are sent to this account before this account sends a
* message in reply. The one_time_key_message buffer is destroyed. Returns 1 if
* the session matches. Returns 0 if the session does not match. Returns
* olm_error() on failure. If the base64 couldn't be decoded then
* olm_session_last_error will be "INVALID_BASE64". If the message was for an
* unsupported protocol version then olm_session_last_error() will be
* "BAD_MESSAGE_VERSION". If the message couldn't be decoded then then
* olm_session_last_error() will be "BAD_MESSAGE_FORMAT". */
OLM_EXPORT size_t olm_matches_inbound_session(
OlmSession * session,
void * one_time_key_message, size_t message_length
);
/** Checks if the PRE_KEY message is for this in-bound session. This can happen
* if multiple messages are sent to this account before this account sends a
* message in reply. The one_time_key_message buffer is destroyed. Returns 1 if
* the session matches. Returns 0 if the session does not match. Returns
* olm_error() on failure. If the base64 couldn't be decoded then
* olm_session_last_error will be "INVALID_BASE64". If the message was for an
* unsupported protocol version then olm_session_last_error() will be
* "BAD_MESSAGE_VERSION". If the message couldn't be decoded then then
* olm_session_last_error() will be "BAD_MESSAGE_FORMAT". */
OLM_EXPORT size_t olm_matches_inbound_session_from(
OlmSession * session,
void const * their_identity_key, size_t their_identity_key_length,
void * one_time_key_message, size_t message_length
);
/** Removes the one time keys that the session used from the account. Returns
* olm_error() on failure. If the account doesn't have any matching one time
* keys then olm_account_last_error() will be "BAD_MESSAGE_KEY_ID". */
OLM_EXPORT size_t olm_remove_one_time_keys(
OlmAccount * account,
OlmSession * session
);
/** The type of the next message that olm_encrypt() will return. Returns
* OLM_MESSAGE_TYPE_PRE_KEY if the message will be a PRE_KEY message.
* Returns OLM_MESSAGE_TYPE_MESSAGE if the message will be a normal message.
* Returns olm_error on failure. */
OLM_EXPORT size_t olm_encrypt_message_type(
OlmSession const * session
);
/** The number of random bytes needed to encrypt the next message. */
OLM_EXPORT size_t olm_encrypt_random_length(
OlmSession const * session
);
/** The size of the next message in bytes for the given number of plain-text
* bytes. */
OLM_EXPORT size_t olm_encrypt_message_length(
OlmSession const * session,
size_t plaintext_length
);
/** Encrypts a message using the session. Returns the length of the message in
* bytes on success. Writes the message as base64 into the message buffer.
* Returns olm_error() on failure. If the message buffer is too small then
* olm_session_last_error() will be "OUTPUT_BUFFER_TOO_SMALL". If there
* weren't enough random bytes then olm_session_last_error() will be
* "NOT_ENOUGH_RANDOM". */
OLM_EXPORT size_t olm_encrypt(
OlmSession * session,
void const * plaintext, size_t plaintext_length,
void * random, size_t random_length,
void * message, size_t message_length
);
/** The maximum number of bytes of plain-text a given message could decode to.
* The actual size could be different due to padding. The input message buffer
* is destroyed. Returns olm_error() on failure. If the message base64
* couldn't be decoded then olm_session_last_error() will be
* "INVALID_BASE64". If the message is for an unsupported version of the
* protocol then olm_session_last_error() will be "BAD_MESSAGE_VERSION".
* If the message couldn't be decoded then olm_session_last_error() will be
* "BAD_MESSAGE_FORMAT". */
OLM_EXPORT size_t olm_decrypt_max_plaintext_length(
OlmSession * session,
size_t message_type,
void * message, size_t message_length
);
/** Decrypts a message using the session. The input message buffer is destroyed.
* Returns the length of the plain-text on success. Returns olm_error() on
* failure. If the plain-text buffer is smaller than
* olm_decrypt_max_plaintext_length() then olm_session_last_error()
* will be "OUTPUT_BUFFER_TOO_SMALL". If the base64 couldn't be decoded then
* olm_session_last_error() will be "INVALID_BASE64". If the message is for
* an unsupported version of the protocol then olm_session_last_error() will
* be "BAD_MESSAGE_VERSION". If the message couldn't be decoded then
* olm_session_last_error() will be BAD_MESSAGE_FORMAT".
* If the MAC on the message was invalid then olm_session_last_error() will
* be "BAD_MESSAGE_MAC". */
OLM_EXPORT size_t olm_decrypt(
OlmSession * session,
size_t message_type,
void * message, size_t message_length,
void * plaintext, size_t max_plaintext_length
);
/** The length of the buffer needed to hold the SHA-256 hash. */
OLM_EXPORT size_t olm_sha256_length(
OlmUtility const * utility
);
/** Calculates the SHA-256 hash of the input and encodes it as base64. If the
* output buffer is smaller than olm_sha256_length() then
* olm_utility_last_error() will be "OUTPUT_BUFFER_TOO_SMALL". */
OLM_EXPORT size_t olm_sha256(
OlmUtility * utility,
void const * input, size_t input_length,
void * output, size_t output_length
);
/** Verify an ed25519 signature. If the key was too small then
* olm_utility_last_error() will be "INVALID_BASE64". If the signature was invalid
* then olm_utility_last_error() will be "BAD_MESSAGE_MAC". */
OLM_EXPORT size_t olm_ed25519_verify(
OlmUtility * utility,
void const * key, size_t key_length,
void const * message, size_t message_length,
void * signature, size_t signature_length
);
#ifdef __cplusplus
}
#endif
#endif /* OLM_H_ */

View file

@ -0,0 +1,42 @@
#ifndef OLM_EXPORT_H
#define OLM_EXPORT_H
#ifdef OLM_STATIC_DEFINE
# define OLM_EXPORT
# define OLM_NO_EXPORT
#else
# ifndef OLM_EXPORT
# ifdef olm_EXPORTS
/* We are building this library */
# define OLM_EXPORT __declspec(dllexport)
# else
/* We are using this library */
# define OLM_EXPORT __declspec(dllimport)
# endif
# endif
# ifndef OLM_NO_EXPORT
# define OLM_NO_EXPORT
# endif
#endif
#ifndef OLM_DEPRECATED
# define OLM_DEPRECATED __attribute__ ((__deprecated__))
#endif
#ifndef OLM_DEPRECATED_EXPORT
# define OLM_DEPRECATED_EXPORT OLM_EXPORT OLM_DEPRECATED
#endif
#ifndef OLM_DEPRECATED_NO_EXPORT
# define OLM_DEPRECATED_NO_EXPORT OLM_NO_EXPORT OLM_DEPRECATED
#endif
#if 0 /* DEFINE_NO_DEPRECATED */
# ifndef OLM_NO_DEPRECATED
# define OLM_NO_DEPRECATED
# endif
#endif
#endif /* OLM_EXPORT_H */

View file

@ -0,0 +1,192 @@
/* Copyright 2016 OpenMarket Ltd
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#ifndef OLM_OUTBOUND_GROUP_SESSION_H_
#define OLM_OUTBOUND_GROUP_SESSION_H_
#include <stddef.h>
#include <stdint.h>
#include "olm/error.h"
#include "olm/olm_export.h"
#ifdef __cplusplus
extern "C" {
#endif
typedef struct OlmOutboundGroupSession OlmOutboundGroupSession;
/** get the size of an outbound group session, in bytes. */
OLM_EXPORT size_t olm_outbound_group_session_size(void);
/**
* Initialise an outbound group session object using the supplied memory
* The supplied memory should be at least olm_outbound_group_session_size()
* bytes.
*/
OLM_EXPORT OlmOutboundGroupSession * olm_outbound_group_session(
void *memory
);
/**
* A null terminated string describing the most recent error to happen to a
* group session */
OLM_EXPORT const char *olm_outbound_group_session_last_error(
const OlmOutboundGroupSession *session
);
/**
* An error code describing the most recent error to happen to a group
* session */
OLM_EXPORT enum OlmErrorCode olm_outbound_group_session_last_error_code(
const OlmOutboundGroupSession *session
);
/** Clears the memory used to back this group session */
OLM_EXPORT size_t olm_clear_outbound_group_session(
OlmOutboundGroupSession *session
);
/** Returns the number of bytes needed to store an outbound group session */
OLM_EXPORT size_t olm_pickle_outbound_group_session_length(
const OlmOutboundGroupSession *session
);
/**
* Stores a group session as a base64 string. Encrypts the session using the
* supplied key. Returns the length of the session on success.
*
* Returns olm_error() on failure. If the pickle output buffer
* is smaller than olm_pickle_outbound_group_session_length() then
* olm_outbound_group_session_last_error() will be "OUTPUT_BUFFER_TOO_SMALL"
*/
OLM_EXPORT size_t olm_pickle_outbound_group_session(
OlmOutboundGroupSession *session,
void const * key, size_t key_length,
void * pickled, size_t pickled_length
);
/**
* Loads a group session from a pickled base64 string. Decrypts the session
* using the supplied key.
*
* Returns olm_error() on failure. If the key doesn't match the one used to
* encrypt the account then olm_outbound_group_session_last_error() will be
* "BAD_ACCOUNT_KEY". If the base64 couldn't be decoded then
* olm_outbound_group_session_last_error() will be "INVALID_BASE64". The input
* pickled buffer is destroyed
*/
OLM_EXPORT size_t olm_unpickle_outbound_group_session(
OlmOutboundGroupSession *session,
void const * key, size_t key_length,
void * pickled, size_t pickled_length
);
/** The number of random bytes needed to create an outbound group session */
OLM_EXPORT size_t olm_init_outbound_group_session_random_length(
const OlmOutboundGroupSession *session
);
/**
* Start a new outbound group session. Returns olm_error() on failure. On
* failure last_error will be set with an error code. The last_error will be
* NOT_ENOUGH_RANDOM if the number of random bytes was too small.
*/
OLM_EXPORT size_t olm_init_outbound_group_session(
OlmOutboundGroupSession *session,
uint8_t *random, size_t random_length
);
/**
* The number of bytes that will be created by encrypting a message
*/
OLM_EXPORT size_t olm_group_encrypt_message_length(
OlmOutboundGroupSession *session,
size_t plaintext_length
);
/**
* Encrypt some plain-text. Returns the length of the encrypted message or
* olm_error() on failure. On failure last_error will be set with an
* error code. The last_error will be OUTPUT_BUFFER_TOO_SMALL if the output
* buffer is too small.
*/
OLM_EXPORT size_t olm_group_encrypt(
OlmOutboundGroupSession *session,
uint8_t const * plaintext, size_t plaintext_length,
uint8_t * message, size_t message_length
);
/**
* Get the number of bytes returned by olm_outbound_group_session_id()
*/
OLM_EXPORT size_t olm_outbound_group_session_id_length(
const OlmOutboundGroupSession *session
);
/**
* Get a base64-encoded identifier for this session.
*
* Returns the length of the session id on success or olm_error() on
* failure. On failure last_error will be set with an error code. The
* last_error will be OUTPUT_BUFFER_TOO_SMALL if the id buffer was too
* small.
*/
OLM_EXPORT size_t olm_outbound_group_session_id(
OlmOutboundGroupSession *session,
uint8_t * id, size_t id_length
);
/**
* Get the current message index for this session.
*
* Each message is sent with an increasing index; this returns the index for
* the next message.
*/
OLM_EXPORT uint32_t olm_outbound_group_session_message_index(
OlmOutboundGroupSession *session
);
/**
* Get the number of bytes returned by olm_outbound_group_session_key()
*/
OLM_EXPORT size_t olm_outbound_group_session_key_length(
const OlmOutboundGroupSession *session
);
/**
* Get the base64-encoded current ratchet key for this session.
*
* Each message is sent with a different ratchet key. This function returns the
* ratchet key that will be used for the next message.
*
* Returns the length of the ratchet key on success or olm_error() on
* failure. On failure last_error will be set with an error code. The
* last_error will be OUTPUT_BUFFER_TOO_SMALL if the buffer was too small.
*/
OLM_EXPORT size_t olm_outbound_group_session_key(
OlmOutboundGroupSession *session,
uint8_t * key, size_t key_length
);
#ifdef __cplusplus
} // extern "C"
#endif
#endif /* OLM_OUTBOUND_GROUP_SESSION_H_ */

View file

@ -0,0 +1,298 @@
/* Copyright 2018, 2019 New Vector Ltd
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#ifndef OLM_PK_H_
#define OLM_PK_H_
#include <stddef.h>
#include <stdint.h>
#include "olm/error.h"
#include "olm/olm_export.h"
#ifdef __cplusplus
extern "C" {
#endif
typedef struct OlmPkEncryption OlmPkEncryption;
/* The size of an encryption object in bytes */
OLM_EXPORT size_t olm_pk_encryption_size(void);
/** Initialise an encryption object using the supplied memory
* The supplied memory must be at least olm_pk_encryption_size() bytes */
OLM_EXPORT OlmPkEncryption *olm_pk_encryption(
void * memory
);
/** A null terminated string describing the most recent error to happen to an
* encryption object */
OLM_EXPORT const char * olm_pk_encryption_last_error(
const OlmPkEncryption * encryption
);
/** An error code describing the most recent error to happen to an encryption
* object */
OLM_EXPORT enum OlmErrorCode olm_pk_encryption_last_error_code(
const OlmPkEncryption * encryption
);
/** Clears the memory used to back this encryption object */
OLM_EXPORT size_t olm_clear_pk_encryption(
OlmPkEncryption *encryption
);
/** Set the recipient's public key for encrypting to */
OLM_EXPORT size_t olm_pk_encryption_set_recipient_key(
OlmPkEncryption *encryption,
void const *public_key, size_t public_key_length
);
/** Get the length of the ciphertext that will correspond to a plaintext of the
* given length. */
OLM_EXPORT size_t olm_pk_ciphertext_length(
const OlmPkEncryption *encryption,
size_t plaintext_length
);
/** Get the length of the message authentication code. */
OLM_EXPORT size_t olm_pk_mac_length(
const OlmPkEncryption *encryption
);
/** Get the length of a public or ephemeral key */
OLM_EXPORT size_t olm_pk_key_length(void);
/** The number of random bytes needed to encrypt a message. */
OLM_EXPORT size_t olm_pk_encrypt_random_length(
const OlmPkEncryption *encryption
);
/** Encrypt a plaintext for the recipient set using
* olm_pk_encryption_set_recipient_key. Writes to the ciphertext, mac, and
* ephemeral_key buffers, whose values should be sent to the recipient. mac is
* a Message Authentication Code to ensure that the data is received and
* decrypted properly. ephemeral_key is the public part of the ephemeral key
* used (together with the recipient's key) to generate a symmetric encryption
* key. Returns olm_error() on failure. If the ciphertext, mac, or
* ephemeral_key buffers were too small then olm_pk_encryption_last_error()
* will be "OUTPUT_BUFFER_TOO_SMALL". If there weren't enough random bytes then
* olm_pk_encryption_last_error() will be "OLM_INPUT_BUFFER_TOO_SMALL". */
OLM_EXPORT size_t olm_pk_encrypt(
OlmPkEncryption *encryption,
void const * plaintext, size_t plaintext_length,
void * ciphertext, size_t ciphertext_length,
void * mac, size_t mac_length,
void * ephemeral_key, size_t ephemeral_key_size,
const void * random, size_t random_length
);
typedef struct OlmPkDecryption OlmPkDecryption;
/* The size of a decryption object in bytes */
OLM_EXPORT size_t olm_pk_decryption_size(void);
/** Initialise a decryption object using the supplied memory
* The supplied memory must be at least olm_pk_decryption_size() bytes */
OLM_EXPORT OlmPkDecryption *olm_pk_decryption(
void * memory
);
/** A null terminated string describing the most recent error to happen to a
* decription object */
OLM_EXPORT const char * olm_pk_decryption_last_error(
const OlmPkDecryption * decryption
);
/** An error code describing the most recent error to happen to a decription
* object */
OLM_EXPORT enum OlmErrorCode olm_pk_decryption_last_error_code(
const OlmPkDecryption * decryption
);
/** Clears the memory used to back this decryption object */
OLM_EXPORT size_t olm_clear_pk_decryption(
OlmPkDecryption *decryption
);
/** Get the number of bytes required to store an olm private key
*/
OLM_EXPORT size_t olm_pk_private_key_length(void);
/** DEPRECATED: Use olm_pk_private_key_length()
*/
OLM_EXPORT size_t olm_pk_generate_key_random_length(void);
/** Initialise the key from the private part of a key as returned by
* olm_pk_get_private_key(). The associated public key will be written to the
* pubkey buffer. Returns olm_error() on failure. If the pubkey buffer is too
* small then olm_pk_decryption_last_error() will be "OUTPUT_BUFFER_TOO_SMALL".
* If the private key was not long enough then olm_pk_decryption_last_error()
* will be "OLM_INPUT_BUFFER_TOO_SMALL".
*
* Note that the pubkey is a base64 encoded string, but the private key is
* an unencoded byte array
*/
OLM_EXPORT size_t olm_pk_key_from_private(
OlmPkDecryption * decryption,
void * pubkey, size_t pubkey_length,
const void * privkey, size_t privkey_length
);
/** DEPRECATED: Use olm_pk_key_from_private
*/
OLM_EXPORT size_t olm_pk_generate_key(
OlmPkDecryption * decryption,
void * pubkey, size_t pubkey_length,
const void * privkey, size_t privkey_length
);
/** Returns the number of bytes needed to store a decryption object. */
OLM_EXPORT size_t olm_pickle_pk_decryption_length(
const OlmPkDecryption * decryption
);
/** Stores decryption object as a base64 string. Encrypts the object using the
* supplied key. Returns the length of the pickled object on success.
* Returns olm_error() on failure. If the pickle output buffer
* is smaller than olm_pickle_pk_decryption_length() then
* olm_pk_decryption_last_error() will be "OUTPUT_BUFFER_TOO_SMALL" */
OLM_EXPORT size_t olm_pickle_pk_decryption(
OlmPkDecryption * decryption,
void const * key, size_t key_length,
void *pickled, size_t pickled_length
);
/** Loads a decryption object from a pickled base64 string. The associated
* public key will be written to the pubkey buffer. Decrypts the object using
* the supplied key. Returns olm_error() on failure. If the key doesn't
* match the one used to encrypt the account then olm_pk_decryption_last_error()
* will be "BAD_ACCOUNT_KEY". If the base64 couldn't be decoded then
* olm_pk_decryption_last_error() will be "INVALID_BASE64". The input pickled
* buffer is destroyed */
OLM_EXPORT size_t olm_unpickle_pk_decryption(
OlmPkDecryption * decryption,
void const * key, size_t key_length,
void *pickled, size_t pickled_length,
void *pubkey, size_t pubkey_length
);
/** Get the length of the plaintext that will correspond to a ciphertext of the
* given length. */
OLM_EXPORT size_t olm_pk_max_plaintext_length(
const OlmPkDecryption * decryption,
size_t ciphertext_length
);
/** Decrypt a ciphertext. The input ciphertext buffer is destroyed. See the
* olm_pk_encrypt function for descriptions of the ephemeral_key and mac
* arguments. Returns the length of the plaintext on success. Returns
* olm_error() on failure. If the plaintext buffer is too small then
* olm_pk_encryption_last_error() will be "OUTPUT_BUFFER_TOO_SMALL". */
OLM_EXPORT size_t olm_pk_decrypt(
OlmPkDecryption * decryption,
void const * ephemeral_key, size_t ephemeral_key_length,
void const * mac, size_t mac_length,
void * ciphertext, size_t ciphertext_length,
void * plaintext, size_t max_plaintext_length
);
/**
* Get the private key for an OlmDecryption object as an unencoded byte array
* private_key must be a pointer to a buffer of at least
* olm_pk_private_key_length() bytes and this length must be passed in
* private_key_length. If the given buffer is too small, returns olm_error()
* and olm_pk_encryption_last_error() will be "OUTPUT_BUFFER_TOO_SMALL".
* Returns the number of bytes written.
*/
OLM_EXPORT size_t olm_pk_get_private_key(
OlmPkDecryption * decryption,
void *private_key, size_t private_key_length
);
typedef struct OlmPkSigning OlmPkSigning;
/* The size of a signing object in bytes */
OLM_EXPORT size_t olm_pk_signing_size(void);
/** Initialise a signing object using the supplied memory
* The supplied memory must be at least olm_pk_signing_size() bytes */
OLM_EXPORT OlmPkSigning *olm_pk_signing(
void * memory
);
/** A null terminated string describing the most recent error to happen to a
* signing object */
OLM_EXPORT const char * olm_pk_signing_last_error(
const OlmPkSigning * sign
);
/** A null terminated string describing the most recent error to happen to a
* signing object */
OLM_EXPORT enum OlmErrorCode olm_pk_signing_last_error_code(
const OlmPkSigning * sign
);
/** Clears the memory used to back this signing object */
OLM_EXPORT size_t olm_clear_pk_signing(
OlmPkSigning *sign
);
/**
* Initialise the signing object with a public/private keypair from a seed. The
* associated public key will be written to the pubkey buffer. Returns
* olm_error() on failure. If the public key buffer is too small then
* olm_pk_signing_last_error() will be "OUTPUT_BUFFER_TOO_SMALL". If the seed
* buffer is too small then olm_pk_signing_last_error() will be
* "INPUT_BUFFER_TOO_SMALL".
*/
OLM_EXPORT size_t olm_pk_signing_key_from_seed(
OlmPkSigning * sign,
void * pubkey, size_t pubkey_length,
const void * seed, size_t seed_length
);
/**
* The size required for the seed for initialising a signing object.
*/
OLM_EXPORT size_t olm_pk_signing_seed_length(void);
/**
* The size of the public key of a signing object.
*/
OLM_EXPORT size_t olm_pk_signing_public_key_length(void);
/**
* The size of a signature created by a signing object.
*/
OLM_EXPORT size_t olm_pk_signature_length(void);
/**
* Sign a message. The signature will be written to the signature
* buffer. Returns olm_error() on failure. If the signature buffer is too
* small, olm_pk_signing_last_error() will be "OUTPUT_BUFFER_TOO_SMALL".
*/
OLM_EXPORT size_t olm_pk_sign(
OlmPkSigning *sign,
uint8_t const * message, size_t message_length,
uint8_t * signature, size_t signature_length
);
#ifdef __cplusplus
}
#endif
#endif /* OLM_PK_H_ */

View file

@ -0,0 +1,197 @@
/* Copyright 2018-2019 New Vector Ltd
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#ifndef OLM_SAS_H_
#define OLM_SAS_H_
#include <stddef.h>
#include "olm/error.h"
#include "olm/olm_export.h"
#ifdef __cplusplus
extern "C" {
#endif
/** @defgroup SAS Short Authentication String verification
* These functions are used for verifying keys using the Short Authentication
* String (SAS) method.
* @{
*/
typedef struct OlmSAS OlmSAS;
/** A null terminated string describing the most recent error to happen to an
* SAS object. */
OLM_EXPORT const char * olm_sas_last_error(
const OlmSAS * sas
);
/** An error code describing the most recent error to happen to an SAS
* object. */
OLM_EXPORT enum OlmErrorCode olm_sas_last_error_code(
const OlmSAS * sas
);
/** The size of an SAS object in bytes. */
OLM_EXPORT size_t olm_sas_size(void);
/** Initialize an SAS object using the supplied memory.
* The supplied memory must be at least `olm_sas_size()` bytes. */
OLM_EXPORT OlmSAS * olm_sas(
void * memory
);
/** Clears the memory used to back an SAS object. */
OLM_EXPORT size_t olm_clear_sas(
OlmSAS * sas
);
/** The number of random bytes needed to create an SAS object. */
OLM_EXPORT size_t olm_create_sas_random_length(
const OlmSAS * sas
);
/** Creates a new SAS object.
*
* @param[in] sas the SAS object to create, initialized by `olm_sas()`.
* @param[in] random array of random bytes. The contents of the buffer may be
* overwritten.
* @param[in] random_length the number of random bytes provided. Must be at
* least `olm_create_sas_random_length()`.
*
* @return `olm_error()` on failure. If there weren't enough random bytes then
* `olm_sas_last_error()` will be `NOT_ENOUGH_RANDOM`.
*/
OLM_EXPORT size_t olm_create_sas(
OlmSAS * sas,
void * random, size_t random_length
);
/** The size of a public key in bytes. */
OLM_EXPORT size_t olm_sas_pubkey_length(const OlmSAS * sas);
/** Get the public key for the SAS object.
*
* @param[in] sas the SAS object.
* @param[out] pubkey buffer to store the public key.
* @param[in] pubkey_length the size of the `pubkey` buffer. Must be at least
* `olm_sas_pubkey_length()`.
*
* @return `olm_error()` on failure. If the `pubkey` buffer is too small, then
* `olm_sas_last_error()` will be `OUTPUT_BUFFER_TOO_SMALL`.
*/
OLM_EXPORT size_t olm_sas_get_pubkey(
OlmSAS * sas,
void * pubkey, size_t pubkey_length
);
/** Sets the public key of other user.
*
* @param[in] sas the SAS object.
* @param[in] their_key the other user's public key. The contents of the
* buffer will be overwritten.
* @param[in] their_key_length the size of the `their_key` buffer.
*
* @return `olm_error()` on failure. If the `their_key` buffer is too small,
* then `olm_sas_last_error()` will be `INPUT_BUFFER_TOO_SMALL`.
*/
OLM_EXPORT size_t olm_sas_set_their_key(
OlmSAS *sas,
void * their_key, size_t their_key_length
);
/** Checks if their key was set.
*
* @param[in] sas the SAS object.
*
*/
OLM_EXPORT int olm_sas_is_their_key_set(
const OlmSAS *sas
);
/** Generate bytes to use for the short authentication string.
*
* @param[in] sas the SAS object.
* @param[in] info extra information to mix in when generating the bytes, as
* per the Matrix spec.
* @param[in] info_length the length of the `info` parameter.
* @param[out] output the output buffer.
* @param[in] output_length the size of the output buffer. For hex-based SAS
* as in the Matrix spec, this will be 5.
*
* @return `olm_error()` on failure. If their key wasn't set then
* `olm_sas_last_error()` will be `SAS_THEIR_KEY_NOT_SET`.
*/
OLM_EXPORT size_t olm_sas_generate_bytes(
OlmSAS * sas,
const void * info, size_t info_length,
void * output, size_t output_length
);
/** The size of the message authentication code generated by
* olm_sas_calculate_mac()`. */
OLM_EXPORT size_t olm_sas_mac_length(
const OlmSAS *sas
);
/** Generate a message authentication code (MAC) based on the shared secret.
*
* @param[in] sas the SAS object.
* @param[in] input the message to produce the authentication code for.
* @param[in] input_length the length of the message.
* @param[in] info extra information to mix in when generating the MAC, as per
* the Matrix spec.
* @param[in] info_length the length of the `info` parameter.
* @param[out] mac the buffer in which to store the MAC.
* @param[in] mac_length the size of the `mac` buffer. Must be at least
* `olm_sas_mac_length()`
*
* @return `olm_error()` on failure. If the `mac` buffer is too small, then
* `olm_sas_last_error()` will be `OUTPUT_BUFFER_TOO_SMALL`.
*/
OLM_EXPORT size_t olm_sas_calculate_mac(
OlmSAS * sas,
const void * input, size_t input_length,
const void * info, size_t info_length,
void * mac, size_t mac_length
);
// A version of the calculate mac function that produces base64 strings that are
// compatible with other base64 implementations.
OLM_EXPORT size_t olm_sas_calculate_mac_fixed_base64(
OlmSAS * sas,
const void * input, size_t input_length,
const void * info, size_t info_length,
void * mac, size_t mac_length
);
// for compatibility with an old version of Riot
OLM_EXPORT size_t olm_sas_calculate_mac_long_kdf(
OlmSAS * sas,
const void * input, size_t input_length,
const void * info, size_t info_length,
void * mac, size_t mac_length
);
/** @} */ // end of SAS group
#ifdef __cplusplus
} // extern "C"
#endif
#endif /* OLM_SAS_H_ */

View file

@ -0,0 +1,11 @@
get_filename_component(Olm_CMAKE_DIR "${CMAKE_CURRENT_LIST_FILE}" PATH)
include(CMakeFindDependencyMacro)
list(APPEND CMAKE_MODULE_PATH ${Olm_CMAKE_DIR})
list(REMOVE_AT CMAKE_MODULE_PATH -1)
if(NOT TARGET Olm::olm)
include("${Olm_CMAKE_DIR}/OlmTargets.cmake")
endif()
set(Olm_LIBRARIES Olm::olm)

View file

@ -0,0 +1,65 @@
# This is a basic version file for the Config-mode of find_package().
# It is used by write_basic_package_version_file() as input file for configure_file()
# to create a version-file which can be installed along a config.cmake file.
#
# The created file sets PACKAGE_VERSION_EXACT if the current version string and
# the requested version string are exactly the same and it sets
# PACKAGE_VERSION_COMPATIBLE if the current version is >= requested version,
# but only if the requested major version is the same as the current one.
# The variable CVF_VERSION must be set before calling configure_file().
set(PACKAGE_VERSION "3.2.16")
if(PACKAGE_VERSION VERSION_LESS PACKAGE_FIND_VERSION)
set(PACKAGE_VERSION_COMPATIBLE FALSE)
else()
if("3.2.16" MATCHES "^([0-9]+)\\.")
set(CVF_VERSION_MAJOR "${CMAKE_MATCH_1}")
if(NOT CVF_VERSION_MAJOR VERSION_EQUAL 0)
string(REGEX REPLACE "^0+" "" CVF_VERSION_MAJOR "${CVF_VERSION_MAJOR}")
endif()
else()
set(CVF_VERSION_MAJOR "3.2.16")
endif()
if(PACKAGE_FIND_VERSION_RANGE)
# both endpoints of the range must have the expected major version
math (EXPR CVF_VERSION_MAJOR_NEXT "${CVF_VERSION_MAJOR} + 1")
if (NOT PACKAGE_FIND_VERSION_MIN_MAJOR STREQUAL CVF_VERSION_MAJOR
OR ((PACKAGE_FIND_VERSION_RANGE_MAX STREQUAL "INCLUDE" AND NOT PACKAGE_FIND_VERSION_MAX_MAJOR STREQUAL CVF_VERSION_MAJOR)
OR (PACKAGE_FIND_VERSION_RANGE_MAX STREQUAL "EXCLUDE" AND NOT PACKAGE_FIND_VERSION_MAX VERSION_LESS_EQUAL CVF_VERSION_MAJOR_NEXT)))
set(PACKAGE_VERSION_COMPATIBLE FALSE)
elseif(PACKAGE_FIND_VERSION_MIN_MAJOR STREQUAL CVF_VERSION_MAJOR
AND ((PACKAGE_FIND_VERSION_RANGE_MAX STREQUAL "INCLUDE" AND PACKAGE_VERSION VERSION_LESS_EQUAL PACKAGE_FIND_VERSION_MAX)
OR (PACKAGE_FIND_VERSION_RANGE_MAX STREQUAL "EXCLUDE" AND PACKAGE_VERSION VERSION_LESS PACKAGE_FIND_VERSION_MAX)))
set(PACKAGE_VERSION_COMPATIBLE TRUE)
else()
set(PACKAGE_VERSION_COMPATIBLE FALSE)
endif()
else()
if(PACKAGE_FIND_VERSION_MAJOR STREQUAL CVF_VERSION_MAJOR)
set(PACKAGE_VERSION_COMPATIBLE TRUE)
else()
set(PACKAGE_VERSION_COMPATIBLE FALSE)
endif()
if(PACKAGE_FIND_VERSION STREQUAL PACKAGE_VERSION)
set(PACKAGE_VERSION_EXACT TRUE)
endif()
endif()
endif()
# if the installed or the using project don't have CMAKE_SIZEOF_VOID_P set, ignore it:
if("${CMAKE_SIZEOF_VOID_P}" STREQUAL "" OR "8" STREQUAL "")
return()
endif()
# check that the installed version has the same 32/64bit-ness as the one which is currently searching:
if(NOT CMAKE_SIZEOF_VOID_P STREQUAL "8")
math(EXPR installedBits "8 * 8")
set(PACKAGE_VERSION "${PACKAGE_VERSION} (${installedBits}bit)")
set(PACKAGE_VERSION_UNSUITABLE TRUE)
endif()

View file

@ -0,0 +1,18 @@
#----------------------------------------------------------------
# Generated CMake target import file for configuration "Debug".
#----------------------------------------------------------------
# Commands may need to know the format version.
set(CMAKE_IMPORT_FILE_VERSION 1)
# Import target "Olm::Olm" for configuration "Debug"
set_property(TARGET Olm::Olm APPEND PROPERTY IMPORTED_CONFIGURATIONS DEBUG)
set_target_properties(Olm::Olm PROPERTIES
IMPORTED_IMPLIB_DEBUG "${_IMPORT_PREFIX}/lib/olm.lib"
)
list(APPEND _cmake_import_check_targets Olm::Olm )
list(APPEND _cmake_import_check_files_for_Olm::Olm "${_IMPORT_PREFIX}/lib/olm.lib" )
# Commands beyond this point should not need to know the version.
set(CMAKE_IMPORT_FILE_VERSION)

View file

@ -0,0 +1,18 @@
#----------------------------------------------------------------
# Generated CMake target import file for configuration "Release".
#----------------------------------------------------------------
# Commands may need to know the format version.
set(CMAKE_IMPORT_FILE_VERSION 1)
# Import target "Olm::Olm" for configuration "Release"
set_property(TARGET Olm::Olm APPEND PROPERTY IMPORTED_CONFIGURATIONS RELEASE)
set_target_properties(Olm::Olm PROPERTIES
IMPORTED_IMPLIB_RELEASE "${_IMPORT_PREFIX}/lib/libolm.dll.a"
)
list(APPEND _cmake_import_check_targets Olm::Olm )
list(APPEND _cmake_import_check_files_for_Olm::Olm "${_IMPORT_PREFIX}/lib/libolm.dll.a" )
# Commands beyond this point should not need to know the version.
set(CMAKE_IMPORT_FILE_VERSION)

View file

@ -0,0 +1,102 @@
# Generated by CMake
if("${CMAKE_MAJOR_VERSION}.${CMAKE_MINOR_VERSION}" LESS 2.8)
message(FATAL_ERROR "CMake >= 2.8.0 required")
endif()
if(CMAKE_VERSION VERSION_LESS "2.8.3")
message(FATAL_ERROR "CMake >= 2.8.3 required")
endif()
cmake_policy(PUSH)
cmake_policy(VERSION 2.8.3...3.24)
#----------------------------------------------------------------
# Generated CMake target import file.
#----------------------------------------------------------------
# Commands may need to know the format version.
set(CMAKE_IMPORT_FILE_VERSION 1)
# Protect against multiple inclusion, which would fail when already imported targets are added once more.
set(_cmake_targets_defined "")
set(_cmake_targets_not_defined "")
set(_cmake_expected_targets "")
foreach(_cmake_expected_target IN ITEMS Olm::Olm)
list(APPEND _cmake_expected_targets "${_cmake_expected_target}")
if(TARGET "${_cmake_expected_target}")
list(APPEND _cmake_targets_defined "${_cmake_expected_target}")
else()
list(APPEND _cmake_targets_not_defined "${_cmake_expected_target}")
endif()
endforeach()
unset(_cmake_expected_target)
if(_cmake_targets_defined STREQUAL _cmake_expected_targets)
unset(_cmake_targets_defined)
unset(_cmake_targets_not_defined)
unset(_cmake_expected_targets)
unset(CMAKE_IMPORT_FILE_VERSION)
cmake_policy(POP)
return()
endif()
if(NOT _cmake_targets_defined STREQUAL "")
string(REPLACE ";" ", " _cmake_targets_defined_text "${_cmake_targets_defined}")
string(REPLACE ";" ", " _cmake_targets_not_defined_text "${_cmake_targets_not_defined}")
message(FATAL_ERROR "Some (but not all) targets in this export set were already defined.\nTargets Defined: ${_cmake_targets_defined_text}\nTargets not yet defined: ${_cmake_targets_not_defined_text}\n")
endif()
unset(_cmake_targets_defined)
unset(_cmake_targets_not_defined)
unset(_cmake_expected_targets)
# Compute the installation prefix relative to this file.
get_filename_component(_IMPORT_PREFIX "${CMAKE_CURRENT_LIST_FILE}" PATH)
get_filename_component(_IMPORT_PREFIX "${_IMPORT_PREFIX}" PATH)
get_filename_component(_IMPORT_PREFIX "${_IMPORT_PREFIX}" PATH)
get_filename_component(_IMPORT_PREFIX "${_IMPORT_PREFIX}" PATH)
if(_IMPORT_PREFIX STREQUAL "/")
set(_IMPORT_PREFIX "")
endif()
# Create imported target Olm::Olm
add_library(Olm::Olm SHARED IMPORTED)
set_target_properties(Olm::Olm PROPERTIES
INTERFACE_INCLUDE_DIRECTORIES "${_IMPORT_PREFIX}/include"
)
# Load information for each installed configuration.
file(GLOB _cmake_config_files "${CMAKE_CURRENT_LIST_DIR}/OlmTargets-*.cmake")
foreach(_cmake_config_file IN LISTS _cmake_config_files)
include("${_cmake_config_file}")
endforeach()
unset(_cmake_config_file)
unset(_cmake_config_files)
# Cleanup temporary variables.
set(_IMPORT_PREFIX)
# Loop over all imported files and verify that they actually exist
foreach(_cmake_target IN LISTS _cmake_import_check_targets)
foreach(_cmake_file IN LISTS "_cmake_import_check_files_for_${_cmake_target}")
if(NOT EXISTS "${_cmake_file}")
message(FATAL_ERROR "The imported target \"${_cmake_target}\" references the file
\"${_cmake_file}\"
but this file does not exist. Possible reasons include:
* The file was deleted, renamed, or moved to another location.
* An install or uninstall procedure did not complete successfully.
* The installation package was faulty and contained
\"${CMAKE_CURRENT_LIST_FILE}\"
but not all the files it references.
")
endif()
endforeach()
unset(_cmake_file)
unset("_cmake_import_check_files_for_${_cmake_target}")
endforeach()
unset(_cmake_target)
unset(_cmake_import_check_targets)
# This file does not depend on other imported targets which have
# been exported from the same project but in a separate export set.
# Commands beyond this point should not need to know the version.
set(CMAKE_IMPORT_FILE_VERSION)
cmake_policy(POP)

Binary file not shown.

BIN
windows-olm/lib/olm.lib Normal file

Binary file not shown.