тонна гонвнокода
This commit is contained in:
parent
5ea0e943fb
commit
6b7bf681ae
16
.gitignore
vendored
16
.gitignore
vendored
@ -2,15 +2,17 @@
|
||||
docs.json
|
||||
__dummy.html
|
||||
docs/
|
||||
/skunkybot-d
|
||||
skunkybot-d.so
|
||||
skunkybot-d.dylib
|
||||
skunkybot-d.dll
|
||||
skunkybot-d.a
|
||||
skunkybot-d.lib
|
||||
skunkybot-d-test-*
|
||||
/neptune
|
||||
neptune.so
|
||||
neptune.dylib
|
||||
neptune.dll
|
||||
neptune.a
|
||||
neptune.lib
|
||||
neptune-test-*
|
||||
*.exe
|
||||
*.pdb
|
||||
*.o
|
||||
*.db
|
||||
*.obj
|
||||
*.lst
|
||||
config.json
|
||||
|
10
README.md
10
README.md
@ -1,7 +1,13 @@
|
||||
# TODO
|
||||
- [ ] get rid of indian code
|
||||
- [x] make function listener asynchronious
|
||||
- [x] make all as replies
|
||||
- [x] APOD (https://api.nasa.gov/)
|
||||
- [ ] implement encrypting
|
||||
- [ ] implement admin tools (i.e. ban, mute, kick, etc)
|
||||
- [ ] implement shared-library modules
|
||||
- [ ] implement config
|
||||
- [ ] implement forgejo/gitea webhooks
|
||||
- [ ] implement MSC2448
|
||||
- [ ] implement rss feeds
|
||||
# INFO
|
||||
говнобот
|
||||
Deps: sqlite3, libolm, libcurl
|
7
config.example.json
Normal file
7
config.example.json
Normal file
@ -0,0 +1,7 @@
|
||||
{
|
||||
"homeserver": "http://192.168.1.132:8008",
|
||||
"token": "zfPqqre33zFgLECg71cQxNHdNByDAsvh",
|
||||
"status": "https://code.lost-skunk.cc/neptune",
|
||||
"database_path": "matrix.db",
|
||||
"accept_invitations": true
|
||||
}
|
12
dub.sdl
12
dub.sdl
@ -1,6 +1,12 @@
|
||||
name "skunkybot-d"
|
||||
name "neptune"
|
||||
description "Matrix bot"
|
||||
authors "skunk"
|
||||
copyright "Copyright © 2025, skunk"
|
||||
authors "lost+skunk"
|
||||
copyright "Copyright © 2025, lost+skunk"
|
||||
license "AGPL-3.0-only"
|
||||
dependency "gamut" version="~>3.2.0"
|
||||
dependency "database:sqlite" version="~>1.2.1"
|
||||
dependency "database" version="~>1.2.1"
|
||||
dependency "asdf" version="~>0.7.17"
|
||||
dflags "-L-s"
|
||||
dflags "-mcpu=native" platform="ldc"
|
||||
libs "curl"
|
||||
|
@ -2,8 +2,19 @@
|
||||
"fileVersion": 1,
|
||||
"versions": {
|
||||
"asdf": "0.7.17",
|
||||
"automem": "0.6.11",
|
||||
"cachetools": "0.4.1",
|
||||
"database": "1.2.1",
|
||||
"gamut": "3.2.0",
|
||||
"intel-intrinsics": "1.11.25",
|
||||
"miniz": "0.0.1",
|
||||
"mir-algorithm": "3.22.3",
|
||||
"mir-core": "1.7.1",
|
||||
"silly": "1.1.1"
|
||||
"mir-cpuid": "1.2.11",
|
||||
"mir-ion": "2.3.3",
|
||||
"requests": "2.1.3",
|
||||
"silly": "1.1.1",
|
||||
"test_allocator": "0.3.4",
|
||||
"unit-threaded": "0.10.8"
|
||||
}
|
||||
}
|
||||
|
35
source/api.d
Normal file
35
source/api.d
Normal file
@ -0,0 +1,35 @@
|
||||
module api;
|
||||
import util, asdf, api_data;
|
||||
|
||||
void send(T)(T content, string roomid, string type = "m.room.message") {
|
||||
import std.random: uniform;
|
||||
mkhsrq("/_matrix/client/v3/rooms/" ~ roomid ~ "/send/" ~ type ~
|
||||
"/skunky-" ~ intToStr(uniform(1111_1111, 9999_9999)), "PUT", content.serializeToJson);
|
||||
}
|
||||
|
||||
void rawState(string room, string name, string content) {
|
||||
mkhsrq (
|
||||
"/_matrix/client/v3/rooms/" ~ room ~ "/state/" ~ name,
|
||||
"PUT",
|
||||
content
|
||||
);
|
||||
}
|
||||
|
||||
void state(T)(string room, string name, T content) {
|
||||
rawState(room, name, content.serializeToJson);
|
||||
}
|
||||
|
||||
T getState(T)(string room, string name) {
|
||||
return mkhsrq("/_matrix/client/v3/rooms/" ~ room ~ "/state/" ~ name).body.deserialize!T;
|
||||
}
|
||||
|
||||
MSG event(string id, string room) {
|
||||
struct Evt { MSG content; }
|
||||
return (mkhsrq("/_matrix/client/v3/rooms/" ~ room ~ "/event/" ~ id).body.deserialize!Evt).content;
|
||||
}
|
||||
|
||||
string upload(T)(T file) {
|
||||
struct Upload { string content_uri; }
|
||||
return (mkhsrq("/_matrix/media/v3/upload", "POST", cast(string)file)
|
||||
.body.deserialize!Upload).content_uri;
|
||||
}
|
110
source/api_data.d
Normal file
110
source/api_data.d
Normal file
@ -0,0 +1,110 @@
|
||||
module api_data;
|
||||
import mir.serde, util: JsonObject;
|
||||
|
||||
struct Moderate {
|
||||
string user_id;
|
||||
@serdeOptional string reason;
|
||||
}
|
||||
|
||||
struct State {
|
||||
struct PowerLevels {
|
||||
short[string] users;
|
||||
}
|
||||
|
||||
struct ACL {
|
||||
@serdeOptional:
|
||||
bool allow_ip_literals;
|
||||
string[] allow = ["*"];
|
||||
string[] deny;
|
||||
}
|
||||
|
||||
JsonObject content;
|
||||
string event_id;
|
||||
string sender;
|
||||
string type;
|
||||
}
|
||||
|
||||
struct Encrypted {
|
||||
char[] algorithm;
|
||||
char[] ciphertext;
|
||||
char[] device_id;
|
||||
char[] sender_key;
|
||||
char[] session_id;
|
||||
}
|
||||
|
||||
struct MSG {
|
||||
struct Meta {
|
||||
int h, w;
|
||||
ulong size;
|
||||
string mimetype;
|
||||
}
|
||||
|
||||
struct Relates {
|
||||
struct EvtBase {
|
||||
string event_id;
|
||||
}
|
||||
|
||||
@serdeOptional @serdeKeys("m.in_reply_to") EvtBase reply;
|
||||
}
|
||||
|
||||
string body;
|
||||
@serdeOptional @serdeIgnoreDefault string formatted_body;
|
||||
string msgtype = "m.notice";
|
||||
@serdeOptional string format = "org.matrix.custom.html";
|
||||
|
||||
@serdeOptional @serdeIgnoreDefault:
|
||||
@serdeKeys("m.relates_to") Relates relates;
|
||||
string rel_type;
|
||||
string url;
|
||||
string filename;
|
||||
Meta info;
|
||||
}
|
||||
|
||||
struct Sync {
|
||||
struct StrippedStateEvent {
|
||||
JsonObject content;
|
||||
string sender, state_key, type;
|
||||
}
|
||||
|
||||
struct Unsigned {
|
||||
int age;
|
||||
string membership, transaction_id;
|
||||
}
|
||||
|
||||
struct Rooms {
|
||||
struct Invited {
|
||||
struct IS { StrippedStateEvent[] events; }
|
||||
IS invite_state;
|
||||
}
|
||||
struct Joined {
|
||||
struct Timeline {
|
||||
EventWithoutRoomID[] events;
|
||||
@serdeOptional bool limited;
|
||||
string prev_batch;
|
||||
}
|
||||
|
||||
struct UNC {
|
||||
int highlight_count;
|
||||
int notification_count;
|
||||
}
|
||||
|
||||
@serdeOptional Timeline timeline;
|
||||
@serdeOptional UNC unread_notifications;
|
||||
}
|
||||
|
||||
@serdeOptional Invited[string] invite;
|
||||
@serdeOptional Joined[string] join;
|
||||
}
|
||||
|
||||
@serdeOptional Rooms rooms;
|
||||
string next_batch;
|
||||
}
|
||||
|
||||
struct EventWithoutRoomID {
|
||||
JsonObject content;
|
||||
string event_id;
|
||||
ulong origin_server_ts;
|
||||
@serdeOptional string sender, state_key, type;
|
||||
@serdeIgnore string room;
|
||||
// Unsigned unsigned;
|
||||
}
|
179
source/app.d
179
source/app.d
@ -1,101 +1,104 @@
|
||||
module main;
|
||||
|
||||
import std.stdio: writeln;
|
||||
import std.net.curl;
|
||||
import asdf: deserialize, serializeToJson;
|
||||
|
||||
import util;
|
||||
import listener;
|
||||
|
||||
void main() {
|
||||
import std.process: environment;
|
||||
alias env = environment.get;
|
||||
homeserver = env("SKUNKYBOT_HOMESERVER");
|
||||
init(env("SKUNKYBOT_TOKEN"));
|
||||
sync;
|
||||
import database.sqlite.db;
|
||||
__gshared SQLite3DB db;
|
||||
|
||||
int main(string[] args) {
|
||||
import core.stdc.stdio;
|
||||
|
||||
char buf;
|
||||
char[] fileStr;
|
||||
auto file = fopen("config.json", "r");
|
||||
if (file is null) return 1;
|
||||
while ((buf = cast(char)fgetc(file)) != 255)
|
||||
fileStr ~= buf;
|
||||
fclose(file);
|
||||
|
||||
cfg = fileStr.deserialize!Config;
|
||||
cfg.token = "Authorization: Bearer " ~ cfg.token;
|
||||
|
||||
if (args.length == 5 && args[1] == "get-token") {
|
||||
auto rq = mkrqst(
|
||||
args[2]~"/_matrix/client/v3/login", "POST",
|
||||
`{
|
||||
"identifier": {
|
||||
"type": "m.id.user",
|
||||
"user": "`~args[3]~`"
|
||||
},
|
||||
"initial_device_display_name": "Neptune Bot",
|
||||
"password": "`~args[4]~`",
|
||||
"type": "m.login.password"
|
||||
}`,
|
||||
true
|
||||
);
|
||||
|
||||
if (rq.status != 200) {
|
||||
writeln("Something went wrong :(\n", rq.body);
|
||||
return 1;
|
||||
}
|
||||
|
||||
HTTP http;
|
||||
string syncUrl;
|
||||
string initialBatch;
|
||||
void init(string token) {
|
||||
http = HTTP();
|
||||
http.addRequestHeader("Authorization", "Bearer " ~ token);
|
||||
http.tcpNoDelay = true;
|
||||
struct Login {
|
||||
string access_token;
|
||||
}
|
||||
|
||||
// initial sync
|
||||
writeln("Your access token: \033[0;32m", (rq.body.deserialize!Login).access_token, "\033[0m.\n",
|
||||
"Save it!");
|
||||
return 0;
|
||||
}
|
||||
|
||||
init;
|
||||
|
||||
import core.thread;
|
||||
import commands.slaves;
|
||||
alias sl = commands.slaves;
|
||||
static foreach (member; __traits(allMembers, sl)) {
|
||||
static foreach (attr; __traits(getAttributes, __traits(getMember, sl, member))) {
|
||||
static if (is(attr == Parallel)) {
|
||||
new Thread(&__traits(getMember, sl, member)).start;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
import commands.apod,
|
||||
commands.misc,
|
||||
commands.mozhi,
|
||||
commands.moderation;
|
||||
|
||||
listen!(
|
||||
commands.apod,
|
||||
commands.misc,
|
||||
commands.mozhi,
|
||||
commands.moderation,
|
||||
);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
// https://m.lost-skunk.cc/_matrix/client/v3/presence/@me:lost-skunk.cc/status
|
||||
void init() {
|
||||
db = SQLite3DB(cfg.database_path);
|
||||
syncUrl = "/_matrix/client/v3/sync?set_presence=online";
|
||||
db.exec("create table if not exists client (latest_batch string)");
|
||||
db.exec("create table if not exists room_pls (room string, user string, pl integer)");
|
||||
auto q = db.query("select latest_batch from client");
|
||||
|
||||
if (q.step) initialBatch = q.get!string;
|
||||
else {
|
||||
import api_data: Sync;
|
||||
writeln("starting initial sync..");
|
||||
syncUrl = homeserver ~ "/_matrix/client/v3/sync?set_presence=online";
|
||||
initialBatch = (get(syncUrl, http).deserialize!Sync).next_batch; syncUrl ~= "&since=";
|
||||
Sync snk = mkhsrq(syncUrl).body.deserialize!Sync;
|
||||
initialBatch = snk.next_batch;
|
||||
db.exec("insert into client (latest_batch) values (?)", initialBatch);
|
||||
writeln("done!");
|
||||
|
||||
foreach(room; snk.rooms.join.keys) fetchMembers(room);
|
||||
}
|
||||
|
||||
void send(T)(T content, string roomid, string type = "m.room.message") {
|
||||
import std.random: uniform;
|
||||
put(homeserver~"/_matrix/client/v3/rooms/" ~ roomid ~ "/send/" ~ type ~
|
||||
"/skunky-" ~ intToStr(uniform(1111_1111, 9999_9999)), content.serializeToJson, http);
|
||||
}
|
||||
|
||||
// void join(string roomid) {
|
||||
// post(homeserver~"/_matrix/client/v3/rooms/"~roomid~"/join", http);
|
||||
// }
|
||||
|
||||
import commands;
|
||||
static MSG helpgen() {
|
||||
string buf;
|
||||
static foreach (member; __traits(allMembers, commands)) {
|
||||
static foreach (attr; __traits(getAttributes, __traits(getMember, commands, member))) {
|
||||
static if (is(typeof(attr) == Command)) buf ~= member ~ ": " ~ attr.description ~ '\n';
|
||||
}
|
||||
}
|
||||
return MSG(buf);
|
||||
}
|
||||
|
||||
void sync() {
|
||||
auto content = Sync();
|
||||
content.next_batch = initialBatch;
|
||||
for (;;) {
|
||||
string bthUrl = syncUrl ~ content.next_batch;
|
||||
try content = get(bthUrl, http).deserialize!Sync;
|
||||
catch (Exception e) { writeln("ERR: ", e.msg); continue; }
|
||||
|
||||
foreach (room, _; content.rooms.invite) {
|
||||
writeln("Joining to room: ", room);
|
||||
post(homeserver~"/_matrix/client/v3/rooms/"~room~"/join", null, http);
|
||||
send(MSG("Йа криведко"), room);
|
||||
}
|
||||
foreach (room, roomContent; content.rooms.join) {
|
||||
foreach(event; roomContent.timeline.events) {
|
||||
if (event.type == "m.room.message") {
|
||||
try {
|
||||
auto evt = deserialize!MSG(event.content.raw);
|
||||
if (!evt.body.length) break;
|
||||
auto argz = parseMsg(evt.body);
|
||||
|
||||
if (argz.command == "hlp") {
|
||||
send(helpgen, room);
|
||||
break;
|
||||
}
|
||||
|
||||
foreach (member; __traits(allMembers, commands)) {
|
||||
if (argz.command == member) {
|
||||
alias command = __traits(getMember, commands, member);
|
||||
foreach (attr; __traits(getAttributes, command)) {
|
||||
static if (is(typeof(attr) == Command)) {
|
||||
static if (is(typeof(command) == function))
|
||||
auto content = command(argz, &event);
|
||||
else static if (__traits(isStaticArray, command))
|
||||
auto content = MSG(command[0], command[1]);
|
||||
else
|
||||
auto content = MSG(command);
|
||||
send(content, room);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
} catch (Exception e) {
|
||||
writeln(e.msg);
|
||||
send(MSG(e.msg), room);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
syncUrl ~= "&since=";
|
||||
}
|
2223
source/bindings/curl.d
Normal file
2223
source/bindings/curl.d
Normal file
File diff suppressed because it is too large
Load Diff
93
source/bindings/olm/error.d
Normal file
93
source/bindings/olm/error.d
Normal file
@ -0,0 +1,93 @@
|
||||
/* 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.
|
||||
*/
|
||||
module libolm.error;
|
||||
|
||||
extern (C):
|
||||
|
||||
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. */
|
||||
}
|
||||
|
||||
alias OLM_SUCCESS = OlmErrorCode.OLM_SUCCESS;
|
||||
alias OLM_NOT_ENOUGH_RANDOM = OlmErrorCode.OLM_NOT_ENOUGH_RANDOM;
|
||||
alias OLM_OUTPUT_BUFFER_TOO_SMALL = OlmErrorCode.OLM_OUTPUT_BUFFER_TOO_SMALL;
|
||||
alias OLM_BAD_MESSAGE_VERSION = OlmErrorCode.OLM_BAD_MESSAGE_VERSION;
|
||||
alias OLM_BAD_MESSAGE_FORMAT = OlmErrorCode.OLM_BAD_MESSAGE_FORMAT;
|
||||
alias OLM_BAD_MESSAGE_MAC = OlmErrorCode.OLM_BAD_MESSAGE_MAC;
|
||||
alias OLM_BAD_MESSAGE_KEY_ID = OlmErrorCode.OLM_BAD_MESSAGE_KEY_ID;
|
||||
alias OLM_INVALID_BASE64 = OlmErrorCode.OLM_INVALID_BASE64;
|
||||
alias OLM_BAD_ACCOUNT_KEY = OlmErrorCode.OLM_BAD_ACCOUNT_KEY;
|
||||
alias OLM_UNKNOWN_PICKLE_VERSION = OlmErrorCode.OLM_UNKNOWN_PICKLE_VERSION;
|
||||
alias OLM_CORRUPTED_PICKLE = OlmErrorCode.OLM_CORRUPTED_PICKLE;
|
||||
alias OLM_BAD_SESSION_KEY = OlmErrorCode.OLM_BAD_SESSION_KEY;
|
||||
alias OLM_UNKNOWN_MESSAGE_INDEX = OlmErrorCode.OLM_UNKNOWN_MESSAGE_INDEX;
|
||||
alias OLM_BAD_LEGACY_ACCOUNT_PICKLE = OlmErrorCode.OLM_BAD_LEGACY_ACCOUNT_PICKLE;
|
||||
alias OLM_BAD_SIGNATURE = OlmErrorCode.OLM_BAD_SIGNATURE;
|
||||
alias OLM_INPUT_BUFFER_TOO_SMALL = OlmErrorCode.OLM_INPUT_BUFFER_TOO_SMALL;
|
||||
alias OLM_SAS_THEIR_KEY_NOT_SET = OlmErrorCode.OLM_SAS_THEIR_KEY_NOT_SET;
|
||||
alias OLM_PICKLE_EXTRA_DATA = OlmErrorCode.OLM_PICKLE_EXTRA_DATA;
|
||||
|
||||
/** get a string representation of the given error code. */
|
||||
const(char)* _olm_error_to_string (OlmErrorCode error);
|
||||
|
||||
// extern "C"
|
||||
|
||||
/* OLM_ERROR_H_ */
|
188
source/bindings/olm/inbound.d
Normal file
188
source/bindings/olm/inbound.d
Normal file
@ -0,0 +1,188 @@
|
||||
module libolm.inbound;
|
||||
/* 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.
|
||||
*/
|
||||
|
||||
import libolm.error;
|
||||
|
||||
@nogc:
|
||||
extern (C):
|
||||
|
||||
struct OlmInboundGroupSession;
|
||||
|
||||
/** get the size of an inbound group session, in bytes. */
|
||||
size_t olm_inbound_group_session_size ();
|
||||
|
||||
/**
|
||||
* Initialise an inbound group session object using the supplied memory
|
||||
* The supplied memory should be at least olm_inbound_group_session_size()
|
||||
* bytes.
|
||||
*/
|
||||
OlmInboundGroupSession* olm_inbound_group_session (void* memory);
|
||||
|
||||
/**
|
||||
* A null terminated string describing the most recent error to happen to a
|
||||
* group session */
|
||||
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 */
|
||||
OlmErrorCode olm_inbound_group_session_last_error_code (const(OlmInboundGroupSession)* session);
|
||||
|
||||
/** Clears the memory used to back this group session */
|
||||
size_t olm_clear_inbound_group_session (OlmInboundGroupSession* session);
|
||||
|
||||
/** Returns the number of bytes needed to store an inbound group session */
|
||||
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"
|
||||
*/
|
||||
size_t olm_pickle_inbound_group_session (OlmInboundGroupSession* session, const(void)* 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
|
||||
*/
|
||||
size_t olm_unpickle_inbound_group_session (OlmInboundGroupSession* session, const(void)* 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
|
||||
*/
|
||||
|
||||
/* base64-encoded keys */
|
||||
size_t olm_init_inbound_group_session (OlmInboundGroupSession* session, const(ubyte)* 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
|
||||
*/
|
||||
|
||||
/* base64-encoded keys; note that it will be overwritten with the base64-decoded
|
||||
data. */
|
||||
size_t olm_import_inbound_group_session (OlmInboundGroupSession* session, const(ubyte)* 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.
|
||||
*/
|
||||
size_t olm_group_decrypt_max_plaintext_length (OlmInboundGroupSession* session, ubyte* 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)
|
||||
*/
|
||||
|
||||
/* input; note that it will be overwritten with the base64-decoded
|
||||
message. */
|
||||
|
||||
/* output */
|
||||
size_t olm_group_decrypt (OlmInboundGroupSession* session, ubyte* message, size_t message_length, ubyte* plaintext, size_t max_plaintext_length, uint* message_index);
|
||||
|
||||
/**
|
||||
* Get the number of bytes returned by olm_inbound_group_session_id()
|
||||
*/
|
||||
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.
|
||||
*/
|
||||
size_t olm_inbound_group_session_id (OlmInboundGroupSession* session, ubyte* id, size_t id_length);
|
||||
|
||||
/**
|
||||
* Get the first message index we know how to decrypt.
|
||||
*/
|
||||
uint 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.
|
||||
*/
|
||||
int olm_inbound_group_session_is_verified (const(OlmInboundGroupSession)* session);
|
||||
|
||||
/**
|
||||
* Get the number of bytes returned by olm_export_inbound_group_session()
|
||||
*/
|
||||
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)
|
||||
*/
|
||||
size_t olm_export_inbound_group_session (OlmInboundGroupSession* session, ubyte* key, size_t key_length, uint message_index);
|
||||
|
||||
// extern "C"
|
||||
|
||||
/* OLM_INBOUND_GROUP_SESSION_H_ */
|
349
source/bindings/olm/olm.d
Normal file
349
source/bindings/olm/olm.d
Normal file
@ -0,0 +1,349 @@
|
||||
/* 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.
|
||||
*/
|
||||
|
||||
import libolm.error;
|
||||
extern (C):
|
||||
|
||||
extern __gshared const size_t OLM_MESSAGE_TYPE_PRE_KEY;
|
||||
extern __gshared const size_t OLM_MESSAGE_TYPE_MESSAGE;
|
||||
|
||||
struct OlmAccount;
|
||||
struct OlmSession;
|
||||
struct OlmUtility;
|
||||
|
||||
/** Get the version number of the library.
|
||||
* Arguments will be updated if non-null.
|
||||
*/
|
||||
void olm_get_library_version (ubyte* major, ubyte* minor, ubyte* patch);
|
||||
|
||||
/** The size of an account object in bytes */
|
||||
size_t olm_account_size ();
|
||||
|
||||
/** The size of a session object in bytes */
|
||||
size_t olm_session_size ();
|
||||
|
||||
/** The size of a utility object in bytes */
|
||||
size_t olm_utility_size ();
|
||||
|
||||
/** Initialise an account object using the supplied memory
|
||||
* The supplied memory must be at least olm_account_size() bytes */
|
||||
OlmAccount* olm_account (void* memory);
|
||||
|
||||
/** Initialise a session object using the supplied memory
|
||||
* The supplied memory must be at least olm_session_size() bytes */
|
||||
OlmSession* olm_session (void* memory);
|
||||
|
||||
/** Initialise a utility object using the supplied memory
|
||||
* The supplied memory must be at least olm_utility_size() bytes */
|
||||
OlmUtility* olm_utility (void* memory);
|
||||
|
||||
/** The value that olm will return from a function if there was an error */
|
||||
size_t olm_error ();
|
||||
|
||||
/** A null terminated string describing the most recent error to happen to an
|
||||
* account */
|
||||
const(char)* olm_account_last_error (const(OlmAccount)* account);
|
||||
|
||||
/** An error code describing the most recent error to happen to an account */
|
||||
OlmErrorCode olm_account_last_error_code (const(OlmAccount)* account);
|
||||
|
||||
/** A null terminated string describing the most recent error to happen to a
|
||||
* session */
|
||||
const(char)* olm_session_last_error (const(OlmSession)* session);
|
||||
|
||||
/** An error code describing the most recent error to happen to a session */
|
||||
OlmErrorCode olm_session_last_error_code (const(OlmSession)* session);
|
||||
|
||||
/** A null terminated string describing the most recent error to happen to a
|
||||
* utility */
|
||||
const(char)* olm_utility_last_error (const(OlmUtility)* utility);
|
||||
|
||||
/** An error code describing the most recent error to happen to a utility */
|
||||
OlmErrorCode olm_utility_last_error_code (const(OlmUtility)* utility);
|
||||
|
||||
/** Clears the memory used to back this account */
|
||||
size_t olm_clear_account (OlmAccount* account);
|
||||
|
||||
/** Clears the memory used to back this session */
|
||||
size_t olm_clear_session (OlmSession* session);
|
||||
|
||||
/** Clears the memory used to back this utility */
|
||||
size_t olm_clear_utility (OlmUtility* utility);
|
||||
|
||||
/** Returns the number of bytes needed to store an account */
|
||||
size_t olm_pickle_account_length (const(OlmAccount)* account);
|
||||
|
||||
/** Returns the number of bytes needed to store a session */
|
||||
size_t olm_pickle_session_length (const(OlmSession)* 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" */
|
||||
size_t olm_pickle_account (OlmAccount* account, const(void)* 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" */
|
||||
size_t olm_pickle_session (OlmSession* session, const(void)* 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 */
|
||||
size_t olm_unpickle_account (OlmAccount* account, const(void)* 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 */
|
||||
size_t olm_unpickle_session (OlmSession* session, const(void)* key, size_t key_length, void* pickled, size_t pickled_length);
|
||||
|
||||
/** The number of random bytes needed to create an account.*/
|
||||
size_t olm_create_account_random_length (const(OlmAccount)* 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" */
|
||||
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 */
|
||||
size_t olm_account_identity_keys_length (const(OlmAccount)* 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". */
|
||||
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. */
|
||||
size_t olm_account_signature_length (const(OlmAccount)* 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" */
|
||||
size_t olm_account_sign (OlmAccount* account, const(void)* message, size_t message_length, void* signature, size_t signature_length);
|
||||
|
||||
/** The size of the output buffer needed to hold the one time keys */
|
||||
size_t olm_account_one_time_keys_length (const(OlmAccount)* 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". */
|
||||
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. */
|
||||
size_t olm_account_mark_keys_as_published (OlmAccount* account);
|
||||
|
||||
/** The largest number of one time keys this account can store. */
|
||||
size_t olm_account_max_number_of_one_time_keys (const(OlmAccount)* account);
|
||||
|
||||
/** The number of random bytes needed to generate a given number of new one
|
||||
* time keys. */
|
||||
size_t olm_account_generate_one_time_keys_random_length (const(OlmAccount)* 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". */
|
||||
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. */
|
||||
size_t olm_account_generate_fallback_key_random_length (const(OlmAccount)* 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". */
|
||||
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. */
|
||||
size_t olm_account_fallback_key_length (const(OlmAccount)* account);
|
||||
|
||||
/** Deprecated: use olm_account_unpublished_fallback_key instead */
|
||||
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. */
|
||||
size_t olm_account_unpublished_fallback_key_length (const(OlmAccount)* account);
|
||||
|
||||
/** Returns the fallback key (if present, and if unpublished) into the
|
||||
* fallback_key buffer */
|
||||
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).
|
||||
*/
|
||||
void olm_account_forget_old_fallback_key (OlmAccount* account);
|
||||
|
||||
/** The number of random bytes needed to create an outbound session */
|
||||
size_t olm_create_outbound_session_random_length (const(OlmSession)* 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". */
|
||||
size_t olm_create_outbound_session (OlmSession* session, const(OlmAccount)* account, const(void)* their_identity_key, size_t their_identity_key_length, const(void)* 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". */
|
||||
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. */
|
||||
size_t olm_create_inbound_session_from (OlmSession* session, OlmAccount* account, const(void)* 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. */
|
||||
size_t olm_session_id_length (const(OlmSession)* 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". */
|
||||
size_t olm_session_id (OlmSession* session, void* id, size_t id_length);
|
||||
|
||||
int olm_session_has_received_message (const(OlmSession)* 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.
|
||||
*/
|
||||
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". */
|
||||
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". */
|
||||
size_t olm_matches_inbound_session_from (OlmSession* session, const(void)* 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". */
|
||||
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. */
|
||||
size_t olm_encrypt_message_type (const(OlmSession)* session);
|
||||
|
||||
/** The number of random bytes needed to encrypt the next message. */
|
||||
size_t olm_encrypt_random_length (const(OlmSession)* session);
|
||||
|
||||
/** The size of the next message in bytes for the given number of plain-text
|
||||
* bytes. */
|
||||
size_t olm_encrypt_message_length (const(OlmSession)* 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". */
|
||||
size_t olm_encrypt (OlmSession* session, const(void)* 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". */
|
||||
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". */
|
||||
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. */
|
||||
size_t olm_sha256_length (const(OlmUtility)* 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". */
|
||||
size_t olm_sha256 (OlmUtility* utility, const(void)* 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". */
|
||||
size_t olm_ed25519_verify (OlmUtility* utility, const(void)* key, size_t key_length, const(void)* message, size_t message_length, void* signature, size_t signature_length);
|
||||
|
||||
/* OLM_H_ */
|
136
source/bindings/olm/outbound.d
Normal file
136
source/bindings/olm/outbound.d
Normal file
@ -0,0 +1,136 @@
|
||||
module libolm.outbound;
|
||||
|
||||
/* 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.
|
||||
*/
|
||||
|
||||
import libolm.error;
|
||||
extern (C):
|
||||
|
||||
struct OlmOutboundGroupSession;
|
||||
|
||||
/** get the size of an outbound group session, in bytes. */
|
||||
size_t olm_outbound_group_session_size ();
|
||||
|
||||
/**
|
||||
* Initialise an outbound group session object using the supplied memory
|
||||
* The supplied memory should be at least olm_outbound_group_session_size()
|
||||
* bytes.
|
||||
*/
|
||||
OlmOutboundGroupSession* olm_outbound_group_session (void* memory);
|
||||
|
||||
/**
|
||||
* A null terminated string describing the most recent error to happen to a
|
||||
* group session */
|
||||
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 */
|
||||
OlmErrorCode olm_outbound_group_session_last_error_code (const(OlmOutboundGroupSession)* session);
|
||||
|
||||
/** Clears the memory used to back this group session */
|
||||
size_t olm_clear_outbound_group_session (OlmOutboundGroupSession* session);
|
||||
|
||||
/** Returns the number of bytes needed to store an outbound group session */
|
||||
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"
|
||||
*/
|
||||
size_t olm_pickle_outbound_group_session (OlmOutboundGroupSession* session, const(void)* 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
|
||||
*/
|
||||
size_t olm_unpickle_outbound_group_session (OlmOutboundGroupSession* session, const(void)* key, size_t key_length, void* pickled, size_t pickled_length);
|
||||
|
||||
/** The number of random bytes needed to create an outbound group session */
|
||||
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.
|
||||
*/
|
||||
size_t olm_init_outbound_group_session (OlmOutboundGroupSession* session, ubyte* random, size_t random_length);
|
||||
|
||||
/**
|
||||
* The number of bytes that will be created by encrypting a message
|
||||
*/
|
||||
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.
|
||||
*/
|
||||
size_t olm_group_encrypt (OlmOutboundGroupSession* session, const(ubyte)* plaintext, size_t plaintext_length, ubyte* message, size_t message_length);
|
||||
|
||||
/**
|
||||
* Get the number of bytes returned by olm_outbound_group_session_id()
|
||||
*/
|
||||
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.
|
||||
*/
|
||||
size_t olm_outbound_group_session_id (OlmOutboundGroupSession* session, ubyte* 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.
|
||||
*/
|
||||
uint olm_outbound_group_session_message_index (OlmOutboundGroupSession* session);
|
||||
|
||||
/**
|
||||
* Get the number of bytes returned by olm_outbound_group_session_key()
|
||||
*/
|
||||
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.
|
||||
*/
|
||||
size_t olm_outbound_group_session_key (OlmOutboundGroupSession* session, ubyte* key, size_t key_length);
|
||||
|
||||
// extern "C"
|
||||
|
||||
/* OLM_OUTBOUND_GROUP_SESSION_H_ */
|
37
source/bindings/olm/package.d
Normal file
37
source/bindings/olm/package.d
Normal file
@ -0,0 +1,37 @@
|
||||
module bindings.olm;
|
||||
|
||||
// import api: Encrypted;
|
||||
// void decrypt(Encrypted* evt) @nogc {
|
||||
// import main: session;
|
||||
// import libolm.inbound;
|
||||
// import core.stdc.stdlib;
|
||||
// import core.stdc.string: strcpy;
|
||||
// // import std.stdio;
|
||||
|
||||
// char[] buf = cast(char[])malloc(evt.ciphertext.length)[0..evt.ciphertext.length];
|
||||
// strcpy(cast(char*)buf, cast(char*)evt.ciphertext);
|
||||
|
||||
// size_t mlen = olm_group_decrypt_max_plaintext_length (
|
||||
// session,
|
||||
// cast(ubyte*)buf,
|
||||
// buf.length
|
||||
// );
|
||||
|
||||
// char[] decbuf = cast(char[])malloc(mlen)[0..mlen];
|
||||
|
||||
// size_t dcr = olm_group_decrypt (
|
||||
// session,
|
||||
// cast(ubyte*)buf,
|
||||
// buf.length,
|
||||
// cast(ubyte*)decbuf,
|
||||
// mlen,
|
||||
// null
|
||||
// );
|
||||
|
||||
// import core.stdc.stdio;
|
||||
// printf("%d\n", dcr);
|
||||
|
||||
// // // string msg = cast(string)decbuf[0..dcr];
|
||||
// // writeln(dcr);
|
||||
// // writeln(msg);
|
||||
// }
|
203
source/bindings/olm/pk.d
Normal file
203
source/bindings/olm/pk.d
Normal file
@ -0,0 +1,203 @@
|
||||
/* 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.
|
||||
*/
|
||||
|
||||
import libolm.error;
|
||||
extern (C):
|
||||
|
||||
struct OlmPkEncryption;
|
||||
|
||||
/* The size of an encryption object in bytes */
|
||||
size_t olm_pk_encryption_size ();
|
||||
|
||||
/** Initialise an encryption object using the supplied memory
|
||||
* The supplied memory must be at least olm_pk_encryption_size() bytes */
|
||||
OlmPkEncryption* olm_pk_encryption (void* memory);
|
||||
|
||||
/** A null terminated string describing the most recent error to happen to an
|
||||
* encryption object */
|
||||
const(char)* olm_pk_encryption_last_error (const(OlmPkEncryption)* encryption);
|
||||
|
||||
/** An error code describing the most recent error to happen to an encryption
|
||||
* object */
|
||||
OlmErrorCode olm_pk_encryption_last_error_code (const(OlmPkEncryption)* encryption);
|
||||
|
||||
/** Clears the memory used to back this encryption object */
|
||||
size_t olm_clear_pk_encryption (OlmPkEncryption* encryption);
|
||||
|
||||
/** Set the recipient's public key for encrypting to */
|
||||
size_t olm_pk_encryption_set_recipient_key (OlmPkEncryption* encryption, const(void)* public_key, size_t public_key_length);
|
||||
|
||||
/** Get the length of the ciphertext that will correspond to a plaintext of the
|
||||
* given length. */
|
||||
size_t olm_pk_ciphertext_length (const(OlmPkEncryption)* encryption, size_t plaintext_length);
|
||||
|
||||
/** Get the length of the message authentication code. */
|
||||
size_t olm_pk_mac_length (const(OlmPkEncryption)* encryption);
|
||||
|
||||
/** Get the length of a public or ephemeral key */
|
||||
size_t olm_pk_key_length ();
|
||||
|
||||
/** The number of random bytes needed to encrypt a message. */
|
||||
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". */
|
||||
size_t olm_pk_encrypt (OlmPkEncryption* encryption, const(void)* 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);
|
||||
|
||||
struct OlmPkDecryption;
|
||||
|
||||
/* The size of a decryption object in bytes */
|
||||
size_t olm_pk_decryption_size ();
|
||||
|
||||
/** Initialise a decryption object using the supplied memory
|
||||
* The supplied memory must be at least olm_pk_decryption_size() bytes */
|
||||
OlmPkDecryption* olm_pk_decryption (void* memory);
|
||||
|
||||
/** A null terminated string describing the most recent error to happen to a
|
||||
* decription object */
|
||||
const(char)* olm_pk_decryption_last_error (const(OlmPkDecryption)* decryption);
|
||||
|
||||
/** An error code describing the most recent error to happen to a decription
|
||||
* object */
|
||||
OlmErrorCode olm_pk_decryption_last_error_code (const(OlmPkDecryption)* decryption);
|
||||
|
||||
/** Clears the memory used to back this decryption object */
|
||||
size_t olm_clear_pk_decryption (OlmPkDecryption* decryption);
|
||||
|
||||
/** Get the number of bytes required to store an olm private key
|
||||
*/
|
||||
size_t olm_pk_private_key_length ();
|
||||
|
||||
/** DEPRECATED: Use olm_pk_private_key_length()
|
||||
*/
|
||||
size_t olm_pk_generate_key_random_length ();
|
||||
|
||||
/** 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
|
||||
*/
|
||||
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
|
||||
*/
|
||||
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. */
|
||||
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" */
|
||||
size_t olm_pickle_pk_decryption (OlmPkDecryption* decryption, const(void)* 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 */
|
||||
size_t olm_unpickle_pk_decryption (OlmPkDecryption* decryption, const(void)* 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. */
|
||||
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". */
|
||||
size_t olm_pk_decrypt (OlmPkDecryption* decryption, const(void)* ephemeral_key, size_t ephemeral_key_length, const(void)* 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.
|
||||
*/
|
||||
size_t olm_pk_get_private_key (OlmPkDecryption* decryption, void* private_key, size_t private_key_length);
|
||||
|
||||
struct OlmPkSigning;
|
||||
|
||||
/* The size of a signing object in bytes */
|
||||
size_t olm_pk_signing_size ();
|
||||
|
||||
/** Initialise a signing object using the supplied memory
|
||||
* The supplied memory must be at least olm_pk_signing_size() bytes */
|
||||
OlmPkSigning* olm_pk_signing (void* memory);
|
||||
|
||||
/** A null terminated string describing the most recent error to happen to a
|
||||
* signing object */
|
||||
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 */
|
||||
OlmErrorCode olm_pk_signing_last_error_code (const(OlmPkSigning)* sign);
|
||||
|
||||
/** Clears the memory used to back this signing object */
|
||||
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".
|
||||
*/
|
||||
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.
|
||||
*/
|
||||
size_t olm_pk_signing_seed_length ();
|
||||
|
||||
/**
|
||||
* The size of the public key of a signing object.
|
||||
*/
|
||||
size_t olm_pk_signing_public_key_length ();
|
||||
|
||||
/**
|
||||
* The size of a signature created by a signing object.
|
||||
*/
|
||||
size_t olm_pk_signature_length ();
|
||||
|
||||
/**
|
||||
* 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".
|
||||
*/
|
||||
size_t olm_pk_sign (OlmPkSigning* sign, const(ubyte)* message, size_t message_length, ubyte* signature, size_t signature_length);
|
||||
|
||||
/* OLM_PK_H_ */
|
142
source/bindings/olm/sas.d
Normal file
142
source/bindings/olm/sas.d
Normal file
@ -0,0 +1,142 @@
|
||||
/* 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.
|
||||
*/
|
||||
|
||||
import libolm.error;
|
||||
extern (C):
|
||||
|
||||
/** @defgroup SAS Short Authentication String verification
|
||||
* These functions are used for verifying keys using the Short Authentication
|
||||
* String (SAS) method.
|
||||
* @{
|
||||
*/
|
||||
|
||||
struct OlmSAS;
|
||||
|
||||
/** A null terminated string describing the most recent error to happen to an
|
||||
* SAS object. */
|
||||
const(char)* olm_sas_last_error (const(OlmSAS)* sas);
|
||||
|
||||
/** An error code describing the most recent error to happen to an SAS
|
||||
* object. */
|
||||
OlmErrorCode olm_sas_last_error_code (const(OlmSAS)* sas);
|
||||
|
||||
/** The size of an SAS object in bytes. */
|
||||
size_t olm_sas_size ();
|
||||
|
||||
/** Initialize an SAS object using the supplied memory.
|
||||
* The supplied memory must be at least `olm_sas_size()` bytes. */
|
||||
OlmSAS* olm_sas (void* memory);
|
||||
|
||||
/** Clears the memory used to back an SAS object. */
|
||||
size_t olm_clear_sas (OlmSAS* sas);
|
||||
|
||||
/** The number of random bytes needed to create an SAS object. */
|
||||
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`.
|
||||
*/
|
||||
size_t olm_create_sas (OlmSAS* sas, void* random, size_t random_length);
|
||||
|
||||
/** The size of a public key in bytes. */
|
||||
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`.
|
||||
*/
|
||||
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`.
|
||||
*/
|
||||
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.
|
||||
*
|
||||
*/
|
||||
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`.
|
||||
*/
|
||||
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()`. */
|
||||
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`.
|
||||
*/
|
||||
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.
|
||||
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
|
||||
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
|
||||
|
||||
// extern "C"
|
||||
|
||||
/* OLM_SAS_H_ */
|
@ -1,40 +0,0 @@
|
||||
module commands;
|
||||
import util;
|
||||
|
||||
// UDA
|
||||
struct Command {
|
||||
string description = "No description provided";
|
||||
string name;
|
||||
}
|
||||
|
||||
@Command("Отображает аватар пользователя")
|
||||
auto avatar(Arguments argz, EventWithoutRoomID* evt) {
|
||||
import std.net.curl: get;
|
||||
string url = cast(string)get(homeserver~"/_matrix/client/v3/profile/" ~
|
||||
((argz.parsed.length == 0) ? evt.sender : argz.parsed[0]) ~ "/avatar_url");
|
||||
if (url == "{}") return MSG("User has no avatar");
|
||||
return MSG(evt.sender, `<img src="`~url[15..$-2]~`">`);
|
||||
}
|
||||
|
||||
@Command("", "пинг")
|
||||
auto ping(Arguments, EventWithoutRoomID* evt) {
|
||||
import std.datetime: Clock, SysTime, unixTimeToStdTime;
|
||||
auto delay = (Clock.currTime() - SysTime(unixTimeToStdTime(0))).total!"msecs" - evt.origin_server_ts;
|
||||
return MSG("PONG [" ~ intToStr(delay) ~ " ms]");
|
||||
}
|
||||
|
||||
@Command("хз мне лень делать описание")
|
||||
auto echo(Arguments argz, EventWithoutRoomID* evt) {
|
||||
return MSG((argz.raw.length > 6) ? argz.raw[6..$] : "Too small MSG");
|
||||
}
|
||||
|
||||
@Command()
|
||||
string[2] huy = [":orehussmile:",
|
||||
`<img data-mx-emoticon height="32" alt=":orehussmile:" title=":orehussmile:"
|
||||
src="mxc://4d2.org/XvWYAuhASYRHtYvtspsrWvtU" >`];
|
||||
|
||||
@Command("Версия бота", "версия")
|
||||
string ver = "SkunkyBot Pre-Alpha 0.1 :: https://git.macaw.me/skunky/skunkybot-d";
|
||||
|
||||
@Command("test")
|
||||
static string compver = "Compiler version: "~intToStr(__VERSION__);
|
105
source/commands/apod.d
Normal file
105
source/commands/apod.d
Normal file
@ -0,0 +1,105 @@
|
||||
module commands.apod;
|
||||
|
||||
import util, api, api_data;
|
||||
import commands.util;
|
||||
import main: db;
|
||||
|
||||
struct APOD {
|
||||
string url;
|
||||
string hdurl;
|
||||
string title;
|
||||
string explanation;
|
||||
}
|
||||
|
||||
struct APOD_internal {
|
||||
string subscribed_room;
|
||||
string mxc, title, body, mimetype;
|
||||
int untill, size, width, height;
|
||||
}
|
||||
|
||||
auto apod_get() {
|
||||
import asdf, api: upload;
|
||||
import gamut: Image;
|
||||
|
||||
MSG msg;
|
||||
Image img;
|
||||
auto data = mkrqst("https://api.nasa.gov/planetary/apod?api_key=DEMO_KEY", null, null, true)
|
||||
.body.deserialize!APOD;
|
||||
auto image = mkrqst(data.hdurl, null, null, true);
|
||||
|
||||
img.loadFromMemory(image.body);
|
||||
msg.info.w = img.width;
|
||||
msg.info.h = img.height;
|
||||
msg.info.size = image.body.length;
|
||||
msg.info.mimetype = image.getHeader("Content-Type");
|
||||
|
||||
msg.url = upload(image.body);
|
||||
msg.msgtype = "m.image";
|
||||
msg.filename = data.hdurl;
|
||||
msg.body = data.title;
|
||||
msg.formatted_body = "<details><summary><b>"~data.title~"</b></summary><p>"~data.explanation~"</p></details>";
|
||||
return msg;
|
||||
}
|
||||
|
||||
// 🇮🇳🇮🇳🇮🇳 यह बकवास का एक बुरा टुकड़ा है, लेकिन मैं इसे ठीक करने के लिए बहुत आलसी हूं ।
|
||||
MSG cached_apod() {
|
||||
import core.stdc.time: time;
|
||||
|
||||
auto now = time(null);
|
||||
auto q = db.query("select * from apod where subscribed_room = 'CACHE'");
|
||||
|
||||
if (q.step) {
|
||||
APOD_internal data = q.get!APOD_internal;
|
||||
if (data.untill > now) {
|
||||
MSG msg = MSG(data.title, data.body);
|
||||
msg.url = data.mxc;
|
||||
msg.info.w = data.width;
|
||||
msg.info.h = data.height;
|
||||
msg.info.size = data.size;
|
||||
msg.info.mimetype = data.mimetype;
|
||||
msg.filename = data.title ~ ".jpg";
|
||||
msg.msgtype = "m.image";
|
||||
return msg;
|
||||
}
|
||||
}
|
||||
|
||||
MSG msg = apod_get;
|
||||
db.exec("insert into apod
|
||||
(subscribed_room, width, height, size, mxc, mimetype, title, body, untill)
|
||||
values ('CACHE',?,?,?,?,?,?,?,?)
|
||||
on conflict (mxc) do update set
|
||||
mxc = excluded.mxc,
|
||||
body = excluded.body,
|
||||
size = excluded.size,
|
||||
title = excluded.title,
|
||||
width = excluded.width,
|
||||
height = excluded.height,
|
||||
mimetype = excluded.mimetype",
|
||||
msg.info.w, msg.info.h, msg.info.size, msg.url, msg.info.mimetype,
|
||||
msg.body, msg.formatted_body, now + Time.day);
|
||||
|
||||
return msg;
|
||||
}
|
||||
|
||||
@Command("Astronomy Picture Of the Day")
|
||||
auto apod(Arguments arg, EventWithoutRoomID* evt) {
|
||||
if (arg.parsed.length == 0) return cached_apod;
|
||||
|
||||
auto powerlevel = getUsrPL(evt.room, evt.sender);
|
||||
bool subscribed = db.query("select * from apod where subscribed_room = ?", evt.room).step;
|
||||
|
||||
if (powerlevel < 50) return MSG("Unauthorized");
|
||||
if (arg.parsed[0] == "subscribe") {
|
||||
if (subscribed)
|
||||
return MSG("Room is already subscribed to APOD.");
|
||||
db.exec("insert into apod (subscribed_room) values (?)", evt.room);
|
||||
return MSG("Room has been subcribed to APOD!");
|
||||
} else if (arg.parsed[0] == "unsubscribe") {
|
||||
if (subscribed) {
|
||||
db.exec("delete from apod where subscribed_room = ?", evt.room);
|
||||
return MSG("Room has been unsubscribed from APOD.");
|
||||
} else return MSG("Room is not subscribed to APOD.");
|
||||
}
|
||||
|
||||
return MSG("Unknown argument");
|
||||
}
|
51
source/commands/misc.d
Normal file
51
source/commands/misc.d
Normal file
@ -0,0 +1,51 @@
|
||||
module commands.misc;
|
||||
|
||||
import util, api_data;
|
||||
import commands.util;
|
||||
|
||||
@Command("хз", "хуй")
|
||||
string[2] huy = [":orehussmile:",
|
||||
`<img data-mx-emoticon height="32" alt=":orehussmile:" title=":orehussmile:"
|
||||
src="mxc://4d2.org/XvWYAuhASYRHtYvtspsrWvtU" >`];
|
||||
|
||||
@Command("Версия бота", "версия")
|
||||
string ver = "Neptune Alpha 1.0 :: https://git.macaw.me/skunky/neptune";
|
||||
|
||||
@Command("компвер")
|
||||
static string compver = "Compiler version: "~intToStr(__VERSION__);
|
||||
|
||||
|
||||
@Command("Измеряет пинг")
|
||||
auto ping(Arguments, EventWithoutRoomID* evt) {
|
||||
static enum Time: int {
|
||||
millisecond = 1,
|
||||
second = 1000,
|
||||
minute = 60 * second,
|
||||
hour = 60 * minute,
|
||||
day = 24 * hour,
|
||||
week = 7 * day,
|
||||
month = 4 * week,
|
||||
year = 12 * month
|
||||
}
|
||||
|
||||
import std.datetime: Clock, SysTime, unixTimeToStdTime;
|
||||
auto delay = (Clock.currTime() - SysTime(unixTimeToStdTime(0))).total!"msecs" - evt.origin_server_ts;
|
||||
|
||||
static foreach_reverse(unit; __traits(allMembers,Time))
|
||||
if (delay >= __traits(getMember, Time, unit)) // реализовать функцию floatToStr
|
||||
return MSG("PONG [" ~ intToStr(delay / __traits(getMember, Time, unit)) ~ ' ' ~ unit ~ "s]");
|
||||
return MSG("шота пошло не так");
|
||||
}
|
||||
|
||||
@Command("хз мне лень делать описание")
|
||||
auto echo(Arguments argz, EventWithoutRoomID* evt) {
|
||||
return MSG((argz.raw.length > 6) ? argz.raw[6..$] : "Too small MSG");
|
||||
}
|
||||
|
||||
// @Command("Отображает аватар пользователя")
|
||||
// auto avatar(Arguments argz, EventWithoutRoomID* evt) {
|
||||
// string url = cast (string) mkrqst(homeserver~"/_matrix/client/v3/profile/" ~
|
||||
// ((argz.parsed.length == 0) ? evt.sender : argz.parsed[0]) ~ "/avatar_url").body;
|
||||
// if (url == "{}") return MSG("User has no avatar");
|
||||
// return MSG(evt.sender, `<img src="`~url[15..$-2]~`">`);
|
||||
// }
|
128
source/commands/moderation.d
Normal file
128
source/commands/moderation.d
Normal file
@ -0,0 +1,128 @@
|
||||
module commands.moderation;
|
||||
|
||||
import util, api_data, api;
|
||||
import asdf;
|
||||
import core.stdc.time: time;
|
||||
import commands.util;
|
||||
|
||||
import main: db;
|
||||
|
||||
enum TimeErr: int {
|
||||
@("Not enough arguments") NotEnoughArguments = -1,
|
||||
@("Invalid date") InvalidDate = -2,
|
||||
@("Invalid unit") InvalidUnit = -3
|
||||
}
|
||||
|
||||
int parseTime(string str) @nogc pure {
|
||||
if (str.length < 2) return TimeErr.NotEnoughArguments;
|
||||
foreach (short c; str[0..$-1])
|
||||
if (!(c >= 48 && c <= 57))
|
||||
return TimeErr.InvalidDate;
|
||||
|
||||
static foreach(unit; __traits(allMembers, Time))
|
||||
if (str[$-1] == __traits(getAttributes, __traits(getMember, Time, unit))[0])
|
||||
return strToInt(str[0..$-1]) * __traits(getMember, Time, unit);
|
||||
|
||||
return TimeErr.InvalidUnit;
|
||||
}
|
||||
|
||||
@Command("Admin tools")
|
||||
MSG nctl(Arguments arg, EventWithoutRoomID* evt) {
|
||||
if (arg.parsed.length != 2) return MSG("❌️ Not enough arguments");
|
||||
if (getUsrPL(evt.room, evt.sender) < 50) return MSG("❌️ Unauthorized");
|
||||
db.exec("create table if not exists nctl (room string, user string, nc string, type string, unt integer)");
|
||||
|
||||
bool wd, err;
|
||||
string cntnt, type;
|
||||
|
||||
int dur;
|
||||
auto durStr = arg.getArg("D");
|
||||
if (durStr) dur = parseTime(durStr);
|
||||
|
||||
if (dur < 0) {
|
||||
static foreach(Terr; __traits(allMembers, TimeErr)) {
|
||||
if (dur == __traits(getMember, TimeErr, Terr)) {
|
||||
return MSG("💥 " ~ __traits(getAttributes, __traits(getMember, TimeErr, Terr))[0]);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void mrq(string ep) {
|
||||
short rq = mkhsrq(
|
||||
"/_matrix/client/v3/rooms/"~evt.room~'/'~ep,
|
||||
"POST",
|
||||
Moderate(arg.parsed[1], "Moderated by "~evt.sender).serializeToJson
|
||||
).status;
|
||||
if (rq != 200) err = true;
|
||||
}
|
||||
|
||||
void setpl(short pl) {
|
||||
auto pls = State.PowerLevels(getUsrsPLs(evt.room));
|
||||
if (dur) cntnt = pls.serializeToJson;
|
||||
pls.users[arg.parsed[1]] = pl;
|
||||
state(evt.room, "m.room.power_levels", pls);
|
||||
}
|
||||
|
||||
bool c() {
|
||||
if (db.query("select type from nctl where room = ? and user = ?",evt.room, arg.parsed[1]).step)
|
||||
return true;
|
||||
return false;
|
||||
}
|
||||
|
||||
switch (arg.parsed[0]) {
|
||||
case "ban":
|
||||
wd = true;
|
||||
mrq("ban");
|
||||
break;
|
||||
case "kick", "unban":
|
||||
mrq(arg.parsed[0]);
|
||||
break;
|
||||
case "mute":
|
||||
if(c) goto e;
|
||||
type = "m.room.power_levels";
|
||||
wd = true;
|
||||
setpl(-100);
|
||||
break;
|
||||
case "unmute": setpl(0); break;
|
||||
case "acl", "delete-acl":
|
||||
State.ACL acls = getState!(State.ACL)(evt.room, "m.room.server_acl");
|
||||
if (dur) cntnt = acls.serializeToJson;
|
||||
|
||||
if (arg.parsed[0] == "acl") {
|
||||
if(c) goto e;
|
||||
type = "m.room.server_acl";
|
||||
wd = true;
|
||||
acls.deny ~= arg.parsed[1];
|
||||
} else {
|
||||
foreach (n, srv; acls.deny) {
|
||||
if (srv == arg.parsed[1])
|
||||
acls.deny = acls.deny[0..n] ~ acls.deny[n+1..$];
|
||||
}
|
||||
}
|
||||
|
||||
state(evt.room, "m.room.server_acl", acls);
|
||||
break;
|
||||
default: return MSG("❓️ Invalid argument");
|
||||
}
|
||||
|
||||
if (err) return MSG("💥 Something went wrong");
|
||||
|
||||
if (dur && wd) {
|
||||
import std.datetime.systime: SysTime;
|
||||
auto untill = time(null) + dur;
|
||||
|
||||
db.exec(
|
||||
"insert into nctl (room, user, nc, type, unt) values (?,?,?,?,?)",
|
||||
evt.room,
|
||||
arg.parsed[1],
|
||||
cntnt,
|
||||
type,
|
||||
untill
|
||||
);
|
||||
|
||||
return MSG("✅️ Blocked untill " ~ SysTime.fromUnixTime(untill).toSimpleString);
|
||||
}
|
||||
|
||||
return MSG("✅️");
|
||||
e: return MSG("💥 Already moderated!");
|
||||
}
|
54
source/commands/mozhi.d
Normal file
54
source/commands/mozhi.d
Normal file
@ -0,0 +1,54 @@
|
||||
module commands.mozhi;
|
||||
|
||||
// import api;
|
||||
// import util;
|
||||
// import commands.util;
|
||||
// import api_data;
|
||||
|
||||
// import asdf;
|
||||
|
||||
// @Command("Translates text via Mozhi")
|
||||
// auto tr(Arguments argz, EventWithoutRoomID* evt) {
|
||||
// struct RqRsp {
|
||||
// string engine;
|
||||
// string detected;
|
||||
// @serdeKeys("translated-text") string translatedText;
|
||||
// string source_language;
|
||||
// string target_language;
|
||||
// }
|
||||
|
||||
// MSG msg;
|
||||
// string text;
|
||||
// auto ngn = argz.getArg("E");
|
||||
// auto instance = argz.getArg("I");
|
||||
// MSG origin = evt.content.raw.deserialize!MSG;
|
||||
|
||||
// if (argz.parsed.length == 2) {
|
||||
// auto reply = event(origin.relates.reply.event_id, evt.room).body;
|
||||
// foreach (chr; reply) {
|
||||
// if (chr == ' ') text ~= '+';
|
||||
// else text ~= chr;
|
||||
// }
|
||||
// } else for (short i = 2; i < argz.parsed.length; ++i)
|
||||
// text ~= argz.parsed[i] ~ '+';
|
||||
|
||||
// auto rq = mkrqst (
|
||||
// "https://" ~ (instance ? instance : "mozhi.gitro.xyz") ~ "/api/translate", "POST",
|
||||
// "engine=" ~ (ngn ? ngn : "google")
|
||||
// ~ "&from=" ~ argz.parsed[0]
|
||||
// ~ "&to=" ~ argz.parsed[1]
|
||||
// ~ "&text=" ~ text,
|
||||
// false
|
||||
// );
|
||||
|
||||
// if (rq.status != 200) return MSG(intToStr(rq.status));
|
||||
// auto content = rq.body.deserialize!RqRsp;
|
||||
|
||||
// msg = MSG("ЙАЗЫКНЙЭВЫ|БРАН", content.translatedText);
|
||||
// return msg;
|
||||
// }
|
||||
|
||||
// @Command("Creates audio with text, using Mozhi")
|
||||
// auto tts(Arguments argz, EventWithoutRoomID* evt) {
|
||||
|
||||
// }
|
81
source/commands/slaves.d
Normal file
81
source/commands/slaves.d
Normal file
@ -0,0 +1,81 @@
|
||||
module commands.slaves;
|
||||
|
||||
enum Parallel;
|
||||
|
||||
import util;
|
||||
import api;
|
||||
import api_data;
|
||||
import main: db;
|
||||
|
||||
void apod_slave() @Parallel {
|
||||
import core.thread;
|
||||
import commands.apod;
|
||||
import core.stdc.time: time;
|
||||
|
||||
db.exec("create table if not exists apod (
|
||||
subscribed_room string,
|
||||
mxc string unique,
|
||||
body string,
|
||||
title string,
|
||||
mimetype string,
|
||||
size integer,
|
||||
width integer,
|
||||
height integer,
|
||||
untill integer
|
||||
)");
|
||||
|
||||
for (;;) {
|
||||
int v;
|
||||
auto q = db.query("select untill from apod where subscribed_room = 'CACHE'");
|
||||
if (q.step) v = q.get!int;
|
||||
for (q = db.query("select subscribed_room from apod where subscribed_room != 'CACHE'"); q.step;) {
|
||||
if (v == 0 || v < time(null)) {
|
||||
send(cached_apod, q.get!string);
|
||||
db.exec("delete from apod where subscribed_room = 'CACHE'");
|
||||
}
|
||||
}
|
||||
Thread.sleep(30.seconds);
|
||||
}
|
||||
}
|
||||
|
||||
void nctl_slave() @Parallel {
|
||||
import core.thread: Thread;
|
||||
import core.time: Duration, dur;
|
||||
import core.stdc.time: time;
|
||||
|
||||
import asdf: serializeToJson;
|
||||
|
||||
static Duration tms = dur!"msecs"(10);
|
||||
|
||||
struct udr {
|
||||
string room;
|
||||
string user;
|
||||
string type;
|
||||
string nc;
|
||||
int unt;
|
||||
}
|
||||
|
||||
for (;;) {
|
||||
auto q = db.query("select * from nctl");
|
||||
while (q.step) {
|
||||
try {
|
||||
udr z = q.get!udr;
|
||||
if (time(null) >= z.unt) {
|
||||
if (z.type == null) {
|
||||
mkhsrq(
|
||||
"/_matrix/client/v3/rooms/"~z.room~"/unban",
|
||||
"POST",
|
||||
Moderate(z.user, "Its time to unban!").serializeToJson
|
||||
);
|
||||
}
|
||||
else rawState(z.room, z.type, z.nc);
|
||||
db.exec("delete from nctl where user = ? and room = ?", z.user, z.room);
|
||||
}
|
||||
} catch (Exception e) {
|
||||
import core.stdc.stdio;
|
||||
printf("[nctl_slave] ERROR: %s\n", cast(char*)e.msg);
|
||||
}
|
||||
}
|
||||
Thread.sleep(tms);
|
||||
}
|
||||
}
|
92
source/commands/util.d
Normal file
92
source/commands/util.d
Normal file
@ -0,0 +1,92 @@
|
||||
module commands.util;
|
||||
|
||||
struct Command {
|
||||
string description = "No description provided";
|
||||
string name;
|
||||
}
|
||||
|
||||
static enum Time: int {
|
||||
@('s') second = 1,
|
||||
@('m') minute = 60 * second,
|
||||
@('h') hour = 60 * minute,
|
||||
@('d') day = 24 * hour,
|
||||
@('w') week = 7 * day,
|
||||
@('M') month = 30 * day,
|
||||
@('y') year = 12 * month
|
||||
}
|
||||
|
||||
struct Arguments {
|
||||
string raw;
|
||||
string command;
|
||||
string[] parsed;
|
||||
char[] options;
|
||||
string getArg(string arg) @nogc {
|
||||
int prev, splt;
|
||||
for (int i; i < options.length; ++i) {
|
||||
if (options[i] == '\0') splt = i;
|
||||
else if (options[i] == '\1') {
|
||||
if (arg == options[prev..splt])
|
||||
return cast(string)options[splt+1..i];
|
||||
prev = i + 1;
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
auto parseMsg(string cmd) {
|
||||
import std.stdio;
|
||||
Arguments argz = Arguments(cmd);
|
||||
if (argz.raw[0] == '#') {
|
||||
string buf;
|
||||
for (ulong i = 1; i < argz.raw.length; ++i)
|
||||
if (argz.raw[i] != ' ' && argz.raw[i] != '=') {
|
||||
buf ~= argz.raw[i];
|
||||
if (i+1 == argz.raw.length || (argz.raw[i+1] == ' ' || argz.raw[i+1] == '=')) {
|
||||
argz.parsed ~= buf;
|
||||
buf = null;
|
||||
}
|
||||
}
|
||||
argz.command = argz.parsed[0]; argz.parsed = argz.parsed[1..$];
|
||||
|
||||
for (ulong i; i < argz.parsed.length; ++i)
|
||||
if (argz.parsed[i][0] == '-') {
|
||||
string key = argz.parsed[i];
|
||||
auto val = (i+1 < argz.parsed.length && argz.parsed[i+1][0] != '-')
|
||||
? argz.parsed[i+1] : null;
|
||||
if (key[1] == '-')
|
||||
argz.options ~= key[2..$] ~ '\0' ~ val ~ '\1';
|
||||
else for (ulong x = 1; x < key.length; ++x)
|
||||
argz.options ~= key[x..x+1] ~ '\0' ~ val ~ '\1';
|
||||
|
||||
auto x = (val) ? i + 2 : i + 1;
|
||||
argz.parsed = argz.parsed[0..i] ~ argz.parsed[x..$];
|
||||
i = i - (x - i);
|
||||
}
|
||||
}
|
||||
return argz;
|
||||
}
|
||||
|
||||
int getUsrPL(string room, string user) {
|
||||
import main: db;
|
||||
auto q = db.query("select pl from room_pls where room = ? and user = ?", room, user);
|
||||
if (q.step) return q.get!int;
|
||||
return 0;
|
||||
}
|
||||
|
||||
short[string] getUsrsPLs(string room) {
|
||||
struct hz {
|
||||
string user;
|
||||
short pl;
|
||||
}
|
||||
|
||||
import main: db;
|
||||
short[string] buf;
|
||||
auto q = db.query("select user, pl from room_pls where room = ?", room);
|
||||
while (q.step) {
|
||||
auto x = q.get!hz;
|
||||
buf[x.user] = x.pl;
|
||||
}
|
||||
|
||||
return buf;
|
||||
}
|
114
source/listener.d
Normal file
114
source/listener.d
Normal file
@ -0,0 +1,114 @@
|
||||
module listener;
|
||||
|
||||
import api, api_data;
|
||||
import commands.util;
|
||||
import main: db;
|
||||
import util;
|
||||
|
||||
import std.stdio: writeln;
|
||||
import core.thread;
|
||||
|
||||
import asdf: deserialize;
|
||||
|
||||
__gshared string syncUrl, initialBatch;
|
||||
|
||||
void listen(Modules...)() {
|
||||
static MSG helpgen() {
|
||||
MSG msg;
|
||||
static foreach (mod; Modules) {
|
||||
static foreach (member; __traits(allMembers, mod)) {
|
||||
static foreach (attr; __traits(getAttributes, __traits(getMember, mod, member))) {
|
||||
static if (is(typeof(attr) == Command)) msg.body ~= member ~ ": " ~ attr.description ~ '\n';
|
||||
}
|
||||
}
|
||||
}
|
||||
return msg;
|
||||
}
|
||||
|
||||
auto content = Sync();
|
||||
content.next_batch = initialBatch;
|
||||
for (;;) {
|
||||
string bthUrl = syncUrl ~ content.next_batch;
|
||||
try {
|
||||
content = mkhsrq(bthUrl).body.deserialize!Sync;
|
||||
db.exec("update client set latest_batch = ?", content.next_batch);
|
||||
} catch (Exception e) { writeln(e.msg); continue; }
|
||||
|
||||
// https://github.com/trikko/serverino/blob/3e3e6273a5aaa32615ae9d007a1a83877bc23ab4/source/serverino/worker.d#L168
|
||||
new Thread(delegate {
|
||||
foreach (room, _; content.rooms.invite) {
|
||||
writeln("Joining to room: ", room);
|
||||
mkhsrq("/_matrix/client/v3/rooms/"~room~"/join", "POST", "{}");
|
||||
send(MSG("Йа криведко"), room);
|
||||
fetchMembers(room);
|
||||
}
|
||||
|
||||
foreach (room, roomContent; content.rooms.join) {
|
||||
foreach(event; roomContent.timeline.events) {
|
||||
if (event.type == "m.room.message") {
|
||||
try {
|
||||
auto evt = deserialize!MSG(event.content.raw);
|
||||
if (!evt.body.length) break;
|
||||
event.room = room;
|
||||
auto argz = parseMsg(evt.body);
|
||||
|
||||
if (argz.command == "hlp") {
|
||||
auto h = helpgen;
|
||||
h.relates.reply.event_id = event.event_id;
|
||||
send(h, room);
|
||||
break;
|
||||
}
|
||||
|
||||
static foreach (mod; Modules) {
|
||||
static foreach (member; __traits(allMembers, mod)) {
|
||||
// if (argz.command == member) {
|
||||
foreach (attr; __traits(getAttributes, __traits(getMember, mod, member))) {
|
||||
if (is(typeof(attr) == Command)
|
||||
&& (argz.command == member
|
||||
|| (argz.command == attr.name && attr.name != null)))
|
||||
{
|
||||
alias command = __traits(getMember, mod, member);
|
||||
static if (is(typeof(command) == function))
|
||||
auto content = command(argz, &event);
|
||||
else static if (__traits(isStaticArray, command))
|
||||
auto content = MSG(command[0], command[1]);
|
||||
else auto content = MSG(command);
|
||||
content.relates.reply.event_id = event.event_id;
|
||||
send(content, room);
|
||||
}
|
||||
}
|
||||
// }
|
||||
}
|
||||
}
|
||||
} catch (Exception e) {
|
||||
writeln(e.msg);
|
||||
send(MSG(e.msg), room);
|
||||
}
|
||||
}
|
||||
else if (event.type == "m.room.power_levels") {
|
||||
auto pls = deserialize!(State.PowerLevels)(event.content.raw);
|
||||
foreach (user, pl; pls.users) {
|
||||
auto q = db.query("select pl from room_pls where room = ? and user = ?", room, user);
|
||||
if (q.step) {
|
||||
if (q.get!int != pl)
|
||||
db.exec("update room_pls set pl = ? where room = ? and user = ?", pl, room, user);
|
||||
} else db.exec("insert into room_pls (room, user, pl) values (?, ?, ?)", room, user, pl);
|
||||
}
|
||||
}
|
||||
// else if (event.type == "m.room.encrypted") {
|
||||
// import encryption;
|
||||
// auto e = deserialize!Encrypted(event.content.raw);
|
||||
// decrypt(&e);
|
||||
// }
|
||||
}
|
||||
}
|
||||
}).start;
|
||||
}
|
||||
}
|
||||
|
||||
void fetchMembers(string room) {
|
||||
auto state = getState!(State.PowerLevels)(room, "m.room.power_levels");
|
||||
foreach (user, pl; state.users) {
|
||||
db.exec("insert into room_pls (room, user, pl) values (?, ?, ?)", room, user, pl);
|
||||
}
|
||||
}
|
206
source/util.d
206
source/util.d
@ -1,14 +1,37 @@
|
||||
module util;
|
||||
import asdf;
|
||||
|
||||
string homeserver;
|
||||
__gshared Config cfg;
|
||||
struct Config {
|
||||
string token, homeserver;
|
||||
string database_path;
|
||||
bool accept_invitations;
|
||||
}
|
||||
|
||||
string intToStr(T)(T num) {
|
||||
if (num == 0) return "0";
|
||||
|
||||
char[] buf;
|
||||
bool minus = num < 0;
|
||||
if (minus) num /= -1;
|
||||
for(short i; num > 0; ++i) {
|
||||
buf = (num % 10 + '0')~buf;
|
||||
num /= 10;
|
||||
} return cast(string)buf;
|
||||
}
|
||||
|
||||
return cast(string)(minus ? '-'~buf : buf);
|
||||
}
|
||||
|
||||
int strToInt(T)(T str) @nogc {
|
||||
int num;
|
||||
bool minus;
|
||||
for (short i; str.length > i; ++i) {
|
||||
if (str[i] == '-') minus = true;
|
||||
else if (str[i] >= '0' || str[i] <= '9')
|
||||
num = num * 10 + (str[i] - 48);
|
||||
else break;
|
||||
}
|
||||
return minus ? num / -1 : num;
|
||||
}
|
||||
|
||||
struct JsonObject {
|
||||
@ -20,102 +43,111 @@ struct JsonObject {
|
||||
return null;
|
||||
}
|
||||
|
||||
void serialize(S)(ref S serializer) {
|
||||
try serializer.sink.putSmallEscaped(data.parseJson.to!string);
|
||||
catch (Exception) serializer.sink.putSmallEscaped("{}");
|
||||
// void serialize(S)(ref S serializer) {
|
||||
// try serializer.sink.putSmallEscaped(data.parseJson.to!string);
|
||||
// catch (Exception) serializer.sink.putSmallEscaped("{}");
|
||||
// }
|
||||
}
|
||||
|
||||
struct RqRsp {
|
||||
short status;
|
||||
char[] body;
|
||||
char[] headers;
|
||||
string getHeader(string header) @nogc {
|
||||
int prev, splt;
|
||||
for (int i; i < headers.length; ++i) {
|
||||
if (headers[i] == '\0') splt = i;
|
||||
else if (headers[i] == '\1') {
|
||||
if (header == headers[prev..splt])
|
||||
return cast(string)headers[splt+2..i];
|
||||
prev = i + 1;
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
struct EventWithoutRoomID {
|
||||
JsonObject content;
|
||||
string event_id;
|
||||
ulong origin_server_ts;
|
||||
@serdeOptional string sender, state_key, type;
|
||||
// Unsigned unsigned;
|
||||
size_t wrt(ubyte[]* outptt, size_t size, size_t nmemb, ubyte* inptt) {
|
||||
auto len = size * nmemb;
|
||||
*outptt ~= inptt[0..len];
|
||||
return len;
|
||||
}
|
||||
|
||||
struct Sync {
|
||||
struct StrippedStateEvent {
|
||||
JsonObject content;
|
||||
string sender, state_key, type;
|
||||
// struct MM {
|
||||
// char* rsp;
|
||||
// size_t len;
|
||||
// }
|
||||
|
||||
// size_t wrt(MM* outptt, size_t size, size_t nmemb, char* inptt) @nogc {
|
||||
// import core.stdc.stdlib;
|
||||
// import core.stdc.string;
|
||||
// size_t rs = size * nmemb;
|
||||
// outptt.rsp = cast(char*)realloc(outptt.rsp, outptt.len+rs+1);
|
||||
// memcpy(&(outptt.rsp[outptt.len]), inptt, rs);
|
||||
// outptt.len += rs;
|
||||
// outptt.rsp[outptt.len] = '\0';
|
||||
// return rs;
|
||||
// }
|
||||
|
||||
size_t hddrz(ubyte[]* outptt, size_t size, size_t nmemb, ubyte* inptt) {
|
||||
auto len = size * nmemb;
|
||||
auto headers = inptt[0..len];
|
||||
int prev;
|
||||
for (int i; i < len; ++i) {
|
||||
if (headers[i] == '\r' && headers[i + 1] == '\n') {
|
||||
auto line = headers[prev..i];
|
||||
prev = i + 1;
|
||||
for (int x; x < line.length; ++x)
|
||||
if (line[x] == ':') {
|
||||
*outptt ~= line[0..x] ~ '\0' ~ line[x + 1..$] ~ '\1';
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
return len;
|
||||
}
|
||||
|
||||
struct Unsigned {
|
||||
int age;
|
||||
string membership, transaction_id;
|
||||
import bindings.curl;
|
||||
const char* UA = "Neptune/1.0 (https://code.lost-skunk.cc/neptune)";
|
||||
|
||||
// FIXME: memory corruption
|
||||
RqRsp mkrqst(string url, string method = "GET", string content = null, bool authorized = false) {
|
||||
RqRsp rsp;
|
||||
auto hndl = curl_easy_init();
|
||||
|
||||
curl_easy_setopt(hndl, CURLOPT_URL, cast(char*)url);
|
||||
curl_easy_setopt(hndl, CURLOPT_WRITEFUNCTION, &wrt);
|
||||
curl_easy_setopt(hndl, CURLOPT_WRITEDATA, &rsp.body);
|
||||
curl_easy_setopt(hndl, CURLOPT_USERAGENT, UA);
|
||||
curl_easy_setopt(hndl, CURLOPT_HEADERFUNCTION, &hddrz);
|
||||
curl_easy_setopt(hndl, CURLOPT_HEADERDATA, &rsp.headers);
|
||||
|
||||
if (method) curl_easy_setopt(hndl, CURLOPT_CUSTOMREQUEST, cast(char*)method);
|
||||
if (content) {
|
||||
curl_easy_setopt(hndl, CURLOPT_POST, 1);
|
||||
curl_easy_setopt(hndl, CURLOPT_POSTFIELDS, cast(void*)content);
|
||||
curl_easy_setopt(hndl, CURLOPT_POSTFIELDSIZE, content.length);
|
||||
}
|
||||
|
||||
struct Rooms {
|
||||
struct Invited {
|
||||
struct IS { StrippedStateEvent[] events; }
|
||||
IS invite_state;
|
||||
}
|
||||
struct Joined {
|
||||
struct Timeline {
|
||||
EventWithoutRoomID[] events;
|
||||
bool limited;
|
||||
string prev_batch;
|
||||
curl_slist* authhdr;
|
||||
if (authorized) {
|
||||
authhdr = curl_slist_append(null, cast(char*)cfg.token);
|
||||
curl_easy_setopt(hndl, CURLOPT_HTTPHEADER, authhdr);
|
||||
}
|
||||
|
||||
struct UNC {
|
||||
int highlight_count;
|
||||
int notification_count;
|
||||
int rs = curl_easy_perform(hndl);
|
||||
if (rs != 0) {
|
||||
static foreach (err; __traits(allMembers, CURLcode)) {
|
||||
if (rs == __traits(getMember, CURLcode, err))
|
||||
throw new Exception(err);
|
||||
}
|
||||
}
|
||||
curl_easy_getinfo(hndl, CURLINFO_RESPONSE_CODE, &rsp.status);
|
||||
if (authorized) curl_slist_free_all(authhdr);
|
||||
curl_easy_cleanup(hndl);
|
||||
return rsp;
|
||||
}
|
||||
|
||||
@serdeOptional Timeline timeline;
|
||||
UNC unread_notifications;
|
||||
}
|
||||
|
||||
@serdeOptional Invited[string] invite;
|
||||
@serdeOptional Joined[string] join;
|
||||
}
|
||||
|
||||
@serdeOptional Rooms rooms;
|
||||
string next_batch;
|
||||
}
|
||||
|
||||
// EVENTS
|
||||
struct MSG {
|
||||
string body;
|
||||
@serdeOptional @serdeIgnoreDefault string formatted_body;
|
||||
string msgtype = "m.notice";
|
||||
@serdeOptional string format = "org.matrix.custom.html";
|
||||
}
|
||||
|
||||
struct Arguments {
|
||||
string raw;
|
||||
string command;
|
||||
string[] parsed;
|
||||
string[string] options;
|
||||
}
|
||||
|
||||
auto parseMsg(string cmd) {
|
||||
Arguments argz = Arguments(cmd);
|
||||
if (argz.raw[0] == '#') {
|
||||
string buf;
|
||||
for (ulong i = 1; i < argz.raw.length; ++i)
|
||||
if (argz.raw[i] != ' ' && argz.raw[i] != '=') {
|
||||
buf ~= argz.raw[i];
|
||||
if (i+1 == argz.raw.length || (argz.raw[i+1] == ' ' || argz.raw[i+1] == '=')) {
|
||||
argz.parsed ~= buf;
|
||||
buf = null;
|
||||
}
|
||||
}
|
||||
argz.command = argz.parsed[0]; argz.parsed = argz.parsed[1..$];
|
||||
|
||||
for (ulong i; i < argz.parsed.length; ++i)
|
||||
if (argz.parsed[i][0] == '-') {
|
||||
string key = argz.parsed[i];
|
||||
auto val = (i+1 < argz.parsed.length && argz.parsed[i+1][0] != '-')
|
||||
? argz.parsed[i+1] : null;
|
||||
if (key[1] == '-') argz.options[key[2..$]] = val;
|
||||
else for (ulong x = 1; x < key.length; ++x)
|
||||
argz.options[key[x..x+1]] = val;
|
||||
|
||||
auto x = (val) ? i + 2 : i + 1;
|
||||
argz.parsed = argz.parsed[0..i] ~ argz.parsed[x..$];
|
||||
i = i - (x - i);
|
||||
}
|
||||
}
|
||||
return argz;
|
||||
RqRsp mkhsrq(string uri, string method = "GET", string content = null) {
|
||||
return mkrqst(cfg.homeserver ~ uri, method, content, true);
|
||||
}
|
Loading…
x
Reference in New Issue
Block a user