Module:Keys

require('strict') local getArgs = require('Module:Arguments').getArgs local infobox = require('Module:Infobox').infobox local device = require('Module:Device') local deviceLink = device.deviceLink local deviceName = device.deviceName local osForDevice = device.osForDevice local data = mw.loadData('Module:Keys/data') local frame = mw.getCurrentFrame

local function hasValue(haystack, needle) for _, value in ipairs(haystack) do		if value == needle then return true end end return false end

local function info(message) return frame:callParserFunction('#info: ' .. message, {}) end

local function warning(message) return frame:callParserFunction('#info: ' .. message, { 'warning' }) end

local function ask(query) return frame:callParserFunction('#ask', query) end

local function keyValue(ul, id, name, kind, value) if not value or value == '' then return '' end

return ul		:tag('li') :tag('strong') :wikitext(name) :done :wikitext(': ') :tag('code') :attr('id', 'keypage-' .. id .. '-' .. kind) :wikitext(value) :done :done end

local function makeInfobox(args) local boxArgs = { labelstyle = 'white-space: nowrap;', titleclass = 'summary', belowstyle = 'font-size: 85%;', label1 = 'Build', label2 = 'Codename', label3 = 'Device', label4 = 'Baseband' }

boxArgs['title'] = tostring(mw.html.create		:wikitext(osForDevice(args['Device'], args['Version']) .. ' ')		:tag('span')			:attr('id', 'keypage-version')			:wikitext(args['Version'])		:done)

boxArgs['data1'] = tostring(mw.html.create('span')		:attr('id', 'keypage-build')		:wikitext(args['Build']))

boxArgs['data2'] = tostring(mw.html.create('span')		:attr('id', 'keypage-codename')		:wikitext(args['Codename']))

local models = mw.html.create('span') :attr('id', 'keypage-device') :wikitext(deviceLink(args['Device'])) if args['Model'] and args['Model2'] then -- Explicitly list both models models:wikitext(' (' .. args['Model'] .. ' and ' .. args['Model2'] .. ')')	end boxArgs['data3'] = tostring(models)

if hasValue(data.devicesWithBaseband, args['Device']) then local baseband = mw.html.create('span') :attr('id', 'keypage-baseband') if args['Baseband'] then local basebandValue = args['Baseband'] -- Handle an edge case if basebandValue == '1.0.11' or basebandValue == '3.0.04' then local modem = 'MDM9600' if args['Device'] == 'iPhone4,1' then modem = 'MDM6610' end basebandValue =  .. basebandValue ..  end

baseband:wikitext(basebandValue) else baseband :wikitext('Unknown ' .. warning('Template:Keys: Device model has a baseband, but the Baseband parameter is missing.')) :wikitext('') end boxArgs['data4'] = tostring(baseband) elseif args['Baseband'] then -- Baseband shouldn't be set local baseband = mw.html.create :wikitext(warning('Template:Keys: Device model does not have a baseband, but the Baseband parameter has been specified. If this device model does have a baseband, add it to Module:Keys/data.')) :wikitext('') boxArgs['data4'] = tostring(baseband) end

if args['DownloadURL'] then local url = args['DownloadURL'] local filename = url:match("^.+/(.+)$") if filename then boxArgs['data5'] = tostring(mw.html.create				:tag('span')					:attr('id', 'keypage-download')					:wikitext('[' .. url .. ' ' .. filename .. ']'))		else -- URL might be something like "?" (deleted/unknown). Just include it verbatim. boxArgs['data5'] = url end end

local pageName = mw.title.getCurrentTitle.prefixedText boxArgs['below'] = tostring(mw.html.create		:wikitext('JSON: ')		:tag('span')			:attr('id', 'keypage-json-firmware')			:wikitext(ask({				 .. pageName .. ,				['?Has operating system'] = 'os',				['?Has firmware version']  = 'version',				['?Has firmware build']    = 'build',				['?Has firmware device']   = 'device',				['?Has firmware codename'] = 'codename',				['?Has firmware baseband'] = 'baseband',				['?Has download URL']      = 'url',				format      = 'json',				type        = 'simple',				mainlabel   = 'name',				searchlabel = 'Firmware'			}))		:done		:wikitext(' &middot; ')		:tag('span')			:attr('id', 'keypage-json-keys')			:wikitext(ask({				'-Has subobject::' .. pageName .. '',				['?Has filename']        = 'filename',				['?Has firmware device'] = 'device',				['?Has key IV']          = 'iv',				['?Has key']             = 'key',				['?Has key KBAG']        = 'kbag', format     = 'json', type       = 'simple', mainlabel  = 'filename', searchlabel = 'Keys' }))		:done )

return infobox(boxArgs) end

local function keyItem(args) if not args.id or args.id == '' then return warning('Internal Template:Keys error') end

if args.id ~= 'rootfs' and args.id ~= 'rootfs-beta' and (not args.iv or args.iv ==  or not args.file or args.file == ) then return '' end

local div = mw.html.create('div') :addClass('keypage-entry')

-- Heading local h2 = div:tag('h2') :wikitext(args.header)

if args.model and args.model ~= '' then h2 :wikitext(' ') :tag('span') :addClass('keypage-model') :wikitext('(' .. args.model .. ')')	end

-- Filename if args.file and args.file ~= '' then div :wikitext(' Filename: ') :tag('span') :addClass('keypage-filename') :attr('id', 'keypage-' .. args.id) :wikitext(args.file) :done end

-- Warnings local isIncomplete = true local isIncorrect = false

if args.file ~= '' and args.iv ~= 'Unknown' and args.key ~= 'Unknown' then isIncomplete = false end

if args.id == 'rootfs' or args.id == 'rootfs-beta' then if args.file ~=  and args.key ~=  and args.key ~= 'Unknown' then isIncomplete = false end elseif (args.iv ~= 'Unknown' and args.kbag and args.kbag ~= ) or (args.iv == 'Unknown' and args.kbag == ) then isIncorrect = true div:wikitext(warning('This key data is missing an IV or KBAG.')) div:wikitext('') end

if isIncomplete then if not isIncorrect then div:wikitext(info('This key data has not been fully filled out.')) end div:wikitext('') end

-- Values list local ul = div:tag('ul') if args.key == 'Not Encrypted' or args.iv == 'Not Encrypted' then ul :tag('li') :wikitext('Not Encrypted') :done else keyValue(ul, args.id, 'IV',  'iv',   args.iv) keyValue(ul, args.id, 'Key', 'key',  args.key) keyValue(ul, args.id, 'KBAG', 'kbag', args.kbag) end

-- Semantic subobject div:wikitext(frame:callParserFunction('#subobject:' .. args.id, { ['Has filename']       = args.file, ['Has firmware device'] = args.model, ['Has key IV']         = args.iv, ['Has key']            = args.key, ['Has key KBAG']       = args.kbag }))

return tostring(div) end

local p = {}

function p._main(frame, args) local root = mw.html.create :wikitext('')

-- Parameter checks if not args['Version'] or args['Version'] ==  or		not args['Build'] or args['Build'] ==  or		not args['Device'] or args['Device'] ==  or		not args['Codename'] or args['Codename'] ==  then root:wikitext(warning('Template:Keys: Required parameters are missing')) root:wikitext('') return tostring(root) end

-- Both Model and Model2 must be set, or neither must be set if args['Model'] and args['Model'] ~=  and (not args['Model2'] or args['Model2'] == ) then root:wikitext(warning('Template:Keys: Model key was set without setting Model2. If there is only one model for this device, remove Model.')) root:wikitext('') end

-- Title check local expectedTitle = mw.title.new('Keys:' .. args['Codename'] .. ' ' .. args['Build'] .. ' (' .. args['Device'] .. ')')	if not mw.title.equals(mw.title.getCurrentTitle, expectedTitle) then root:wikitext(warning('Template:Keys: Page name does not follow the correct format. Fix the parameters, or rename the page to: ' .. expectedTitle.prefixedText)) root:wikitext('') end

-- Device category root:wikitext('')

-- Semantic object root:wikitext(frame:callParserFunction('#set:', { ['Has operating system'] = osForDevice(args['Device'], args['Version']), ['Has firmware version'] = args['Version'] or '', ['Has firmware build']   = args['Build'] or '', ['Has firmware device']  = args['Device'] or '', ['Has firmware codename'] = args['Codename'] or '', ['Has firmware baseband'] = args['Baseband'] or '', ['Has download URL']     = args['DownloadURL'] or '' }))

-- CSS root:wikitext(frame:extensionTag('templatestyles', '', { src = 'Keys/styles.css' }))

-- Infobox root:wikitext(makeInfobox(args))

-- Root filesystem local rootfsFilename = '' if args['RootFS'] and args['RootFS'] ~= '' then rootfsFilename = args['RootFS'] .. '.dmg' end root:wikitext(keyItem({ id    = 'rootfs', header = 'Root Filesystem', file  = rootfsFilename, key   = args['RootFSKey'] or '', }))

if args['RootFSBeta'] then root:wikitext(keyItem({ id    = 'rootfs-beta', header = 'Root Filesystem (Beta)', file  = args['RootFSBeta'] .. '.dmg', key   = args['RootFSBetaKey'] or 'Not Encrypted', }))	end

-- Remaining files for _, item in ipairs(data.files) do		local filename = '' if args[item.param] then filename = args[item.param] .. (item.extension or '') end

local model = nil if args['Model2'] and args[item.param .. '2'] then model = args['Model'] end

root:wikitext(keyItem({ id    = item.id, header = item.header, file  = filename, iv    = args[item.param .. 'IV'] or '', key   = args[item.param .. 'Key'] or '', kbag  = args[item.param .. 'KBAG'] or '', model = model }))

-- Handle 2nd variant of this device (e.g. A9 Samsung/TSMC) if model then local filename2 = args[item.param .. '2'] .. (item.extension or '') root:wikitext(keyItem({ id    = item.id .. '2',				header = item.header, file  = filename2, iv    = args[item.param .. '2IV'] or '', key   = args[item.param .. '2Key'] or '', kbag  = args[item.param .. '2KBAG'] or '', model = args['Model2'] }))		end end

return tostring(root) end

function p.main(frame) return p._main(frame, getArgs(frame)) end

return p