27 Commits

Author SHA1 Message Date
15809f3fbd Added more libraries 2023-02-16 17:03:26 -05:00
f4c947e359 Added debug logging 2023-02-16 17:03:20 -05:00
5b31fef0c7 Added matrix listeners 2023-02-16 17:03:12 -05:00
a4ff706a28 Added crypto file 2023-02-16 17:03:01 -05:00
4b6bb780d4 Created check for Matrix mode 2023-02-16 10:53:08 -05:00
e8463ecc25 Added Matrix SDK 2023-02-16 10:52:56 -05:00
2083e8279f Created initial matrix listener 2023-02-16 10:52:46 -05:00
19e011dfac Added matrix variables 2023-02-16 10:52:38 -05:00
bb96bcde61 Fixed bug deleting entire user variable
All checks were successful
continuous-integration/drone/push Build is passing
2023-02-15 16:33:57 -05:00
15416e3728 Fixed log date 2023-02-15 16:33:45 -05:00
feccbc05e6 Updated readme
All checks were successful
continuous-integration/drone/push Build is passing
2023-02-15 14:12:00 -05:00
7d16552d65 Updated .gitignore 2023-02-15 13:55:16 -05:00
268bbdf9b7 Added json field checks 2023-02-15 13:53:47 -05:00
8ab6b9d986 Added log message
All checks were successful
continuous-integration/drone/push Build is passing
2023-02-15 12:25:05 -05:00
2261e753d5 Implemented timestamp logging
All checks were successful
continuous-integration/drone/push Build is passing
2023-02-15 12:20:23 -05:00
88dd3b5908 Added better link processing and logging 2023-02-15 12:20:07 -05:00
f8f94b4afc Added better link processing 2023-02-15 12:19:40 -05:00
309d7c0cd3 Added better log messaging 2023-02-15 12:17:08 -05:00
f37beb0a5d Removed try/catch it broke
All checks were successful
continuous-integration/drone/push Build is passing
2023-02-15 10:05:30 -05:00
eec1050e17 Added datetime for logging 2023-02-15 10:05:14 -05:00
8ffd920007 Updated CMD command
All checks were successful
continuous-integration/drone/push Build is passing
2023-02-14 15:29:55 -05:00
846b7d10d8 Fixed tag to be lowercase
All checks were successful
continuous-integration/drone/push Build is passing
2023-02-14 15:17:53 -05:00
5adc9b7b9f Fixed image tag
Some checks failed
continuous-integration/drone/push Build is failing
2023-02-14 15:13:30 -05:00
3eb412bd6e Fixed missing step
Some checks failed
continuous-integration/drone/push Build is failing
2023-02-14 15:09:57 -05:00
1949c7af1b Merge branch 'main' of git.kizaing.ca:kizaing/TeleTok
Some checks reported errors
continuous-integration/drone/push Build encountered an error
continuous-integration/drone Build encountered an error
2023-02-14 15:07:27 -05:00
993a94ddb1 Updated build task 2023-02-14 15:06:39 -05:00
26dcd962b8 Merge pull request 'bugfixes/crash-handler' (#1) from bugfixes/crash-handler into main
Some checks failed
continuous-integration/drone/push Build is failing
Reviewed-on: #1
2023-02-14 11:53:45 -08:00
11 changed files with 331 additions and 37 deletions

View File

@ -4,11 +4,6 @@ type: docker
name: publish-bot name: publish-bot
steps: steps:
- name: build-dotnet
image: mcr.microsoft.com/dotnet/sdk:6.0
commands:
- dotnet publish
- name: build-image - name: build-image
image: plugins/docker image: plugins/docker
settings: settings:
@ -17,10 +12,8 @@ steps:
from_secret: DOCKER_USER from_secret: DOCKER_USER
password: password:
from_secret: DOCKER_PASS from_secret: DOCKER_PASS
repo: git.kizaing.ca/kizaing/TeleTok repo: git.kizaing.ca/kizaing/teletok
tags: latest tags: latest
platform: linux/amd64,linux/arm64
# Commented out until stuff actually works # Commented out until stuff actually works
trigger: trigger:

2
.gitignore vendored
View File

@ -1,2 +1,4 @@
bin bin
obj obj
.vscode
config.Dev.json

46
CryptographyService.cs Normal file
View File

@ -0,0 +1,46 @@
using System;
using Sodium;
namespace TeleTok
{
public class CryptographyService
{
public string ToHexString(byte[] input)
{
var hexString = BitConverter.ToString(input);
string result = hexString.Replace("-", "");
return result.ToLower();
}
public byte[] GenerateLoginDigest()
{
long now = DateTimeOffset.UtcNow.ToUnixTimeSeconds() * 1000;
var message = $"login:{now / 1000 / (5 * 60)}";
return GenericHash.Hash(message, (byte[]?) null, 32);
}
public KeyPair GenerateEd25519KeyPair(string seed)
{
byte[] hash = GenericHash.Hash(seed, (byte[]?) null, 32);
return PublicKeyAuth.GenerateKeyPair(hash);
}
public string GenerateHexSignature(byte[] loginDigest, byte[] secretKey)
{
byte[] signature = PublicKeyAuth.SignDetached(loginDigest, secretKey);
return ToHexString(signature);
}
public string GenerateHexId(byte[] publicKey)
{
byte[] hash = GenericHash.Hash(publicKey, null, publicKey.Length);
return ToHexString(hash);
}
}
}

View File

@ -1,7 +1,14 @@
FROM mcr.microsoft.com/dotnet/runtime:6.0-alpine3 #Builds the bot from source
FROM mcr.microsoft.com/dotnet/sdk:6.0 AS build-task
COPY . /build
RUN cd /build && dotnet publish
# Actually runs the bot
FROM mcr.microsoft.com/dotnet/runtime:6.0
WORKDIR /app/teletok WORKDIR /app/teletok
COPY bin/Debug/net6.0/publish/* /app/teletok/ COPY --from=build-task /build/bin/Debug/net6.0/publish/* /app/teletok/
CMD [ "TeleTok" ] CMD [ "./TeleTok" ]

114
MatrixListener.cs Normal file
View File

@ -0,0 +1,114 @@
using System;
using System.Configuration;
using Matrix.Sdk;
using Matrix.Sdk.Core.Domain.MatrixRoom;
using Matrix.Sdk.Core.Domain.RoomEvent;
using Matrix.Sdk.Core.Infrastructure.Dto.Room.Create;
using Sodium;
namespace TeleTok
{
public class MatrixListener
{
private static readonly CryptographyService CryptographyService = new();
public record LoginRequest(Uri BaseAddress, string Username, string Password, string DeviceId);
public async Task RunListener()
{
var factory = new MatrixClientFactory();
var anotherFactory = new MatrixClientFactory();
IMatrixClient client = factory.Create();
IMatrixClient anotherClient = anotherFactory.Create();
client.OnMatrixRoomEventsReceived += (sender, eventArgs) =>
{
foreach (BaseRoomEvent roomEvent in eventArgs.MatrixRoomEvents)
{
if (roomEvent is not TextMessageEvent textMessageEvent)
continue;
(string roomId, string senderUserId, string message) = textMessageEvent;
if (client.UserId != senderUserId)
TeleTok.LogMessage($"RoomId: {roomId} received message from {senderUserId}: {message}.");
}
};
anotherClient.OnMatrixRoomEventsReceived += (sender, eventArgs) =>
{
foreach (BaseRoomEvent roomEvent in eventArgs.MatrixRoomEvents)
{
if (roomEvent is not TextMessageEvent textMessageEvent)
continue;
(string roomId, string senderUserId, string message) = textMessageEvent;
if (anotherClient.UserId != senderUserId)
TeleTok.LogMessage($"RoomId: {roomId} received message from {senderUserId}: {message}.");
}
};
(Uri matrixNodeAddress, string username, string password, string deviceId) = CreateLoginRequest();
await client.LoginAsync(matrixNodeAddress, username, password, deviceId);
LoginRequest request2 = CreateLoginRequest();
await anotherClient.LoginAsync(request2.BaseAddress, request2.Username, request2.Password, request2.DeviceId);
if(client.IsLoggedIn)
{
TeleTok.LogMessage($"client.IsLoggedIn: {client.IsLoggedIn}");
TeleTok.LogMessage($"client.IsSyncing: {client.IsSyncing}");
}
client.Start();
anotherClient.Start();
CreateRoomResponse createRoomResponse = await client.CreateTrustedPrivateRoomAsync(new[]
{
anotherClient.UserId
});
await anotherClient.JoinTrustedPrivateRoomAsync(createRoomResponse.RoomId);
var spin = new SpinWait();
while(anotherClient.JoinedRooms.Length ==0)
spin.SpinOnce();
await client.SendMessageAsync(createRoomResponse.RoomId, "Hello");
await anotherClient.SendMessageAsync(anotherClient.JoinedRooms[0].Id, ", ");
await client.SendMessageAsync(createRoomResponse.RoomId, "World");
await anotherClient.SendMessageAsync(anotherClient.JoinedRooms[0].Id, "!");
TeleTok.LogMessage($"client.IsLoggedIn: {client.IsLoggedIn}");
TeleTok.LogMessage($"client.IsSyncing: {client.IsSyncing}");
Console.ReadLine();
client.Stop();
anotherClient.Stop();
Console.WriteLine($"client.IsLoggedIn: {client.IsLoggedIn}");
Console.WriteLine($"client.IsSyncing: {client.IsSyncing}");
}
private static LoginRequest CreateLoginRequest()
{
var seed = Guid.NewGuid().ToString();
KeyPair keyPair = CryptographyService.GenerateEd25519KeyPair(seed);
byte[] loginDigest = CryptographyService.GenerateLoginDigest();
string hexSignature = CryptographyService.GenerateHexSignature(loginDigest, keyPair.PrivateKey);
string publicKeyHex = CryptographyService.ToHexString(keyPair.PublicKey);
string hexId = CryptographyService.GenerateHexId(keyPair.PublicKey);
var password = $"ed:{hexSignature}:{publicKeyHex}";
string deviceId = publicKeyHex;
LoginRequest loginRequest = new LoginRequest(TeleTok.mAddress, TeleTok.mBotUser, TeleTok.mBotPass, deviceId);
return loginRequest;
}
}
}

View File

@ -10,17 +10,99 @@ namespace TeleTok
.AddJsonFile("config.json", true) .AddJsonFile("config.json", true)
.Build(); .Build();
// Value to see what bot mode to run in
public static string botMode = config.GetSection("TeleTokConf:botMode").Value;
// Telegram bot config
public static string token = config.GetSection("TeleTokConf:token").Value; public static string token = config.GetSection("TeleTokConf:token").Value;
public static string ptInstance = config.GetSection("TeleTokConf:proxitokInstance").Value; public static string ptInstance = config.GetSection("TeleTokConf:ptInstance").Value;
// Matrix bot config
public static string matrixAddress = config.GetSection("TeleTokConf:matrixAddress").Value;
public static Uri mAddress;
public static string mBotUser = config.GetSection("TeleTokConf:mBotUser").Value;
public static string mBotPass = config.GetSection("TeleTokConf:mBotPass").Value;
static async Task Main(string[] args) static async Task Main(string[] args)
{ {
//Checks to see what mode to run the bot in
LogMessage($"The current running config is: \n Bot Mode: {botMode} \n Telegram Token: {token} \n ProxiTok Instance: {ptInstance} \n Matrix Homeserver: {matrixAddress} \n Matrix Bot User: {mBotUser}");
TelegramListener listener = new TelegramListener(); if(botMode == "telegram")
Console.WriteLine("Now listening..."); {
//Checks if the config json data is valid
if(!ConfigCheck(token))
{
LogMessage("Telegram bot token is invalid! Exiting...");
}
else if(!ConfigCheck(ptInstance))
{
LogMessage("Proxitok instance is invalid! Exiting...");
}
else
{
TelegramListener tListener = new TelegramListener();
LogMessage("Now listening...");
listener.RunListener(); tListener.RunListener();
}
}
else if(botMode == "matrix")
{
//Checks if the config json data is valid
if(Uri.IsWellFormedUriString(matrixAddress, UriKind.Absolute))
{
mAddress = new Uri(matrixAddress);
}
else
{
LogMessage("Matrix server address is not a valid URL! Exiting...");
}
if(!ConfigCheck(mBotUser))
{
LogMessage("Matrix bot username is invalid! Exiting...");
}
else if(!ConfigCheck(mBotPass))
{
LogMessage("Matrix bot password is invalid! Exiting...");
}
else
{
MatrixListener mListener = new MatrixListener();
LogMessage("Now listening...");
await mListener.RunListener();
}
}
else
{
LogMessage("Bot mode is not configured! Enter either \'telegram\' or \'matrix\'");
}
}
public static bool ConfigCheck(string confItem)
{
if(confItem == "" || confItem == null
|| confItem == "INSERT TOKEN HERE"
|| confItem == "PROXITOK INSTANCE URL"
|| confItem == "SYNAPSE SERVER URL"
|| confItem == "MATRIX BOT USERNAMEL"
|| confItem == "MATRIX BOT PASSWORD")
{
return false;
}
else
{
return true;
}
}
public static void LogMessage(string text)
{
DateTime now =DateTime.Now;
Console.WriteLine("[" + now.ToString() + "] " + text);
} }
} }
} }

View File

@ -1,5 +1,33 @@
[![Build Status](https://ci.kizaing.ca/api/badges/kizaing/TeleTok/status.svg)](https://ci.kizaing.ca/kizaing/TeleTok) [![Build Status](https://ci.kizaing.ca/api/badges/kizaing/TeleTok/status.svg)](https://ci.kizaing.ca/kizaing/TeleTok)
# TeleTok Telegram Bot # TeleTok Telegram Bot
This bot will monitor any chats for TikTok links that are posted, and then will run the link through a [ProxiTok](https://github.com/pablouser1/ProxiTok) instance to generate a download link. The resulting video file will then get directly uploaded directly to your chat.
This bot is in early development, but the end goal is to have this bot automatically convert all tiktok links in a chat into a videofile that can be re-uploaded to the telegram chat ## Building
Requirements: Dotnet SDK 6.0
Run `dotnet build` for a Debug instance
Run `dotnet publish` for a full release
## Installation
### Requirements
* A telegram bot token
* A working [ProxiTok](https://github.com/pablouser1/ProxiTok) instance, either public or hosted yourself. (Please be kind and take bandwidth into account when using a public instance)
### Binary
1. Either build the application or download a release zip for your OS/architecture
2. Edit the config.json and put your telegram bot token in the "token" field, and your chosen ProxiTok instance in the "ptInstance" field
3. Run the TeleTok.exe/TeleTok executable
### Docker
1. You can build an image for yourself with `docker build teletok .` or you can pull a prebuilt image with `docker pull kizaing/teletok:latest`
2. Copy the placeholder config.json from the repo to a location of your choosing
3. Edit the config.json and put your telegram bot token in the "token" field, and your chosen ProxiTok instance in the "ptInstance" field
4. Run the container with `docker run -v ${PWD}/config.json:/app/teletok/config.json -d kizaing/teletok:latest`
## To Do
- [x] Add better error and link handling
- [x] Process videos into telegram
- [ ] Add [Matrix](https://matrix.org) support
- [ ] Automate binary release publishing

View File

@ -8,8 +8,10 @@
</PropertyGroup> </PropertyGroup>
<ItemGroup> <ItemGroup>
<PackageReference Include="Matrix.Sdk" Version="1.0.7" />
<PackageReference Include="Microsoft.Extensions.Configuration.Binder" Version="7.0.2" /> <PackageReference Include="Microsoft.Extensions.Configuration.Binder" Version="7.0.2" />
<PackageReference Include="Microsoft.Extensions.Configuration.Json" Version="7.0.0" /> <PackageReference Include="Microsoft.Extensions.Configuration.Json" Version="7.0.0" />
<PackageReference Include="Sodium.Core" Version="1.3.3" />
<PackageReference Include="Telegram.Bot" Version="17.0.0" /> <PackageReference Include="Telegram.Bot" Version="17.0.0" />
<PackageReference Include="Telegram.Bot.Extensions.Polling" Version="1.0.2" /> <PackageReference Include="Telegram.Bot.Extensions.Polling" Version="1.0.2" />
</ItemGroup> </ItemGroup>

View File

@ -54,8 +54,6 @@ namespace TeleTok
// Passes the url along to the video downloader if it is valid AND a tiktok link // Passes the url along to the video downloader if it is valid AND a tiktok link
if (isUri) if (isUri)
{
try
{ {
if(messageText.Contains("tiktok.com")) if(messageText.Contains("tiktok.com"))
{ {
@ -68,11 +66,6 @@ namespace TeleTok
); );
} }
} }
catch
{
Console.WriteLine("Valid TikTok URI was sent, but was not a video!");
}
}
} }
Task HandlePollingErrorAsync(ITelegramBotClient botClient, Exception exception, CancellationToken cancellationToken) Task HandlePollingErrorAsync(ITelegramBotClient botClient, Exception exception, CancellationToken cancellationToken)
@ -84,7 +77,7 @@ namespace TeleTok
_ => exception.ToString() _ => exception.ToString()
}; };
Console.WriteLine(ErrorMessage); TeleTok.LogMessage(ErrorMessage);
return Task.CompletedTask; return Task.CompletedTask;
} }
} }

View File

@ -12,13 +12,16 @@ namespace TeleTok
string url = videourl; string url = videourl;
string proxyUrl; string proxyUrl;
TeleTok.LogMessage("Video for " + videourl + " processing..");
if(url.Contains("vm.tiktok.com")) if(url.Contains("vm.tiktok.com"))
{ {
url = UnshortenUrl(url); url = UnshortenUrl(url);
} }
proxyUrl = TeleTok.ptInstance + "/download?url=" + url; proxyUrl = CreateDownloadLink(url);
Console.WriteLine("Video for " + url + " has been sent..");
TeleTok.LogMessage("Sending video link for " + proxyUrl);
return proxyUrl; return proxyUrl;
} }
@ -33,5 +36,25 @@ namespace TeleTok
return realUrl; return realUrl;
} }
//Breaks apart the URL and extracts the User and Video ID to be processed into a working download link
static string CreateDownloadLink(string videourl)
{
Uri segmentedUri = new Uri(videourl);
segmentedUri = new Uri(segmentedUri.AbsoluteUri.Replace(segmentedUri.Query, string.Empty));
string videoUser = segmentedUri.Segments[1];
videoUser = videoUser.Replace(@"/", "");
string videoID = segmentedUri.Segments[3];
string fixedUrl = "https://www.tiktok.com/" + videoUser + "/video/" + videoID + @"&id=" + videoID + @"&user=" + videoUser.Remove(0, 1);
string proxyLink = TeleTok.ptInstance + "/download?url=" + fixedUrl;
TeleTok.LogMessage("Input User ID is: " + videoUser);
TeleTok.LogMessage("Input video ID is: " + videoID);
return proxyLink;
}
} }
} }

View File

@ -1,6 +1,10 @@
{ {
"TeleTokConf": { "TeleTokConf": {
"botMode": "telegram",
"token": "INSERT TOKEN HERE", "token": "INSERT TOKEN HERE",
"proxitokInstance": "PROXITOK INSTANCE URL" "ptInstance": "PROXITOK INSTANCE URL",
"matrixAddress": "SYNAPSE SERVER URL",
"mBotUser": "MATRIX BOT USERNAME",
"mBotPass": "MATRIX BOT PASSWORD"
} }
} }