{"version":3,"file":"index.mjs","sources":["../src/deferPromise.ts","../src/normalizeProfile.ts","../src/strategy.ts"],"sourcesContent":["export default function deferPromise() {\n  let resolve\n  let reject\n  const promise = new Promise((_resolve, _reject) => {\n    resolve = _resolve\n    reject = _reject\n  })\n\n  return {\n    then: f => promise.then(f),\n    callback: (err, ...data) => (err ? reject(err) : resolve(data)),\n    promise,\n  }\n}\n","import { PassportTelegramUser, TelegramUser } from './types'\n\nexport function normalizeProfile(profile: TelegramUser): PassportTelegramUser {\n  const normalizedProfile: PassportTelegramUser = {\n    ...profile,\n    provider: 'telegram',\n    displayName: profile.username,\n    name: {\n      givenName: profile.first_name,\n      familyName: profile.last_name,\n    },\n    photos: profile.photo_url ? [{ value: profile.photo_url }] : [],\n  }\n\n  return normalizedProfile\n}\n","import * as crypto                         from 'crypto'\nimport { Request }                         from 'express'\nimport { Strategy }                        from 'passport-strategy'\n\nimport deferPromise                        from './deferPromise'\nimport { normalizeProfile }                from './normalizeProfile'\nimport { TelegramOptions, VerifyCallback } from './types'\n\nexport const defaultOptions = {\n  queryExpiration: 86400,\n  passReqToCallback: false,\n}\n\nexport const whitelistParams = [\n  'id',\n  'first_name',\n  'last_name',\n  'username',\n  'photo_url',\n  'auth_date',\n]\n\n/**\n * `TelegramStrategy` constructor.\n *\n * The Telegram authentication strategy authenticates requests by delegating to\n * Telegram using their protocol: https://core.telegram.org/widgets/login\n *\n * Applications must supply a `verify` callback which accepts an `account` object,\n * and then calls `done` callback sypplying a `user`, which should be set to `false` if the\n * credentials are not valid.  If an exception occurred, `error` should be set.\n *\n * More info here: https://core.telegram.org/widgets/login\n *\n * @param {Object} options\n * @param {Function} verify\n * @example\n * passport.use(new TelegramStrategy({\n *   botId: 12434151\n * }), (user) => {\n *   User.findOrCreate({telegramId: user.id}, done);\n * });\n */\nexport default class TelegramStrategy extends Strategy {\n  readonly name: string = 'telegram'\n\n  readonly options: TelegramOptions\n\n  protected readonly verify\n\n  protected readonly hashedBotToken: Buffer\n\n  constructor(options: TelegramOptions, verify: VerifyCallback) {\n    super()\n\n    if (!options.botToken) {\n      throw new TypeError('options.botToken is required in TelegramStrategy')\n    }\n    if (!verify) {\n      throw new TypeError('LocalStrategy requires a verify callback')\n    }\n\n    this.options = {\n      ...defaultOptions,\n      ...options,\n    }\n\n    this.verify = verify\n    this.hashedBotToken = this.getBotToken()\n  }\n\n  // eslint-disable-next-line consistent-return\n  authenticate(req: Request, options?: any) {\n    const query = req.method === 'GET' ? req.query : req.body\n\n    try {\n      const validationResult = this.validateQuery(req)\n      if (validationResult !== true) {\n        return validationResult\n      }\n\n      const profile = normalizeProfile(query)\n      const promise = deferPromise()\n\n      if (this.options.passReqToCallback) {\n        this.verify(req, profile, promise.callback)\n      } else {\n        this.verify(profile, promise.callback)\n      }\n\n      promise\n        .then(([user, info]) => {\n          if (!user) {\n            return this.fail(info)\n          }\n\n          return this.success(user, info)\n        })\n        .catch(err => {\n          return this.error(err)\n        })\n    } catch (e) {\n      return this.error(e)\n    }\n  }\n\n  /**\n   * Function to check if provided date in callback is outdated\n   * @returns {number}\n   */\n  protected getTimestamp(): number {\n    return Math.floor(Date.now() / 1000)\n  }\n\n  // We have to hash botToken too\n  protected getBotToken(): Buffer {\n    return crypto.createHash('sha256').update(this.options.botToken).digest()\n  }\n\n  /**\n   * Used to validate if fields like telegram must send are exists\n   * @param {e.Request} req\n   * @returns {any}\n   */\n  validateQuery(req: Request): boolean | void {\n    const query = req.method === 'GET' ? req.query : req.body\n\n    if (!query.auth_date || !query.hash || !query.id) {\n      return this.fail({ message: 'Missing some important data' }, 400)\n    }\n\n    const authDate = Math.floor(Number(query.auth_date))\n    if (\n      this.options.queryExpiration !== -1 &&\n      (Number.isNaN(authDate) || this.getTimestamp() - authDate > this.options.queryExpiration)\n    ) {\n      return this.fail({ message: 'Data is outdated' }, 400)\n    }\n\n    const sorted = Object.keys(query).sort()\n    const mapped = sorted // Only whitelisted query parameters must be mapped\n      .filter(d => whitelistParams.includes(d))\n      .map(key => `${key}=${query[key]}`)\n\n    const hashString = mapped.join('\\n')\n    const hash = crypto.createHmac('sha256', this.hashedBotToken).update(hashString).digest('hex')\n\n    if (hash !== query.hash) {\n      return this.fail({ message: 'Hash validation failed' }, 403)\n    }\n\n    return true\n  }\n}\n"],"names":["deferPromise","resolve","reject","promise","Promise","_resolve","_reject","then","f","callback","err","data","normalizeProfile","profile","normalizedProfile","provider","displayName","username","name","givenName","first_name","familyName","last_name","photos","photo_url","value","defaultOptions","queryExpiration","passReqToCallback","whitelistParams","TelegramStrategy","Strategy","constructor","options","verify","hashedBotToken","botToken","TypeError","getBotToken","authenticate","req","query","method","body","validationResult","validateQuery","user","info","fail","success","catch","error","e","getTimestamp","Math","floor","Date","now","crypto","createHash","update","digest","auth_date","hash","id","message","authDate","Number","isNaN","sorted","Object","keys","sort","mapped","filter","d","includes","map","key","hashString","join","createHmac"],"mappings":"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"}