require 'openssl' require 'base64' require 'json' module Fastlane module PageGenerator def self.mail(config) UI.message("Generating e-mail...") eth = Fastlane::ErbTemplateHelper html_template = eth.load_from_path("#{__dir__}/../templates/download.erb") eth.render(html_template, { author: config[:author], last_commit: config[:last_commit], is_android: config[:is_android], app_icon: config[:app_icon] ? "cid:#{config[:app_icon]}" : "https://s3.eu-central-1.amazonaws.com/fota.polidea.com/mails/images/icon-placeholder.png", app_name: config[:app_name], app_version: config[:app_version], build_number: config[:build_number], installation_link: config[:installation_link], release_notes: parse_release_notes(config[:release_notes]), platform: config[:platform], release_date: config[:release_date], binary_size: config[:binary_size], qr_code: "cid:#{config[:qr_code]}" }) end def self.installation_page(config) if config[:installation_password] generate_private(config) else generate_public(config) end end def self.generate_private(config) UI.message("Generating private installation page with password `#{config[:installation_password]}`...") eth = Fastlane::ErbTemplateHelper html_template = eth.load_from_path("#{__dir__}/../templates/secure_installation_template.erb") installation_link, salt, iv = encrypt(config[:url], config[:installation_password]) eth.render(html_template, { url: installation_link, salt: salt, iv: iv, app_version: config[:app_version], build_number: config[:build_number], app_name: config[:app_name], app_icon: config[:app_icon], platform: config[:platform], release_notes: parse_release_notes(config[:release_notes]) }) end private_class_method :generate_private def self.generate_public(config) UI.message("Generating public installation page...") eth = Fastlane::ErbTemplateHelper html_template = eth.load_from_path("#{__dir__}/../templates/installation_template.erb") eth.render(html_template, { url: config[:url], app_version: config[:app_version], build_number: config[:build_number], app_name: config[:app_name], app_icon: config[:app_icon], platform: config[:platform], release_notes: parse_release_notes(config[:release_notes]) }) end private_class_method :generate_public def self.encrypt(url, password) salt = OpenSSL::Random.random_bytes(32) iter = 128 key_len = 32 key = OpenSSL::PKCS5.pbkdf2_hmac_sha1(password, salt, iter, key_len) cipher = OpenSSL::Cipher::AES256.new(:CBC) cipher.encrypt cipher.key = key random_iv = cipher.random_iv iv = Base64.encode64(random_iv).delete "\n" to_json = { url: url.to_s }.to_json var = cipher.update(to_json.to_s) + cipher.final installation_link = Base64.encode64(var).delete "\n" salt = Base64.encode64(salt).delete "\n" return installation_link, salt, iv end private_class_method :encrypt def self.parse_release_notes(release_notes) renderer = Redcarpet::Render::HTML.new({ filter_html: true, no_styles: true }) markdown = Redcarpet::Markdown.new( renderer, fenced_code_blocks: true, autolink: false, tables: false ) markdown.render(release_notes || "No release notes.") end private_class_method :parse_release_notes end end