From 370a9ec0cf52fae714c936436b10910ba66839c4 Mon Sep 17 00:00:00 2001 From: Conor Horan-Kates Date: Mon, 28 Nov 2016 17:04:52 -0800 Subject: [PATCH] cleanup on impersonation --- lg_webOS/impersonate-lge.com.rb | 110 ++++++++++++++++++++++---------- lg_webOS/json-list.rb | 4 +- lg_webOS/webos.paw | Bin 5625 -> 16876 bytes 3 files changed, 79 insertions(+), 35 deletions(-) diff --git a/lg_webOS/impersonate-lge.com.rb b/lg_webOS/impersonate-lge.com.rb index f49f160..e3e5579 100644 --- a/lg_webOS/impersonate-lge.com.rb +++ b/lg_webOS/impersonate-lge.com.rb @@ -1,8 +1,7 @@ #/usr/bin/env ruby ## impersonate-lge.com.rb - fake version of *.lge.com -# serving a cooked version of busybox and base-files - +require 'base64' require 'sinatra' port = ENV['USER'].eql?('root') ? 80 : 8080 @@ -15,37 +14,42 @@ set :public_folder, '_public' get '/fts/:file' do |file| + t = Time.now + (8 * 60 * 60) + timestamp = t.strftime('%a, %d %b %Y %H:%m:%S GMT') + target_host = request.host if target_host.match(/gfts/) - @type = :ngfts + @type = :gfts + ## app store downloads # http://gfts.lge.com/fts/gftsFilePathDownload.lge?key=777863&hash=6Vsai7Ky71UPgetV&mtime=1479098823000 - # this is the opkg update path - #redirect '/base-files/base-files.ipk' - # unfortunately, we need to set these headers: - # Server: Apache - # Content-Disposition: attachment; filename="16881482.ipk" - # Content-Transfer-Encoding: binary; - # Content-Type: application/octet-stream;charset=UTF-8 + key = params['key'] # 777863 + hash = params['hash'] # 6Vsai7Ky71UPgetV + mtime = params['mtime'] # 1479098823000 - # and currently, we send: - # Content-Type: application/vnd.shana.informed.package - # and the other fields are empty + fake_ipk_name = '16881482.ipk' + real_ipk_file = File.join(settings.public_folder, '/gfts/base-files.ipk') headers( - 'Content-Disposition' => 'attachment; filename="base-files.ipk"', + 'Content-Disposition' => sprintf('attachment; filename="%s"', fake_ipk_name), 'Content-Transfer-Encoding' => 'binary', 'Content-Type' => 'application/octet-stream;charset=UTF-8', 'Server' => 'Apache', ) - send_file File.join(settings.public_folder, '/base-files/base-files.ipk') + send_file real_ipk_file elsif target_host.match(/ngfts/) + ## channel searching -- images / thumbnails + # samples in line @type = :ngfts - biz_code = '' # TODO fill this in + + biz_code = params['biz_code'] + func_code = params['func_code'] + file_path = params['file_path'] + if biz_code.eql?('PREMIUMS') # TODO /fts/gftsDownload.lge?biz_code=PREMIUM&func_code=RECOMM_PROMOTION_IMAGE&file_path=/todayrecomm/template/promotion/w1_8.png elsif biz_code.eql?('META_IMG') @@ -57,33 +61,73 @@ get '/fts/:file' do |file| elsif biz_code.eql?('MAS') # TODO /fts/gftsDownload.lge?biz_code=MAS&func_code=META_THUMBNAIL&file_path=%2Fmas%2Ftms%2Fprogram%2Fp185554_b_ap.jpg end + + # failover redirect '/ngfts/faked-ngfts.zip' + elsif target_host.match(/aic/) + ## channel searching - listing JSON + # http://aic-gfts.lge.com/fts/gftsDownload.lge?biz_code=IBS&func_code=ONLINE_EPG_FILE&file_path=/ibs/online/epg_file/20161116/f_1479280636996tmsepgcrawler_merged000004417_201611160600_06_20161116070000.zip @type = :aic - @real_file = '/aic/faked-aic.zip' - @fake_file = '16881482.ipk' - redirect real_file + + fake_file = 'TODO' # TODO not sure what this is supposed to be + real_file = File.join(settings.public_folder, '/aic/faked-aic.zip') + + if @type.eql?(:aic) + headers( + 'Server' => 'Apache', + 'Content-Disposition' => sprintf('attachment; filename="%s"', fake_file), + 'Content-Transfer-Encoding' => 'binary', + 'Content-Type' => 'image/jpeg;charset=UTF-8', + 'Connection' => 'keep-alive', + 'Content-Length' => File.read(real_file).size, + 'Last-Modified' => timestamp, + 'Date' => timestamp, + ) + end + + send_file real_file + else # failover - 'your princess is in another castle' + 'your princess is in another castle - lge' end end -after do - +post '/CheckSWAutoUpdate.laf' do t = Time.now + (8 * 60 * 60) timestamp = t.strftime('%a, %d %b %Y %H:%m:%S GMT') - if @type.eql?(:aic) - response['Server'] = 'Apache' - response['Content-Disposition'] = sprintf('attachment; filename="%s"', @fake_file) - response['Content-Transfer-Encoding'] = 'binary' - response['Content-Type'] = 'image/jpeg;charset=UTF-8' - response['Connection'] = 'keep-alive' - response['Content-Length'] = File.read(@real_file).size - response['Last-Modified'] = timestamp - response['Date'] = timestamp - end + string = " +900 +Success +00000000008613244660 +http://snu.lge.com/fizbuzz +400 +fizzbuzz +04 +30.50 +Y + +#{timestamp} +01 +http://snu.lge.com/fizzbuzz + +" - @type = @real_file = @fake_file = nil + payload = Base64.strict_encode64(string) + + headers( + 'Date' => timestamp, + 'Pragma' => 'no-cache', + 'Expires' => '-1', + 'Content-Type' => 'application/octet-stream;charset=UTF-8', + 'Content-Length' => payload.size, + ) + + payload +end + +after do + # noop for now end \ No newline at end of file diff --git a/lg_webOS/json-list.rb b/lg_webOS/json-list.rb index 620d2b5..f7ee924 100644 --- a/lg_webOS/json-list.rb +++ b/lg_webOS/json-list.rb @@ -20,8 +20,8 @@ start.downto(0).each do |i| puts sprintf(' [%s/%s] [%.2f%%]', i, start, (start.to_f / i.to_f) * 100) end - url = sprintf('http://%s:%s/json/list?t=%s', h, p, i) - data = nil + url = sprintf('http://%s:%s/json/list?t=%s', h, p, i) + data = nil begin response = Utility.get_url(url) diff --git a/lg_webOS/webos.paw b/lg_webOS/webos.paw index b73613a2b5b767ca8790897f55f35cd9eb31aa8a..318853041f42a7757b104cda757c3e3569d8c64d 100644 GIT binary patch literal 16876 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