package sessionimport import ( "crypto/sha1" "database/sql" "fmt" "github.com/gotd/td/session" _ "modernc.org/sqlite" ) // ConvertPyrogramSession reads a Pyrogram/Telethon SQLite session file and // builds a gotd/td session.Data representing the same authorization. // // Pyrogram schema (single row in `sessions` table): // // CREATE TABLE sessions ( // dc_id INTEGER PRIMARY KEY, // api_id INTEGER, // test_mode INTEGER, // auth_key BLOB, -- 256 bytes // date INTEGER NOT NULL, // user_id INTEGER, // is_bot INTEGER); func ConvertPyrogramSession(sqlitePath string) (*session.Data, error) { // Open READ-ONLY + IMMUTABLE. Pyrogram .session files may be in-use by a // running Pyrogram client; a write-capable handle could corrupt them via // journal rollback on crash. dsn := fmt.Sprintf("file:%s?mode=ro&immutable=1", sqlitePath) db, err := sql.Open("sqlite", dsn) if err != nil { return nil, fmt.Errorf("open pyrogram sqlite: %w", err) } defer db.Close() var dcID int var authKey []byte err = db.QueryRow(`SELECT dc_id, auth_key FROM sessions LIMIT 1`).Scan(&dcID, &authKey) if err != nil { return nil, fmt.Errorf("read pyrogram sessions row: %w", err) } if len(authKey) != 256 { return nil, fmt.Errorf("invalid auth_key length: %d (want 256)", len(authKey)) } addr, err := TGDCAddr(dcID) if err != nil { return nil, err } // auth_key_id = SHA-1(auth_key)[12:20] — lower 64 bits of the SHA-1 digest. sum := sha1.Sum(authKey) keyID := make([]byte, 8) copy(keyID, sum[12:20]) return &session.Data{ DC: dcID, Addr: addr, AuthKey: authKey, AuthKeyID: keyID, }, nil }