diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..1f29647 --- /dev/null +++ b/.gitignore @@ -0,0 +1,5 @@ +build/ +.rgadle/ +.gradle/ +auth.dat +dc.dat diff --git a/build.gradle b/build.gradle index bbfeb03..c227b16 100644 --- a/build.gradle +++ b/build.gradle @@ -1 +1,29 @@ apply plugin: 'java' +apply plugin: 'application' + +mainClassName= 'de.fabianonline.telegram_backup.Main' + +repositories { + mavenCentral() + maven { + url "https://jitpack.io" + } +} + +dependencies { + compile 'com.github.badoualy:kotlogram:0.0.6' +} + +run { + standardInput = System.in +} + +jar { + manifest { + attributes "Main-Class": "$mainClassName" + } + + from { + configurations.compile.collect { it.isDirectory() ? it : zipTree(it) } + } +} diff --git a/src/de/fabianonline/telegram_backup/Main.java b/src/de/fabianonline/telegram_backup/Main.java deleted file mode 100644 index 6774082..0000000 --- a/src/de/fabianonline/telegram_backup/Main.java +++ /dev/null @@ -1,7 +0,0 @@ -package de.fabianonline.telegram_backup; - -public class Main { - public static void main(String[] args) { - System.out.println("Hello World"); - } -} diff --git a/src/main/java/de/fabianonline/telegram_backup/ApiStorage.java b/src/main/java/de/fabianonline/telegram_backup/ApiStorage.java new file mode 100644 index 0000000..44ddf38 --- /dev/null +++ b/src/main/java/de/fabianonline/telegram_backup/ApiStorage.java @@ -0,0 +1,69 @@ +package de.fabianonline.telegram_backup; + +import com.github.badoualy.telegram.api.TelegramApiStorage; +import com.github.badoualy.telegram.mtproto.DataCenter; +import com.github.badoualy.telegram.mtproto.auth.AuthKey; + +import org.apache.commons.io.FileUtils; + +import java.io.File; +import java.io.FileNotFoundException; +import java.io.IOException; + +class ApiStorage implements TelegramApiStorage { + public void saveAuthKey(AuthKey authKey) { + try { + FileUtils.writeByteArrayToFile(Config.FILE_AUTH_KEY, authKey.getKey()); + } catch (IOException e) { + e.printStackTrace(); + } + } + + public AuthKey loadAuthKey() { + try { + return new AuthKey(FileUtils.readFileToByteArray(Config.FILE_AUTH_KEY)); + } catch (IOException e) { + if (!(e instanceof FileNotFoundException)) e.printStackTrace(); + } + + return null; + } + + public void saveDc(DataCenter dc) { + try { + FileUtils.write(Config.FILE_DC, dc.toString()); + } catch (IOException e) { + e.printStackTrace(); + } + } + + public DataCenter loadDc() { + try { + String[] infos = FileUtils.readFileToString(Config.FILE_DC).split(":"); + return new DataCenter(infos[0], Integer.parseInt(infos[1])); + } catch (IOException e) { + if (!(e instanceof FileNotFoundException)) e.printStackTrace(); + } + return null; + } + + public void deleteAuthKey() { + try { + FileUtils.forceDelete(Config.FILE_AUTH_KEY); + } catch (IOException e) { + e.printStackTrace(); + } + } + + public void deleteDc() { + try { + FileUtils.forceDelete(Config.FILE_DC); + } catch (IOException e) { + e.printStackTrace(); + } + } + + public void saveServerSalt(long salt) {} + + public Long loadServerSalt() { return null; } +} diff --git a/src/main/java/de/fabianonline/telegram_backup/Config.java b/src/main/java/de/fabianonline/telegram_backup/Config.java new file mode 100644 index 0000000..75f2666 --- /dev/null +++ b/src/main/java/de/fabianonline/telegram_backup/Config.java @@ -0,0 +1,17 @@ +package de.fabianonline.telegram_backup; + +import java.io.File; + +class Config { + public static final int APP_ID = 32860; + public static final String APP_HASH = "16e4ff955cd0adfc058f95ca564f562d"; + public static final String APP_MODEL = "Desktop"; + public static final String APP_SYSVER = "1.0"; + public static final String APP_APPVER = "0.1"; + public static final String APP_LANG = "en"; + + public static final File FILE_AUTH_KEY = new File("auth.dat"); + public static final File FILE_DC = new File("dc.dat"); + public static final File FILE_SALT = new File("salt.dat"); +} + diff --git a/src/main/java/de/fabianonline/telegram_backup/Main.java b/src/main/java/de/fabianonline/telegram_backup/Main.java new file mode 100644 index 0000000..faf7f82 --- /dev/null +++ b/src/main/java/de/fabianonline/telegram_backup/Main.java @@ -0,0 +1,60 @@ +package de.fabianonline.telegram_backup; + +import com.github.badoualy.telegram.api.Kotlogram; +import com.github.badoualy.telegram.api.TelegramApp; +import com.github.badoualy.telegram.api.TelegramClient; +import com.github.badoualy.telegram.tl.exception.RpcErrorException; + +import de.fabianonline.telegram_backup.Config; +import de.fabianonline.telegram_backup.ApiStorage; +import de.fabianonline.telegram_backup.UserManager; + +import java.io.File; +import java.io.IOException; +import java.util.Scanner; + +public class Main { + public static TelegramApp app = new TelegramApp(Config.APP_ID, Config.APP_HASH, Config.APP_MODEL, Config.APP_SYSVER, Config.APP_APPVER, Config.APP_LANG); + public static UserManager user = null; + + public static void main(String[] args) { + System.out.println("Hello World"); + + Kotlogram.setDebugLogEnabled(true); + + TelegramClient client = Kotlogram.getDefaultClient(app, new ApiStorage()); + + try { + user = new UserManager(client); + + if (!user.isLoggedIn()) { + System.out.println("Please enter your phone number in international format."); + System.out.println("Example: +4917077651234"); + System.out.print("> "); + String phone = new Scanner(System.in).nextLine(); + user.sendCodeToPhoneNumber(phone); + + System.out.println("Telegram sent you a code. Please enter it here."); + System.out.print("> "); + String code = new Scanner(System.in).nextLine(); + user.verifyCode(code); + + if (user.isPasswordNeeded()) { + System.out.println("We also need your account password."); + System.out.print("> "); + String pw = new Scanner(System.in).nextLine(); + user.verifyPassword(pw); + } + } + + System.out.println("You are now signed in as " + user.getUserString()); + } catch (RpcErrorException e) { + e.printStackTrace(); + } catch (IOException e) { + e.printStackTrace(); + } finally { + client.close(); + } + System.out.println("----- EXIT -----"); + } +} diff --git a/src/main/java/de/fabianonline/telegram_backup/TLRequestAccountGetPasswordWithCurrentSalt.java b/src/main/java/de/fabianonline/telegram_backup/TLRequestAccountGetPasswordWithCurrentSalt.java new file mode 100644 index 0000000..3987057 --- /dev/null +++ b/src/main/java/de/fabianonline/telegram_backup/TLRequestAccountGetPasswordWithCurrentSalt.java @@ -0,0 +1,29 @@ +package de.fabianonline.telegram_backup; + +import com.github.badoualy.telegram.tl.TLContext; +import com.github.badoualy.telegram.tl.api.account.TLPassword; +import com.github.badoualy.telegram.tl.core.TLMethod; +import com.github.badoualy.telegram.tl.core.TLObject; + +import java.io.IOException; +import java.io.InputStream; + +import static com.github.badoualy.telegram.tl.StreamUtils.readTLObject; + +public class TLRequestAccountGetPasswordWithCurrentSalt extends TLMethod { + public static final int CONSTRUCTOR_ID = 0x548a30f5; + private final String _constructor = "account.getPassword#548a30f5"; + public TLRequestAccountGetPasswordWithCurrentSalt() {} + public TLPassword deserializeResponse(InputStream stream, TLContext context) throws IOException { + final TLObject response = readTLObject(stream, context); + if (response == null) { + throw new IOException("Unable to parse response"); + } + if (!(response instanceof TLPassword)) { + throw new IOException("Incorrect response type, expected getClass().getCanonicalName(), found response.getClass().getCanonicalName()"); + } + return (TLPassword) response; + } + public String toString() { return _constructor; } + public int getConstructorId() { return CONSTRUCTOR_ID; } +} diff --git a/src/main/java/de/fabianonline/telegram_backup/UserManager.java b/src/main/java/de/fabianonline/telegram_backup/UserManager.java new file mode 100644 index 0000000..21de8e5 --- /dev/null +++ b/src/main/java/de/fabianonline/telegram_backup/UserManager.java @@ -0,0 +1,92 @@ +package de.fabianonline.telegram_backup; + +import com.github.badoualy.telegram.api.TelegramClient; +import com.github.badoualy.telegram.tl.api.auth.TLAbsSentCode; +import com.github.badoualy.telegram.tl.api.auth.TLAuthorization; +import com.github.badoualy.telegram.tl.api.TLUser; +import com.github.badoualy.telegram.tl.api.TLUserFull; +import com.github.badoualy.telegram.tl.api.TLInputUserSelf; +import com.github.badoualy.telegram.tl.api.account.TLPassword; +import com.github.badoualy.telegram.tl.exception.RpcErrorException; +import com.github.badoualy.telegram.tl.core.TLBytes; + +import java.security.MessageDigest; +import java.security.NoSuchAlgorithmException; +import java.io.IOException; + +class UserManager { + public TLUser user = null; + public String phone = null; + private String code = null; + private TelegramClient client = null; + private TLAbsSentCode sent_code = null; + private TLAuthorization auth = null; + private boolean password_needed = false; + + public UserManager(TelegramClient c) throws IOException { + this.client = c; + try { + TLUserFull full_user = this.client.usersGetFullUser(new TLInputUserSelf()); + this.user = full_user.getUser().getAsUser(); + } catch (Exception e) { + // This may happen. Ignoring it. + } + } + + public boolean isLoggedIn() { return user!=null; } + + public void sendCodeToPhoneNumber(String number) throws RpcErrorException, IOException { + this.phone = number; + this.sent_code = this.client.authSendCode(this.phone, 5); + } + + public void verifyCode(String code) throws RpcErrorException, IOException { + this.code = code; + try { + this.auth = client.authSignIn(phone, this.sent_code.getPhoneCodeHash(), this.code); + this.user = auth.getUser().getAsUser(); + } catch (RpcErrorException e) { + if (!e.getTag().equals("401: SESSION_PASSWORD_NEEDED")) throw e; + this.password_needed = true; + } + } + + public boolean isPasswordNeeded() { return this.password_needed; } + + public void verifyPassword(String pw) throws RpcErrorException, IOException { + byte[] password = pw.getBytes("UTF-8"); + byte[] salt = ((TLPassword)client.executeRpcQuery(new TLRequestAccountGetPasswordWithCurrentSalt())).getCurrentSalt().getData(); + MessageDigest md = null; + try { + md = MessageDigest.getInstance("SHA-256"); + } catch (NoSuchAlgorithmException e) { + e.printStackTrace(); + return; + } + byte[] salted = new byte[2*salt.length + password.length]; + System.arraycopy(salt, 0, salted, 0, salt.length); + System.arraycopy(password, 0, salted, salt.length, password.length); + System.arraycopy(salt, 0, salted, salt.length+password.length, salt.length); + byte[] hash = md.digest(salted); + auth = client.authCheckPassword(new TLBytes(hash)); + this.user = auth.getUser().getAsUser(); + } + + public String getUserString() { + if (this.user==null) return "Not logged in"; + StringBuilder sb = new StringBuilder(); + if (this.user.getFirstName()!=null) { + sb.append(this.user.getFirstName()); + } + if (this.user.getLastName()!=null) { + sb.append(" "); + sb.append(this.user.getLastName()); + } + if (this.user.getUsername()!=null) { + sb.append(" (@"); + sb.append(this.user.getUsername()); + sb.append(")"); + } + return sb.toString(); + } +}