├── .files ├── about.txt └── schema.txt ├── .gitignore ├── LICENSE ├── README.md ├── bower.json ├── dist ├── telegramApi.js └── telegramApi.min.js ├── docs ├── API.md ├── build.js ├── examples │ ├── createChannel.js │ ├── createChat.js │ ├── downloadDocument.js │ ├── editChatAdmin.js │ ├── editChatTitle.js │ ├── getChatLink.js │ ├── getHistory.js │ ├── getUserInfo.js │ ├── getUserPhoto.js │ ├── invokeApi.js │ ├── joinChat.js │ ├── logOut.js │ ├── sendCode.js │ ├── sendFile.js │ ├── sendMessage.js │ ├── sendSms.js │ ├── setConfig.js │ ├── signIn.js │ ├── signUp.js │ └── startBot.js └── jsdoc-options.json ├── example ├── index.html ├── script.js └── style.css ├── gulpfile.js ├── package.json └── src ├── IoC.js ├── js ├── App │ ├── AppChatsManager.js │ ├── AppPeersManager.js │ ├── AppProfileManager.js │ └── AppUsersManager.js ├── Etc │ ├── CryptoWorker.js │ ├── FileSaver.js │ ├── Helper.js │ ├── IdleManager.js │ ├── Storage.js │ ├── TelegramMeWebService.js │ ├── angular │ │ ├── $http.js │ │ ├── $interval.js │ │ ├── $q.js │ │ ├── $rootScope.js │ │ └── $timeout.js │ ├── jQuery.js │ └── qSync.js ├── Mtp │ ├── MtpApiFileManager.js │ ├── MtpApiManager.js │ ├── MtpAuthorizer.js │ ├── MtpDcConfigurator.js │ ├── MtpNetworkerFactory.js │ ├── MtpRsaKeysManager.js │ ├── MtpSecureRandom.js │ ├── MtpSingleInstanceService.js │ └── MtpTimeManager.js └── lib │ ├── bin_utils.js │ ├── config.js │ ├── polyfill.js │ ├── tl_utils.js │ └── utils.js ├── telegramApi.js └── vendor ├── cryptoJS ├── THIRDPARTY_LICENSE └── crypto.min.js └── jsbn ├── THIRDPARTY_LICENSE └── jsbn_combined.min.js /.files/about.txt: -------------------------------------------------------------------------------- 1 | /** 2 | * telegram-api v{VERSION} 3 | * Infinnity Solutions 4 | */ 5 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | .idea 2 | node_modules 3 | example/js/ 4 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # TelegramApi 2 | 3 | Based on [**webogram**](https://github.com/zhukov/webogram) 4 | 5 | ## Getting started 6 | 7 | 1) Install package via npm 8 | ``` 9 | npm install telegram-api-js 10 | ``` 11 | Or bower 12 | ``` 13 | bower install telegram-api-js 14 | ``` 15 | 16 | 2) Add a ``` 24 | 25 | 26 | 27 | ``` 28 | 29 | 3) Set your app configuration 30 | ``` 31 | /* You should register your application on https://my.telegram.org/ */ 32 | telegramApi.setConfig({ 33 | app: { 34 | id: 0, /* App ID */ 35 | hash: 'qwertyasdfghzxcvbnqwertyasd', /* App hash */ 36 | version: '0.0.0' /* App version */ 37 | }, 38 | server: { 39 | test: [ 40 | { 41 | id: 2, /* DC ID */ 42 | host: '0.0.0.0', 43 | port: 443 44 | } 45 | ], 46 | production: [ 47 | { 48 | id: 2, /* DC ID */ 49 | host: '0.0.0.0', 50 | port: 123 51 | } 52 | ] 53 | } 54 | }); 55 | ``` 56 | 57 | 4) Check your status 58 | ``` 59 | telegramApi.getUserInfo().then(function(user) { 60 | if (user.id) { 61 | // You have already signed in 62 | } else { 63 | // Log in 64 | } 65 | }); 66 | ``` 67 | 68 | [API documentation](./docs/API.md) 69 | -------------------------------------------------------------------------------- /bower.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "telegram-api", 3 | "license": "GPL-3.0", 4 | "ignore": [ 5 | "example", 6 | "src", 7 | "gulpfile.js", 8 | "package.json" 9 | ] 10 | } 11 | -------------------------------------------------------------------------------- /docs/API.md: -------------------------------------------------------------------------------- 1 | # Methods 2 | 3 | 4 | 5 |
6 |
invokeApi(method, [params])
7 |

Invoke any method from .files/schema.txt

8 |
9 |
sendCode(phone_number)
10 |

Send code by phone number

11 |
12 |
signIn(phone_number, phone_code_hash, phone_code)
13 |

Sign in

14 |
15 |
signUp(phone_number, phone_code_hash, phone_code, first_name, [last_name])
16 |

Sign up

17 |
18 |
sendMessage(id, message)
19 |

Send message

20 |
21 |
startBot(botName)
22 |

Send bot command /start

23 |
24 |
sendSms(phone_number, phone_code_hash)
25 |

Send code via SMS

26 |
27 |
setConfig(config)
28 |

Configure your application

29 |
30 |
createChat(title, userIDs)
31 |

Create telegram chat (By default only creator will admin. In the future it will be changed)

32 |
33 |
getChatLink(chatID, [force])
34 |

Get chat invite link

35 |
36 |
getUserInfo()
37 |

Get self information

38 |
39 |
getUserPhoto([type], [size])
40 |

Get user photo

41 |
42 |
logOut()
43 |

Logout from Telegram

44 |
45 |
createChannel(title, [about])
46 |

Create channel (use carefully)

47 |
48 |
getHistory(params)
49 |

Get chat messages

50 |
51 |
sendFile(params)
52 |

Send file

53 |
54 |
downloadDocument(doc, [progress], [autosave])
55 |

Download Telegram document

56 |
57 |
joinChat(link)
58 |

Join to chat by link or hash

59 |
60 |
editChatAdmin(chatID, userID, [isAdmin])
61 |

Edit chat administrator

62 |
63 |
editChatTitle(chat_id, title)
64 |

Edit chat title

65 |
66 |
67 | 68 | 69 | 70 | ## invokeApi(method, [params]) 71 | Invoke any method from .files/schema.txt 72 | 73 | 74 | 75 | | Param | Type | Description | 76 | | --- | --- | --- | 77 | | method | String | Method name | 78 | | [params] | Object | Parameters | 79 | 80 | **Example** 81 | ```js 82 | telegramApi.invokeApi('messages.getDialogs', { 83 | offset_peer: {_: 'inputPeerEmpty'}, 84 | offset_date: 0, 85 | limit: 20 86 | }).then(function(dialogResult) { 87 | /* Do something */ 88 | }); 89 | ``` 90 | 91 | 92 | ## sendCode(phone_number) 93 | Send code by phone number 94 | 95 | 96 | 97 | | Param | Type | Description | 98 | | --- | --- | --- | 99 | | phone_number | String | Phone number | 100 | 101 | **Example** 102 | ```js 103 | telegramApi.sendCode('some_phone_number').then(function(sent_code) { 104 | if (!sent_code.phone_registered) { 105 | // New user 106 | } 107 | 108 | // phone_code_hash will need to sign in or sign up 109 | window.phone_code_hash = sent_code.phone_code_hash; 110 | }); 111 | ``` 112 | 113 | 114 | ## signIn(phone_number, phone_code_hash, phone_code) 115 | Sign in 116 | 117 | 118 | 119 | | Param | Type | Description | 120 | | --- | --- | --- | 121 | | phone_number | String | Phone number | 122 | | phone_code_hash | String | Code hash (was received in sendCode method) | 123 | | phone_code | String | Code by Telegram | 124 | 125 | **Example** 126 | ```js 127 | telegramApi.signIn('some_phone_number', window.phone_code_hash, '000000').then(function() { 128 | // Sign in complete 129 | delete window.phone_code_hash; 130 | }, function(err) { 131 | switch (err.type) { 132 | case 'PHONE_CODE_INVALID': 133 | // alert "Phone code invalid" 134 | break; 135 | case 'PHONE_NUMBER_UNOCCUPIED': 136 | // User not registered, you should use signUp method 137 | break; 138 | } 139 | }); 140 | ``` 141 | 142 | 143 | ## signUp(phone_number, phone_code_hash, phone_code, first_name, [last_name]) 144 | Sign up 145 | 146 | 147 | 148 | | Param | Type | Description | 149 | | --- | --- | --- | 150 | | phone_number | String | Phone number | 151 | | phone_code_hash | String | Code hash (was received in sendCode method) | 152 | | phone_code | String | Code by Telegram | 153 | | first_name | String | User first name | 154 | | [last_name] | String | User last name | 155 | 156 | **Example** 157 | ```js 158 | telegramApi.signUp('some_phone_number', window.phone_code_hash, '000000', 'John', 'Doe').then(function() { 159 | // Sign up complete 160 | delete window.phone_code_hash; 161 | }); 162 | ``` 163 | 164 | 165 | ## sendMessage(id, message) 166 | Send message 167 | 168 | 169 | 170 | | Param | Type | Description | 171 | | --- | --- | --- | 172 | | id | Number | Peer ID | 173 | | message | String | Message text | 174 | 175 | **Example** 176 | ```js 177 | telegramApi.sendMessage(9999999999, 'Hey man!').then(function(updates) { 178 | // Do something 179 | }); 180 | ``` 181 | 182 | 183 | ## startBot(botName) 184 | Send bot command /start 185 | 186 | 187 | 188 | | Param | Type | Description | 189 | | --- | --- | --- | 190 | | botName | String | Bot name | 191 | 192 | **Example** 193 | ```js 194 | telegramApi.startBot('exampleBot').then(function(updates) { 195 | // Was invoked telegramApi.sendMessage(bot.id, '/start'); 196 | }); 197 | ``` 198 | 199 | 200 | ## sendSms(phone_number, phone_code_hash) 201 | Send code via SMS 202 | 203 | 204 | 205 | | Param | Type | Description | 206 | | --- | --- | --- | 207 | | phone_number | String | Phone number | 208 | | phone_code_hash | String | Code hash (was received in sendCode method) | 209 | 210 | **Example** 211 | ```js 212 | telegramApi.sendSms('some_phone_number', window.phone_code_hash).then(function() { 213 | // Do something 214 | }); 215 | ``` 216 | 217 | 218 | ## setConfig(config) 219 | Configure your application 220 | 221 | 222 | 223 | | Param | Type | Description | 224 | | --- | --- | --- | 225 | | config | Object | Configuration object | 226 | | config.app.id | Number | Application ID | 227 | | config.app.hash | String | App hash | 228 | | config.app.version | String | App version | 229 | | config.server.test | Array.<Object> | List test servers | 230 | | config.server.production | Array.<Object> | List production servers | 231 | 232 | **Example** 233 | ```js 234 | telegramApi.setConfig({ 235 | app: { 236 | id: 0, /* App ID */ 237 | hash: 'qwertyasdfghzxcvbnqwertyasd', /* App hash */ 238 | version: '0.0.0' /* App version */ 239 | }, 240 | server: { 241 | test: [ 242 | { 243 | id: 2, /* DC ID */ 244 | host: '0.0.0.0', 245 | port: 443 246 | } 247 | ], 248 | production: [ 249 | { 250 | id: 2, /* DC ID */ 251 | host: '0.0.0.0', 252 | port: 123 253 | } 254 | ] 255 | } 256 | }); 257 | ``` 258 | 259 | 260 | ## createChat(title, userIDs) 261 | Create telegram chat (By default only creator will admin. In the future it will be changed) 262 | 263 | 264 | 265 | | Param | Type | Description | 266 | | --- | --- | --- | 267 | | title | String | Chat title | 268 | | userIDs | Array.<Number> | User ids list | 269 | 270 | **Example** 271 | ```js 272 | telegramApi.createChat('Chat title', [123456789]).then(function(updates) { 273 | // If you want all users to be administrators, use it 274 | return telegramApi.invokeApi('messages.toggleChatAdmins', { 275 | chat_id: updates.chats[0].id, 276 | enabled: false 277 | }); 278 | }); 279 | ``` 280 | 281 | 282 | ## getChatLink(chatID, [force]) 283 | Get chat invite link 284 | 285 | 286 | 287 | | Param | Type | Description | 288 | | --- | --- | --- | 289 | | chatID | Number | String | Chat id | 290 | | [force] | Boolean | Force generate | 291 | 292 | **Example** 293 | ```js 294 | telegramApi.getChatLink(12456789, true).then(function(link) { 295 | // Do something 296 | }); 297 | ``` 298 | 299 | 300 | ## getUserInfo() 301 | Get self information 302 | 303 | 304 | **Example** 305 | ```js 306 | telegramApi.getUserInfo().then(function(user) { 307 | if (user.id) { 308 | // You have already signed in 309 | } else { 310 | // Open log in page 311 | } 312 | }); 313 | ``` 314 | 315 | 316 | ## getUserPhoto([type], [size]) 317 | Get user photo 318 | 319 | 320 | 321 | | Param | Type | Description | 322 | | --- | --- | --- | 323 | | [type] | String | Photo type (values: byteArray (default), base64, blob) | 324 | | [size] | String | Photo size (values: big (default), small) | 325 | 326 | **Example** 327 | ```js 328 | telegramApi.getUserPhoto('base64', 'small').then(function(base64) { 329 | $('img#avatar').attr('src', base64); 330 | }); 331 | ``` 332 | 333 | 334 | ## logOut() 335 | Logout from Telegram 336 | 337 | 338 | **Example** 339 | ```js 340 | telegramApi.logOut().then(function() { 341 | setTimeout(function() { 342 | // Do something after logouts 343 | // Use setTimeout (It will be fixed) 344 | }, 1500); 345 | }); 346 | ``` 347 | 348 | 349 | ## createChannel(title, [about]) 350 | Create channel (use carefully) 351 | 352 | 353 | 354 | | Param | Type | Description | 355 | | --- | --- | --- | 356 | | title | String | Channel title | 357 | | [about] | String | About text | 358 | 359 | **Example** 360 | ```js 361 | telegramApi.createChannel('New channel', 'This is example channel').then(function(updates) { 362 | var channel = updates.chats[0]; 363 | 364 | /** 365 | * WARNING! 366 | * If you often call this method, you will receive a reply FLOOD_WAIT_{seconds} 367 | */ 368 | }); 369 | ``` 370 | 371 | 372 | ## getHistory(params) 373 | Get chat messages 374 | 375 | 376 | 377 | | Param | Type | Description | 378 | | --- | --- | --- | 379 | | params | Object | Parameters | 380 | | params.id | Number | Chat ID | 381 | | [params.take] | Number | How much messages you will receive (default: 15) | 382 | | [params.skip] | Number | How much messages you will skip (default: 0) | 383 | | [params.type] | String | Chat type (for chat and channel use 'chat' (default)) | 384 | 385 | **Example** 386 | ```js 387 | telegramApi.getHistory({ 388 | id: 12345678, 389 | take: 50, 390 | type: 'user' 391 | }).then(function(data) { 392 | var totalCount = data.count || data.messages.length; 393 | 394 | data.messages.forEach(function(message) { 395 | /** 396 | * message.from_id - Sender ID 397 | * message.date - Date 398 | * message.media - If message is Document or Photo 399 | * message.message - Message text 400 | */ 401 | }); 402 | }); 403 | ``` 404 | 405 | 406 | ## sendFile(params) 407 | Send file 408 | 409 | 410 | 411 | | Param | Type | Description | 412 | | --- | --- | --- | 413 | | params | Object | Parameters | 414 | | params.id | Number | Peer ID | 415 | | params.type | String | Chat type (for chat and channel use 'chat' (default)) | 416 | | params.file | File | File | 417 | | [params.caption] | String | File caption | 418 | 419 | **Example** 420 | ```js 421 | telegramApi.sendFile({ 422 | id: 123456789, 423 | type: 'user', 424 | file: $('input[type=file]').val(), 425 | caption: 'This is file' 426 | }).then(function(updates) { 427 | // Do something 428 | }); 429 | ``` 430 | 431 | 432 | ## downloadDocument(doc, [progress], [autosave]) 433 | Download Telegram document 434 | 435 | 436 | 437 | | Param | Type | Description | 438 | | --- | --- | --- | 439 | | doc | Object | Telegram document | 440 | | [progress] | function | Progress callback | 441 | | [autosave] | Boolean | Save file on device | 442 | 443 | **Example** 444 | ```js 445 | telegramApi.getHistory({ 446 | id: 123456789, 447 | type: 'user', 448 | take: 1, 449 | skip: 0 450 | }).then(function(data) { 451 | var message = data.messages[0]; 452 | var doc = message.media.document; 453 | 454 | telegramApi.downloadDocument(doc, function(downloaded, total) { 455 | console.log('Loaded ' + downloaded + ' bytes. Total ' + total + ' bytes'); 456 | }).then(function(result) { 457 | /** 458 | * result.bytes - file data 459 | * result.fileName - file name 460 | * result.type - file MIME-type 461 | */ 462 | }); 463 | }); 464 | ``` 465 | 466 | 467 | ## joinChat(link) 468 | Join to chat by link or hash 469 | 470 | 471 | 472 | | Param | Type | Description | 473 | | --- | --- | --- | 474 | | link | String | Chat invite link or hash | 475 | 476 | **Example** 477 | ```js 478 | telegramApi.joinChat('https://telegram.me/joinchat/some-hash').then(function(updates) { 479 | // Do something 480 | }); 481 | ``` 482 | 483 | 484 | ## editChatAdmin(chatID, userID, [isAdmin]) 485 | Edit chat administrator 486 | 487 | 488 | 489 | | Param | Type | Description | 490 | | --- | --- | --- | 491 | | chatID | Number | Chat ID | 492 | | userID | Number | User ID | 493 | | [isAdmin] | Boolean | Admin status (default: true) | 494 | 495 | **Example** 496 | ```js 497 | telegramApi.editChatAdmin(123456789, 987654321, false).then(function() { 498 | // Do something 499 | }); 500 | ``` 501 | 502 | 503 | ## editChatTitle(chat_id, title) 504 | Edit chat title 505 | 506 | 507 | 508 | | Param | Type | Description | 509 | | --- | --- | --- | 510 | | chat_id | Number | Chat ID | 511 | | title | String | New title | 512 | 513 | **Example** 514 | ```js 515 | telegramApi.editChatTitle(123456789, 'New title').then(function() { 516 | // Do something 517 | }); 518 | ``` 519 | 520 | 521 | ## To be continued -------------------------------------------------------------------------------- /docs/build.js: -------------------------------------------------------------------------------- 1 | const jsdoc2md = require('jsdoc-to-markdown'); 2 | const fs = require('fs'); 3 | 4 | const output = './docs/API.md'; 5 | const examplesPath = './docs/examples/'; 6 | 7 | let options = require('./jsdoc-options.json'); 8 | 9 | jsdoc2md.render(options).then(result => { 10 | result = result 11 | .replace(/\*\*Kind\*\*: global function/g, '') 12 | .replace(/## Functions/g, '') 13 | .replace(/<%example:(\w+\.js)%>/g, function(str, fileName) { 14 | return fs.readFileSync(examplesPath + fileName, 'utf8').replace(/\n$/, ''); 15 | }); 16 | 17 | fs.writeFileSync(output, '# Methods\n\n' + result + '\n\n## To be continued'); 18 | }); 19 | -------------------------------------------------------------------------------- /docs/examples/createChannel.js: -------------------------------------------------------------------------------- 1 | telegramApi.createChannel('New channel', 'This is example channel').then(function(updates) { 2 | var channel = updates.chats[0]; 3 | 4 | /** 5 | * WARNING! 6 | * If you often call this method, you will receive a reply FLOOD_WAIT_{seconds} 7 | */ 8 | }); 9 | -------------------------------------------------------------------------------- /docs/examples/createChat.js: -------------------------------------------------------------------------------- 1 | telegramApi.createChat('Chat title', [123456789]).then(function(updates) { 2 | // If you want all users to be administrators, use it 3 | return telegramApi.invokeApi('messages.toggleChatAdmins', { 4 | chat_id: updates.chats[0].id, 5 | enabled: false 6 | }); 7 | }); 8 | -------------------------------------------------------------------------------- /docs/examples/downloadDocument.js: -------------------------------------------------------------------------------- 1 | telegramApi.getHistory({ 2 | id: 123456789, 3 | type: 'user', 4 | take: 1, 5 | skip: 0 6 | }).then(function(data) { 7 | var message = data.messages[0]; 8 | var doc = message.media.document; 9 | 10 | telegramApi.downloadDocument(doc, function(downloaded, total) { 11 | console.log('Loaded ' + downloaded + ' bytes. Total ' + total + ' bytes'); 12 | }).then(function(result) { 13 | /** 14 | * result.bytes - file data 15 | * result.fileName - file name 16 | * result.type - file MIME-type 17 | */ 18 | }); 19 | }); 20 | -------------------------------------------------------------------------------- /docs/examples/editChatAdmin.js: -------------------------------------------------------------------------------- 1 | telegramApi.editChatAdmin(123456789, 987654321, false).then(function() { 2 | // Do something 3 | }); 4 | -------------------------------------------------------------------------------- /docs/examples/editChatTitle.js: -------------------------------------------------------------------------------- 1 | telegramApi.editChatTitle(123456789, 'New title').then(function() { 2 | // Do something 3 | }); 4 | -------------------------------------------------------------------------------- /docs/examples/getChatLink.js: -------------------------------------------------------------------------------- 1 | telegramApi.getChatLink(12456789, true).then(function(link) { 2 | // Do something 3 | }); 4 | -------------------------------------------------------------------------------- /docs/examples/getHistory.js: -------------------------------------------------------------------------------- 1 | telegramApi.getHistory({ 2 | id: 12345678, 3 | take: 50, 4 | type: 'user' 5 | }).then(function(data) { 6 | var totalCount = data.count || data.messages.length; 7 | 8 | data.messages.forEach(function(message) { 9 | /** 10 | * message.from_id - Sender ID 11 | * message.date - Date 12 | * message.media - If message is Document or Photo 13 | * message.message - Message text 14 | */ 15 | }); 16 | }); 17 | -------------------------------------------------------------------------------- /docs/examples/getUserInfo.js: -------------------------------------------------------------------------------- 1 | telegramApi.getUserInfo().then(function(user) { 2 | if (user.id) { 3 | // You have already signed in 4 | } else { 5 | // Open log in page 6 | } 7 | }); 8 | -------------------------------------------------------------------------------- /docs/examples/getUserPhoto.js: -------------------------------------------------------------------------------- 1 | telegramApi.getUserPhoto('base64', 'small').then(function(base64) { 2 | $('img#avatar').attr('src', base64); 3 | }); 4 | -------------------------------------------------------------------------------- /docs/examples/invokeApi.js: -------------------------------------------------------------------------------- 1 | telegramApi.invokeApi('messages.getDialogs', { 2 | offset_peer: {_: 'inputPeerEmpty'}, 3 | offset_date: 0, 4 | limit: 20 5 | }).then(function(dialogResult) { 6 | /* Do something */ 7 | }); 8 | -------------------------------------------------------------------------------- /docs/examples/joinChat.js: -------------------------------------------------------------------------------- 1 | telegramApi.joinChat('https://telegram.me/joinchat/some-hash').then(function(updates) { 2 | // Do something 3 | }); 4 | -------------------------------------------------------------------------------- /docs/examples/logOut.js: -------------------------------------------------------------------------------- 1 | telegramApi.logOut().then(function() { 2 | setTimeout(function() { 3 | // Do something after logouts 4 | // Use setTimeout (It will be fixed) 5 | }, 1500); 6 | }); 7 | -------------------------------------------------------------------------------- /docs/examples/sendCode.js: -------------------------------------------------------------------------------- 1 | telegramApi.sendCode('some_phone_number').then(function(sent_code) { 2 | if (!sent_code.phone_registered) { 3 | // New user 4 | } 5 | 6 | // phone_code_hash will need to sign in or sign up 7 | window.phone_code_hash = sent_code.phone_code_hash; 8 | }); 9 | -------------------------------------------------------------------------------- /docs/examples/sendFile.js: -------------------------------------------------------------------------------- 1 | telegramApi.sendFile({ 2 | id: 123456789, 3 | type: 'user', 4 | file: $('input[type=file]').val(), 5 | caption: 'This is file' 6 | }).then(function(updates) { 7 | // Do something 8 | }); 9 | -------------------------------------------------------------------------------- /docs/examples/sendMessage.js: -------------------------------------------------------------------------------- 1 | telegramApi.sendMessage(9999999999, 'Hey man!').then(function(updates) { 2 | // Do something 3 | }); 4 | -------------------------------------------------------------------------------- /docs/examples/sendSms.js: -------------------------------------------------------------------------------- 1 | telegramApi.sendSms('some_phone_number', window.phone_code_hash).then(function() { 2 | // Do something 3 | }); 4 | -------------------------------------------------------------------------------- /docs/examples/setConfig.js: -------------------------------------------------------------------------------- 1 | telegramApi.setConfig({ 2 | app: { 3 | id: 0, /* App ID */ 4 | hash: 'qwertyasdfghzxcvbnqwertyasd', /* App hash */ 5 | version: '0.0.0' /* App version */ 6 | }, 7 | server: { 8 | test: [ 9 | { 10 | id: 2, /* DC ID */ 11 | host: '0.0.0.0', 12 | port: 443 13 | } 14 | ], 15 | production: [ 16 | { 17 | id: 2, /* DC ID */ 18 | host: '0.0.0.0', 19 | port: 123 20 | } 21 | ] 22 | } 23 | }); 24 | -------------------------------------------------------------------------------- /docs/examples/signIn.js: -------------------------------------------------------------------------------- 1 | telegramApi.signIn('some_phone_number', window.phone_code_hash, '000000').then(function() { 2 | // Sign in complete 3 | delete window.phone_code_hash; 4 | }, function(err) { 5 | switch (err.type) { 6 | case 'PHONE_CODE_INVALID': 7 | // alert "Phone code invalid" 8 | break; 9 | case 'PHONE_NUMBER_UNOCCUPIED': 10 | // User not registered, you should use signUp method 11 | break; 12 | } 13 | }); 14 | -------------------------------------------------------------------------------- /docs/examples/signUp.js: -------------------------------------------------------------------------------- 1 | telegramApi.signUp('some_phone_number', window.phone_code_hash, '000000', 'John', 'Doe').then(function() { 2 | // Sign up complete 3 | delete window.phone_code_hash; 4 | }); 5 | -------------------------------------------------------------------------------- /docs/examples/startBot.js: -------------------------------------------------------------------------------- 1 | telegramApi.startBot('exampleBot').then(function(updates) { 2 | // Was invoked telegramApi.sendMessage(bot.id, '/start'); 3 | }); 4 | -------------------------------------------------------------------------------- /docs/jsdoc-options.json: -------------------------------------------------------------------------------- 1 | { 2 | "files": "src/telegramApi.js", 3 | "param-list-format": "table" 4 | } 5 | -------------------------------------------------------------------------------- /example/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | Test Telegram App 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 |
17 |
18 |
19 |
20 |

Auth panel

21 | 22 | 23 |
24 |
25 | 26 |
27 |
28 | 29 |
30 |
31 |
32 | 33 |
34 |

Info panel

35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | 46 | 47 | 48 | 49 | 50 | 51 | 52 | 53 | 54 | 55 | 56 | 57 | 58 | 59 | 60 | 61 | 62 | 63 | 64 |
ID
Photo
First Name
Last Name
Username
Phone
65 | 66 | 67 | 68 | 69 |
70 | 71 |
72 | 76 | 79 |
80 | 81 |
82 |

Operations

83 |
84 |
85 |

Success

86 |
    87 |
  • 88 | {{item._}} 89 | A 90 | C 91 |
  • 92 |
93 |
94 |
95 |

Failed

96 |
    97 |
  • 98 | {{item.description}} 99 | A 100 | C 101 |
  • 102 |
103 |
104 |
105 |
106 |
107 |
108 |
109 |

Logs

110 |
    111 |
  • 112 | {{log._}} 113 | A 114 | C 115 |
  • 116 |
117 |
118 |
119 |
120 |
121 | 122 | 123 | 124 | 125 | 126 | 127 | -------------------------------------------------------------------------------- /example/script.js: -------------------------------------------------------------------------------- 1 | telegramApi.setConfig({ 2 | app: { 3 | id: 24939, 4 | hash: 'cf2f9913563b63810ca02d77d5d44f92', 5 | version: telegramApi.VERSION 6 | }, 7 | server: { 8 | test: [ 9 | { 10 | id: 2, 11 | host: '149.154.167.40', 12 | port: '443' 13 | } 14 | ], 15 | production: [ 16 | { 17 | id: 2, 18 | host: '149.154.167.50', 19 | port: '443' 20 | } 21 | ] 22 | } 23 | }); 24 | 25 | angular.module('myApp', []) 26 | .controller('mainCtrl', function ($scope) { 27 | angular.extend($scope, { 28 | update: function () { 29 | if ($scope._timeout) { 30 | return; 31 | } 32 | 33 | $scope._timeout = setTimeout(function () { 34 | delete $scope._timeout; 35 | $scope.$apply(); 36 | }, 0); 37 | }, 38 | visible: { 39 | auth: false, 40 | info: false 41 | }, 42 | auth: {}, 43 | info: {}, 44 | logs: [], 45 | success: [], 46 | failed: [], 47 | methods: [], 48 | json: function (obj, indent) { 49 | return JSON.stringify(obj, null, indent ? 4 : 0); 50 | }, 51 | showLog: function (log, type) { 52 | switch (type) { 53 | case 'console': 54 | console.log(log); 55 | break; 56 | case 'alert': 57 | alert(this.json(log, true)); 58 | break; 59 | } 60 | }, 61 | invokeMethod: function (method, params, onSuccess, onError) { 62 | telegramApi[method].apply(telegramApi, params).then(function (result) { 63 | $scope.success.push(result); 64 | $scope.update(); 65 | onSuccess && onSuccess(result); 66 | }, function (err) { 67 | $scope.failed.push(err); 68 | $scope.update(); 69 | onError && onError(err); 70 | }); 71 | } 72 | }); 73 | 74 | /* Auth methods */ 75 | $scope.auth.sendCode = function () { 76 | $scope.invokeMethod('sendCode', [$scope.auth.phone], function (sent_code) { 77 | $scope.phone_code_hash = sent_code.phone_code_hash; 78 | }); 79 | }; 80 | 81 | $scope.auth.signIn = function () { 82 | $scope.invokeMethod('signIn', [$scope.auth.phone, $scope.phone_code_hash, $scope.auth.code], function () { 83 | setTimeout(function () { 84 | window.location.reload(); 85 | }, 1000); 86 | }); 87 | }; 88 | 89 | /* Other methods */ 90 | $scope.info.logOut = function () { 91 | telegramApi.logOut().then(function () { 92 | // TODO: Без setTimeout 93 | setTimeout(function () { 94 | window.location.reload(); 95 | }, 1500); 96 | }); 97 | }; 98 | 99 | $scope.info.checkPhone = function (phone) { 100 | $scope.invokeMethod('checkPhone', [phone]); 101 | }; 102 | 103 | for (var key in telegramApi) { 104 | if (telegramApi.hasOwnProperty(key) && typeof telegramApi[key] == 'function') { 105 | $scope.methods.push(key); 106 | } 107 | } 108 | 109 | /* Initialize */ 110 | telegramApi.getUserInfo().then(function (user) { 111 | if (!user.id) { 112 | $scope.visible.auth = true; 113 | $scope.update(); 114 | } else { 115 | angular.extend($scope.info, user); 116 | $scope.visible.info = true; 117 | 118 | telegramApi.getUserPhoto('base64', 'small').then(function (base64) { 119 | $scope.info.photoBase64 = base64; 120 | $scope.update(); 121 | }); 122 | } 123 | }); 124 | 125 | telegramApi.subscribe('Test', function (message) { 126 | $scope.logs.push(message); 127 | $scope.update(); 128 | }); 129 | }); -------------------------------------------------------------------------------- /example/style.css: -------------------------------------------------------------------------------- 1 | .list-group, .dropdown-menu { 2 | max-height: 300px; 3 | overflow-y: scroll; 4 | } 5 | 6 | .badge { 7 | cursor: pointer; 8 | } -------------------------------------------------------------------------------- /gulpfile.js: -------------------------------------------------------------------------------- 1 | var gulp = require('gulp'); 2 | var $ = require('gulp-load-plugins')(); 3 | var version = require('./package.json').version; 4 | var about = require('fs') 5 | .readFileSync('./.files/about.txt', 'utf8') 6 | .replace('{VERSION}', version); 7 | 8 | gulp.task('clean', function () { 9 | return gulp.src([ 10 | 'example/js', 11 | 'dist/' 12 | ]).pipe($.clean({force: true})); 13 | }); 14 | 15 | gulp.task('js', function () { 16 | return gulp.src([ 17 | 'node_modules/long/dist/long.min.js', 18 | 'node_modules/zlibjs/bin/gunzip.min.js', 19 | 'node_modules/rusha/rusha.min.js', 20 | 'node_modules/ioc-js/dist/ioc-js.min.js', 21 | 22 | 'src/vendor/**/*.js', 23 | 'src/js/**/*.js', 24 | 25 | 'src/telegramApi.js', 26 | 'src/IoC.js' 27 | ]) 28 | .pipe($.concat('telegramApi.js')) 29 | .pipe($.replace(/<%TELEGRAM-API-VERSION%>/g, version)) 30 | .pipe($.wrapper({ 31 | header: about + '(function(){\n', 32 | footer: '\n})();' 33 | })) 34 | .pipe(gulp.dest('dist')) 35 | 36 | .pipe($.rename({suffix: '.min'})) 37 | .pipe($.uglify()) 38 | .pipe($.wrapper({header: about})) 39 | .pipe(gulp.dest('dist')); 40 | }); 41 | 42 | gulp.task('copy', function () { 43 | gulp.src('dist/**/*.js') 44 | .pipe(gulp.dest('example/js')); 45 | }); 46 | 47 | gulp.task('server', function () { 48 | gulp.src('example') 49 | .pipe($.webserver({open: true})); 50 | }); 51 | 52 | gulp.task('build', ['clean', 'js']); 53 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "telegram-api-js", 3 | "version": "1.2.9", 4 | "description": "JavaScript library for using Telegram API.", 5 | "repository": { 6 | "type": "git", 7 | "url": "https://github.com/sunriselink/TelegramApi.git" 8 | }, 9 | "author": { 10 | "name": "Infinnity Solutions", 11 | "email": "info@infinnity.ru" 12 | }, 13 | "contributors": [ 14 | { 15 | "name": "Maxim Sadofyev", 16 | "email": "m.sadofyev@infinnity.ru" 17 | }, 18 | { 19 | "name": "Dinara Zaripova", 20 | "email": "d.zaripova@infinnity.ru" 21 | } 22 | ], 23 | "license": "GPL-3.0", 24 | "keywords": [ 25 | "telegram", 26 | "telegramapi", 27 | "webogram", 28 | "infinnity", 29 | "infinnitysolutions" 30 | ], 31 | "scripts": { 32 | "build": "gulp build", 33 | "build-lib": "npm i && npm run build", 34 | "build-doc": "node docs/build.js", 35 | "example": "npm run build && gulp copy", 36 | "start": "npm run example && gulp server" 37 | }, 38 | "devDependencies": { 39 | "gulp": "^3.9.1", 40 | "gulp-clean": "^0.3.2", 41 | "gulp-concat": "^2.6.0", 42 | "gulp-load-plugins": "^1.3.0", 43 | "gulp-rename": "^1.2.2", 44 | "gulp-replace": "^0.5.4", 45 | "gulp-uglify": "^2.0.0", 46 | "gulp-webserver": "^0.9.1", 47 | "gulp-wrapper": "^1.0.0", 48 | "ioc-js": "0.0.4", 49 | "jsdoc-to-markdown": "^2.0.1", 50 | "long": "3.2.0", 51 | "rusha": "0.8.4", 52 | "zlibjs": "0.2.0" 53 | } 54 | } 55 | -------------------------------------------------------------------------------- /src/IoC.js: -------------------------------------------------------------------------------- 1 | // Create container 2 | var builder = new ContainerModule(); 3 | 4 | // Register App modules 5 | builder.register('AppChatsManager', AppChatsManagerModule); 6 | builder.register('AppPeersManager', AppPeersManagerModule); 7 | builder.register('AppProfileManager', AppProfileManagerModule); 8 | builder.register('AppUsersManager', AppUsersManagerModule); 9 | 10 | // Register Mtp modules 11 | builder.register('MtpApiFileManager', MtpApiFileManagerModule); 12 | builder.register('MtpApiManager', MtpApiManagerModule); 13 | builder.register('MtpAuthorizer', MtpAuthorizerModule); 14 | builder.register('MtpDcConfigurator', MtpDcConfiguratorModule); 15 | builder.register('MtpNetworkerFactory', MtpNetworkerFactoryModule); 16 | builder.register('MtpRsaKeysManager', MtpRsaKeysManagerModule); 17 | builder.register('MtpSecureRandom', MtpSecureRandomModule); 18 | builder.register('MtpSingleInstanceService', MtpSingleInstanceServiceModule); 19 | builder.register('MtpTimeManager', MtpTimeManagerModule); 20 | 21 | // Register Angular modules 22 | builder.register('$http', $httpModule); 23 | builder.register('$interval', $intervalModule); 24 | builder.register('$q', $qModule); 25 | builder.register('$rootScope', $rootScopeModule); 26 | builder.register('$timeout', $timeoutModule); 27 | 28 | // Register other modules 29 | builder.register('CryptoWorker', CryptoWorkerModule); 30 | builder.register('IdleManager', IdleManagerModule); 31 | builder.register('qSync', qSyncModule); 32 | builder.register('Storage', StorageModule); 33 | builder.register('TelegramMeWebService', TelegramMeWebServiceModule); 34 | builder.register('jQuery', jQueryModule); 35 | builder.register('FileSaver', FileSaverModule); 36 | 37 | // Register TelegramApi module 38 | builder.register('TelegramApi', TelegramApiModule); 39 | 40 | // Initialize modules 41 | builder.init(); 42 | 43 | // Resolve TelegramApi 44 | window.telegramApi = builder.resolve('TelegramApi'); 45 | -------------------------------------------------------------------------------- /src/js/App/AppChatsManager.js: -------------------------------------------------------------------------------- 1 | function AppChatsManagerModule() { 2 | var chats = {}, 3 | channelAccess = {}; 4 | 5 | function saveApiChats(apiChats) { 6 | forEach(apiChats, saveApiChat); 7 | } 8 | 9 | function saveApiChat(apiChat) { 10 | if (!isObject(apiChat)) { 11 | return; 12 | } 13 | 14 | apiChat.num = (Math.abs(apiChat.id >> 1) % 8) + 1; 15 | 16 | if (apiChat.pFlags === undefined) { 17 | apiChat.pFlags = {}; 18 | } 19 | 20 | if (chats[apiChat.id] === undefined) { 21 | chats[apiChat.id] = apiChat; 22 | } else { 23 | safeReplaceObject(chats[apiChat.id], apiChat); 24 | } 25 | } 26 | 27 | function getChat(id) { 28 | return chats[id] || {id: id, deleted: true, access_hash: channelAccess[id]}; 29 | } 30 | 31 | function isChannel(id) { 32 | var chat = chats[id]; 33 | 34 | return chat && (chat._ == 'channel' || chat._ == 'channelForbidden') || channelAccess[id]; 35 | } 36 | 37 | function getChatInput(id) { 38 | return id || 0; 39 | } 40 | 41 | function getChannelInput(id) { 42 | if (!id) { 43 | return {_: 'inputChannelEmpty'}; 44 | } 45 | return { 46 | _: 'inputChannel', 47 | channel_id: id, 48 | access_hash: getChat(id).access_hash || channelAccess[id] || 0 49 | } 50 | } 51 | 52 | return { 53 | saveApiChats: saveApiChats, 54 | saveApiChat: saveApiChat, 55 | getChat: getChat, 56 | isChannel: isChannel, 57 | getChatInput: getChatInput, 58 | getChannelInput: getChannelInput 59 | }; 60 | } 61 | 62 | AppChatsManagerModule.dependencies = []; 63 | -------------------------------------------------------------------------------- /src/js/App/AppPeersManager.js: -------------------------------------------------------------------------------- 1 | function AppPeersManagerModule(AppChatsManager, AppUsersManager) { 2 | function getInputPeerByID(peerID) { 3 | if (!peerID) { 4 | return {_: 'inputPeerEmpty'}; 5 | } 6 | if (peerID < 0) { 7 | var chatID = -peerID; 8 | if (!AppChatsManager.isChannel(chatID)) { 9 | return { 10 | _: 'inputPeerChat', 11 | chat_id: chatID 12 | }; 13 | } else { 14 | return { 15 | _: 'inputPeerChannel', 16 | channel_id: chatID, 17 | access_hash: AppChatsManager.getChat(chatID).access_hash || 0 18 | } 19 | } 20 | } 21 | return { 22 | _: 'inputPeerUser', 23 | user_id: peerID, 24 | access_hash: AppUsersManager.getUser(peerID).access_hash || 0 25 | }; 26 | } 27 | 28 | function getPeerID(peerString) { 29 | if (isObject(peerString)) { 30 | return peerString.user_id 31 | ? peerString.user_id 32 | : -(peerString.channel_id || peerString.chat_id); 33 | } 34 | var isUser = peerString.charAt(0) == 'u', 35 | peerParams = peerString.substr(1).split('_'); 36 | 37 | return isUser ? peerParams[0] : -peerParams[0] || 0; 38 | } 39 | 40 | function getPeer(peerID) { 41 | return peerID > 0 42 | ? AppUsersManager.getUser(peerID) 43 | : AppChatsManager.getChat(-peerID); 44 | } 45 | 46 | function isChannel(peerID) { 47 | return (peerID < 0) && AppChatsManager.isChannel(-peerID); 48 | } 49 | 50 | return { 51 | getInputPeerByID: getInputPeerByID, 52 | getPeerID: getPeerID, 53 | getPeer: getPeer, 54 | isChannel: isChannel 55 | }; 56 | } 57 | 58 | AppPeersManagerModule.dependencies = [ 59 | 'AppChatsManager', 60 | 'AppUsersManager' 61 | ]; 62 | -------------------------------------------------------------------------------- /src/js/App/AppProfileManager.js: -------------------------------------------------------------------------------- 1 | function AppProfileManagerModule(AppChatsManager, AppUsersManager, MtpApiManager, $q) { 2 | var chatsFull = {}; 3 | var chatFullPromises = {}; 4 | 5 | function getChatFull(id) { 6 | if (AppChatsManager.isChannel(id)) { 7 | return getChannelFull(id); 8 | } 9 | if (chatsFull[id] !== undefined) { 10 | var chat = AppChatsManager.getChat(id); 11 | if (chat.version == chatsFull[id].participants.version || 12 | chat.pFlags.left) { 13 | return $q.when(chatsFull[id]); 14 | } 15 | } 16 | if (chatFullPromises[id] !== undefined) { 17 | return chatFullPromises[id]; 18 | } 19 | console.trace(dT(), 'Get chat full', id, AppChatsManager.getChat(id)); 20 | return chatFullPromises[id] = MtpApiManager.invokeApi('messages.getFullChat', { 21 | chat_id: AppChatsManager.getChatInput(id) 22 | }).then(function (result) { 23 | AppChatsManager.saveApiChats(result.chats); 24 | AppUsersManager.saveApiUsers(result.users); 25 | var fullChat = result.full_chat; 26 | delete chatFullPromises[id]; 27 | chatsFull[id] = fullChat; 28 | 29 | return fullChat; 30 | }); 31 | } 32 | 33 | function getChatInviteLink(id, force) { 34 | return getChatFull(id).then(function (chatFull) { 35 | if (!force && 36 | chatFull.exported_invite && 37 | chatFull.exported_invite._ == 'chatInviteExported') { 38 | return chatFull.exported_invite.link; 39 | } 40 | var promise; 41 | if (AppChatsManager.isChannel(id)) { 42 | promise = MtpApiManager.invokeApi('channels.exportInvite', { 43 | channel: AppChatsManager.getChannelInput(id) 44 | }); 45 | } else { 46 | promise = MtpApiManager.invokeApi('messages.exportChatInvite', { 47 | chat_id: AppChatsManager.getChatInput(id) 48 | }); 49 | } 50 | return promise.then(function (exportedInvite) { 51 | if (chatsFull[id] !== undefined) { 52 | chatsFull[id].exported_invite = exportedInvite; 53 | } 54 | return exportedInvite.link; 55 | }); 56 | }); 57 | } 58 | 59 | function getChannelParticipants(id) { 60 | return MtpApiManager.invokeApi('channels.getParticipants', { 61 | channel: AppChatsManager.getChannelInput(id), 62 | filter: {_: 'channelParticipantsRecent'}, 63 | offset: 0, 64 | limit: 200 65 | }).then(function (result) { 66 | AppUsersManager.saveApiUsers(result.users); 67 | var participants = result.participants; 68 | 69 | var chat = AppChatsManager.getChat(id); 70 | if (!chat.pFlags.kicked && !chat.pFlags.left) { 71 | var myID = AppUsersManager.getSelf().id; 72 | var myIndex = false; 73 | var myParticipant; 74 | for (var i = 0, len = participants.length; i < len; i++) { 75 | if (participants[i].user_id == myID) { 76 | myIndex = i; 77 | break; 78 | } 79 | } 80 | if (myIndex !== false) { 81 | myParticipant = participants[i]; 82 | participants.splice(i, 1); 83 | } else { 84 | myParticipant = {_: 'channelParticipantSelf', user_id: myID}; 85 | } 86 | participants.unshift(myParticipant); 87 | } 88 | 89 | return participants; 90 | }); 91 | } 92 | 93 | function getChannelFull(id, force) { 94 | if (chatsFull[id] !== undefined && !force) { 95 | return $q.when(chatsFull[id]); 96 | } 97 | if (chatFullPromises[id] !== undefined) { 98 | return chatFullPromises[id]; 99 | } 100 | 101 | return chatFullPromises[id] = MtpApiManager.invokeApi('channels.getFullChannel', { 102 | channel: AppChatsManager.getChannelInput(id) 103 | }).then(function (result) { 104 | AppChatsManager.saveApiChats(result.chats); 105 | AppUsersManager.saveApiUsers(result.users); 106 | var fullChannel = result.full_chat; 107 | var chat = AppChatsManager.getChat(id); 108 | var participantsPromise; 109 | if (fullChannel.flags & 8) { 110 | participantsPromise = getChannelParticipants(id).then(function (participants) { 111 | delete chatFullPromises[id]; 112 | fullChannel.participants = { 113 | _: 'channelParticipants', 114 | participants: participants 115 | }; 116 | }, function (error) { 117 | error.handled = true; 118 | }); 119 | } else { 120 | participantsPromise = $q.when(); 121 | } 122 | return participantsPromise.then(function () { 123 | delete chatFullPromises[id]; 124 | chatsFull[id] = fullChannel; 125 | 126 | return fullChannel; 127 | }); 128 | }, function (error) { 129 | return $q.reject(error); 130 | }); 131 | } 132 | 133 | return { 134 | getChatInviteLink: getChatInviteLink 135 | }; 136 | } 137 | 138 | AppProfileManagerModule.dependencies = [ 139 | 'AppChatsManager', 140 | 'AppUsersManager', 141 | 'MtpApiManager', 142 | '$q' 143 | ]; 144 | -------------------------------------------------------------------------------- /src/js/App/AppUsersManager.js: -------------------------------------------------------------------------------- 1 | function AppUsersManagerModule(Storage, MtpApiManager) { 2 | var users = {}, 3 | userAccess = {}, 4 | myID, 5 | serverTimeOffset = 0; 6 | 7 | Storage.get('server_time_offset').then(function (to) { 8 | if (to) { 9 | serverTimeOffset = to; 10 | } 11 | }); 12 | 13 | MtpApiManager.getUserID().then(function (id) { 14 | myID = id; 15 | }); 16 | 17 | function saveApiUsers(apiUsers) { 18 | forEach(apiUsers, saveApiUser); 19 | } 20 | 21 | function saveApiUser(apiUser, noReplace) { 22 | if (!isObject(apiUser) || noReplace && isObject(users[apiUser.id]) && users[apiUser.id].first_name) { 23 | return; 24 | } 25 | 26 | var userID = apiUser.id; 27 | 28 | apiUser.num = (Math.abs(userID) % 8) + 1; 29 | 30 | if (apiUser.pFlags === undefined) { 31 | apiUser.pFlags = {}; 32 | } 33 | 34 | if (apiUser.status) { 35 | if (apiUser.status.expires) { 36 | apiUser.status.expires -= serverTimeOffset; 37 | } 38 | if (apiUser.status.was_online) { 39 | apiUser.status.was_online -= serverTimeOffset; 40 | } 41 | } 42 | if (apiUser.pFlags.bot) { 43 | apiUser.sortStatus = -1; 44 | } else { 45 | apiUser.sortStatus = getUserStatusForSort(apiUser.status); 46 | } 47 | 48 | var result = users[userID]; 49 | 50 | if (result === undefined) { 51 | result = users[userID] = apiUser; 52 | } else { 53 | safeReplaceObject(result, apiUser); 54 | } 55 | } 56 | 57 | function getUserStatusForSort(status) { 58 | if (status) { 59 | var expires = status.expires || status.was_online; 60 | if (expires) { 61 | return expires; 62 | } 63 | var timeNow = tsNow(true); 64 | switch (status._) { 65 | case 'userStatusRecently': 66 | return timeNow - 86400 * 3; 67 | case 'userStatusLastWeek': 68 | return timeNow - 86400 * 7; 69 | case 'userStatusLastMonth': 70 | return timeNow - 86400 * 30; 71 | } 72 | } 73 | 74 | return 0; 75 | } 76 | 77 | function getUser(id) { 78 | if (isObject(id)) { 79 | return id; 80 | } 81 | return users[id] || {id: id, deleted: true, num: 1, access_hash: userAccess[id]}; 82 | } 83 | 84 | function getSelf() { 85 | return getUser(myID); 86 | } 87 | 88 | function getUserInput(id) { 89 | var user = getUser(id); 90 | if (user.pFlags.self) { 91 | return {_: 'inputUserSelf'}; 92 | } 93 | return { 94 | _: 'inputUser', 95 | user_id: id, 96 | access_hash: user.access_hash || 0 97 | }; 98 | } 99 | 100 | return { 101 | saveApiUsers: saveApiUsers, 102 | saveApiUser: saveApiUser, 103 | getUser: getUser, 104 | getSelf: getSelf, 105 | getUserInput: getUserInput 106 | }; 107 | } 108 | 109 | AppUsersManagerModule.dependencies = [ 110 | 'Storage', 111 | 'MtpApiManager' 112 | ]; 113 | -------------------------------------------------------------------------------- /src/js/Etc/CryptoWorker.js: -------------------------------------------------------------------------------- 1 | function CryptoWorkerModule($timeout) { 2 | return { 3 | sha1Hash: function (bytes) { 4 | return $timeout(function () { 5 | return sha1HashSync(bytes); 6 | }); 7 | }, 8 | sha256Hash: function (bytes) { 9 | return $timeout(function () { 10 | return sha256HashSync(bytes); 11 | }); 12 | }, 13 | aesEncrypt: function (bytes, keyBytes, ivBytes) { 14 | return $timeout(function () { 15 | return convertToArrayBuffer(aesEncryptSync(bytes, keyBytes, ivBytes)); 16 | }); 17 | }, 18 | aesDecrypt: function (encryptedBytes, keyBytes, ivBytes) { 19 | return $timeout(function () { 20 | return convertToArrayBuffer(aesDecryptSync(encryptedBytes, keyBytes, ivBytes)); 21 | }); 22 | }, 23 | factorize: function (bytes) { 24 | bytes = convertToByteArray(bytes); 25 | 26 | return $timeout(function () { 27 | return pqPrimeFactorization(bytes); 28 | }); 29 | }, 30 | modPow: function (x, y, m) { 31 | return $timeout(function () { 32 | return bytesModPow(x, y, m); 33 | }); 34 | } 35 | }; 36 | } 37 | 38 | CryptoWorkerModule.dependencies = [ 39 | '$timeout' 40 | ]; 41 | -------------------------------------------------------------------------------- /src/js/Etc/FileSaver.js: -------------------------------------------------------------------------------- 1 | function FileSaverModule($timeout) { 2 | function save(bytes, fileName) { 3 | // TODO: Improve 4 | var a = document.createElement('a'); 5 | var blob = new Blob(bytes, {type: 'octet/stream'}); 6 | 7 | if (window.navigator && window.navigator.msSaveBlob) { 8 | window.navigator.msSaveBlob(blob, fileName); 9 | return; 10 | } 11 | 12 | document.body.appendChild(a); 13 | 14 | a.style = 'display: none'; 15 | a.href = window.URL.createObjectURL(blob); 16 | a.download = fileName; 17 | a.click(); 18 | 19 | $timeout(function() { 20 | window.URL.revokeObjectURL(a.href); 21 | a.remove(); 22 | }, 100); 23 | } 24 | 25 | return { 26 | save: save 27 | }; 28 | } 29 | 30 | FileSaverModule.dependencies = [ 31 | '$timeout' 32 | ]; 33 | -------------------------------------------------------------------------------- /src/js/Etc/Helper.js: -------------------------------------------------------------------------------- 1 | function forEach(obj, iterator, context) { 2 | if (!obj) { 3 | return; 4 | } 5 | 6 | if (isArray(obj)) { 7 | if (obj.forEach) { 8 | obj.forEach(iterator, context, obj); 9 | } else { 10 | for (var i = 0; i < obj.length; i++) { 11 | iterator.call(context, obj[i], i, obj); 12 | } 13 | } 14 | } else if (isObject(obj)) { 15 | for (var key in obj) { 16 | iterator.call(context, obj[key], key, obj); 17 | } 18 | } 19 | } 20 | 21 | function isObject(value) { 22 | return value !== null && typeof value === 'object'; 23 | } 24 | 25 | function isString(value) { 26 | return typeof value == 'string'; 27 | } 28 | 29 | function isArray(value) { 30 | return Array.isArray(value); 31 | } 32 | 33 | function isFunction(value) { 34 | return typeof value == 'function'; 35 | } 36 | 37 | function extend() { 38 | var objects = toArray(arguments); 39 | var obj = objects[0]; 40 | 41 | for (var i = 1; i < objects.length; i++) { 42 | for (var key in objects[i]) { 43 | obj[key] = objects[i][key]; 44 | } 45 | } 46 | 47 | return obj; 48 | } 49 | 50 | function map(array, iterator) { 51 | var result = []; 52 | 53 | forEach(array, function (obj) { 54 | result.push(iterator(obj)); 55 | }); 56 | 57 | return result; 58 | } 59 | 60 | function min(array) { 61 | var min = array[0]; 62 | 63 | forEach(array, function (obj) { 64 | if (obj < min) { 65 | min = obj; 66 | } 67 | }); 68 | 69 | return min; 70 | } 71 | function toArray(obj) { 72 | return Array.prototype.slice.call(obj); 73 | } 74 | 75 | function noop() { 76 | 77 | } 78 | -------------------------------------------------------------------------------- /src/js/Etc/IdleManager.js: -------------------------------------------------------------------------------- 1 | function IdleManagerModule($rootScope, $timeout, $) { 2 | $rootScope.idle = {isIDLE: false}; 3 | 4 | var toPromise, started = false; 5 | var hidden = 'hidden'; 6 | var visibilityChange = 'visibilitychange'; 7 | 8 | if (typeof document.hidden !== 'undefined') { 9 | // default 10 | } else if (typeof document.mozHidden !== 'undefined') { 11 | hidden = 'mozHidden'; 12 | visibilityChange = 'mozvisibilitychange'; 13 | } else if (typeof document.msHidden !== 'undefined') { 14 | hidden = 'msHidden'; 15 | visibilityChange = 'msvisibilitychange'; 16 | } else if (typeof document.webkitHidden !== 'undefined') { 17 | hidden = 'webkitHidden'; 18 | visibilityChange = 'webkitvisibilitychange'; 19 | } 20 | 21 | return { 22 | start: start 23 | }; 24 | 25 | function start() { 26 | if (!started) { 27 | started = true; 28 | $(window).on(visibilityChange + ' blur focus keydown mousedown touchstart', onEvent); 29 | 30 | setTimeout(function () { 31 | onEvent({type: 'blur'}); 32 | }, 0); 33 | } 34 | } 35 | 36 | function onEvent(e) { 37 | // console.log('event', e.type); 38 | if (e.type == 'mousemove') { 39 | var e = e.originalEvent || e; 40 | if (e && e.movementX === 0 && e.movementY === 0) { 41 | return; 42 | } 43 | $(window).off('mousemove', onEvent); 44 | } 45 | 46 | var isIDLE = e.type == 'blur' || e.type == 'timeout' ? true : false; 47 | if (hidden && document[hidden]) { 48 | isIDLE = true; 49 | } 50 | 51 | $timeout.cancel(toPromise); 52 | if (!isIDLE) { 53 | // console.log('update timeout'); 54 | toPromise = $timeout(function () { 55 | onEvent({type: 'timeout'}); 56 | }, 30000); 57 | } 58 | 59 | if (isIDLE && e.type == 'timeout') { 60 | $(window).on('mousemove', onEvent); 61 | } 62 | } 63 | } 64 | 65 | IdleManagerModule.dependencies = [ 66 | '$rootScope', 67 | '$timeout', 68 | 'jQuery' 69 | ]; 70 | -------------------------------------------------------------------------------- /src/js/Etc/Storage.js: -------------------------------------------------------------------------------- 1 | function StorageModule($q) { 2 | var methods = {}; 3 | 4 | forEach(['get', 'set', 'remove'], function (methodName) { 5 | methods[methodName] = function () { 6 | var deferred = $q.defer(), 7 | args = toArray(arguments); 8 | 9 | args.push(function (result) { 10 | deferred.resolve(result); 11 | }); 12 | 13 | ConfigStorage[methodName].apply(ConfigStorage, args); 14 | 15 | return deferred.promise; 16 | }; 17 | }); 18 | 19 | return methods; 20 | } 21 | 22 | StorageModule.dependencies = [ 23 | '$q' 24 | ]; 25 | -------------------------------------------------------------------------------- /src/js/Etc/TelegramMeWebService.js: -------------------------------------------------------------------------------- 1 | function TelegramMeWebServiceModule(Storage, $) { 2 | var disabled = location.protocol != 'http:' && location.protocol != 'https:'; 3 | 4 | function sendAsyncRequest(canRedirect) { 5 | if (disabled) { 6 | return false; 7 | } 8 | 9 | Storage.get('tgme_sync').then(function (curValue) { 10 | var ts = tsNow(true); 11 | if (canRedirect && 12 | curValue && 13 | curValue.canRedirect == canRedirect && 14 | curValue.ts + 86400 > ts) { 15 | return false; 16 | } 17 | Storage.set({tgme_sync: {canRedirect: canRedirect, ts: ts}}); 18 | 19 | var script = $('