2

I need to get public url for file with telegram bot API. The problem with getFile method that it returns url in following format: https://api.telegram.org/file/bot<token>/<file_path> meaning I can't really share it in public because it contains my bot token, sharing this url wouldn't be secure.

Is it possible to get public url for file id that does not have my bot token in it? What are the alternatives?

FamousSnake
  • 328
  • 4
  • 11
  • I asked similar question in a Bot Support channel and they said you need to download the file and serve/stream it again. Did you find another solution or anyone reading this question has a better approach? – user2174111 Jun 07 '20 at 17:27

1 Answers1

0

I have created the following solution as a Proof Of Concept. Please check: https://gist.github.com/gilpanal/099ff5fc94366fbaabd5e2fbedc7c86f

The idea is that you access to the binary data of your file through an intermediate API where your token is safe.

/*** server.js ***/
/* TESTED WITH NODE VERSION 14+ */

const express = require('express')
const app = express()
const https = require('https')
const port = process.env.PORT || 3000

// Use an Environment Variable to Secure Token Value
const BOT_TOKEN = <BOT_SECRET_TOKEN>
// For better CORS: https://expressjs.com/en/resources/middleware/cors.html
app.use( (req, res, next)  => {
    res.header('Access-Control-Allow-Origin', '*')
    res.header('Access-Control-Allow-Headers', 'Origin, X-Requested-With, Content-Type, Accept')
    next()
})

app.get('/', (req, res) => {
    res.sendStatus(200)
})

// Inspired by: https://stackoverflow.com/a/21024737
app.get('/fileDownload', (req, res) => {
    let uploadResponse = { ok: false, result: null, error: 404, description: 'Not Found' }
    if (req._parsedUrl && req._parsedUrl.query) {        
        const tel_file_path = 'https://api.telegram.org/file/bot' + BOT_TOKEN + req._parsedUrl.query
        https.get(tel_file_path, (response) => {
            const data = []
            response.on('data', (chunk) => {
                data.push(chunk)
            }).on('end', () => {                
                const buffer = Buffer.concat(data)
                res.send(buffer)
            })
        })
    } else {
        res.sendStatus(uploadResponse)
    }
})

app.listen(port)

/*** app.js ***/
const TEL_PATH = '/music/file_352.mp3'
const API_FILEDONWLOAD = 'http://localhost:3000/fileDownload?'

const load = () => {

    return new Promise((resolve, reject) => {
        const xhr = new XMLHttpRequest()

        xhr.open('GET', API_FILEDONWLOAD + TEL_PATH, true)
        xhr.responseType = 'arraybuffer'
        xhr.send()

        xhr.addEventListener('progress', (e) => {
            console.log(`${e.type}: ${e.loaded} bytes transferred\n`)            
        })

        xhr.addEventListener('load', (e) => {            
            const audioData = e.target.response || e.target.result
            resolve(audioData)            
        })

        xhr.addEventListener('error', () => {
            reject(Error('Track ' + TEL_PATH + ' failed to load'))
        })
    })
}

load().then((audiData) => {
    console.log(audiData)
}).catch((err) =>{
    console.log(err)
})
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Document</title>
</head>
<body>
    BODY
    <script src="app.js"></script>
</body>
</html>
user2174111
  • 83
  • 1
  • 6