Module:Sensitive IP addresses/API: Difference between revisions

Content deleted Content added
actually use the separator
m Protected "Module:Sensitive IP addresses/API": High-risk Lua module: used in the MediaWiki interface, e.g. MediaWiki:Blockiptext via Template:Sensitive IP addresses ([Edit=Require administrator access] (indefinite...
 
(8 intermediate revisions by the same user not shown)
Line 7:
local IPv4Collection = mIP.IPv4Collection
local IPv6Collection = mIP.IPv6Collection
 
local libraryUtil = require('libraryUtil')
-- Lazily load the jf-JSON module
local checkType = libraryUtil.checkType
local JSON
 
-------------------------------------------------------------------------------
Line 26 ⟶ 27:
else
return val
end
end
 
local function deepCopyInto(source, dest)
-- Do a deep copy of a source table into a destination table, ignoring
-- self-references and metatables. If a table in source has a self-reference
-- you will get an infinite loop.
for k, v in pairs(source) do
if type(v) == 'table' then
dest[k] = {}
deepCopyInto(v, dest[k])
else
dest[k] = v
end
end
end
Line 87 ⟶ 102:
-- otherwise. matchObj is the Subnet object that was matched, and queryObj
-- is the IPAddress or Subnet object corresponding to the input string.
checkType('matchesIPOrRange', 1, str, 'string')
 
-- Get the IPAddress or Subnet object for str
Line 156 ⟶ 170:
-- {
-- entities = {'all'}
-- }
--
-- Query all entities and format the result as a JSON string:
-- {
-- entities = {'all'},
-- format = 'json'
-- }
--
Line 237 ⟶ 257:
end
 
local function makeError(code, info, format)
returnlocal ret = {['error'] = {
code = code,
info = info,
['*'] = 'See https://en.wikipedia.org/wiki/Module:Sensitive_IP_addresses/API for API usage',
}}
if format == 'json' then
return mw.text.jsonEncode(ret)
else
return ret
end
end
 
-- Construct result
local result = {}
matches = {},
['matched-ranges'] = {},
entities = {},
['entity-ids'] = {}
}
 
if type(options) ~= 'table' then
Line 259 ⟶ 289:
return makeError(
'sipa-blank-options',
"the options table didn't contain a 'test' or an 'entities' key",
options.format
)
end
Line 270 ⟶ 301:
"'test' options key was type %s (expected table)",
type(options.test)
),
options.format
)
end
Line 282 ⟶ 314:
i,
type(testString)
),
options.format
)
end
Line 301 ⟶ 334:
i,
testString
),
options.format
)
end
if isMatch then
-- The string was a sensitive IP address or subnet.
 
-- Set up result subtables
result.matches = result.matches or {}
result['matched-ranges'] = result['matched-ranges'] or {}
result.entities = result.entities or {}
result['entity-ids'] = result['entity-ids'] or {}
 
-- Add match data
Line 356 ⟶ 384:
"'entities' options key was type %s (expected table)",
type(options.test)
),
options.format
)
end
Line 371 ⟶ 400:
i,
type(entityString)
),
options.format
)
end
Line 394 ⟶ 424:
-- Insert the entity and entity-id subtables if they aren't already
-- present.
result.entities = result.entities or {}
result['entity-ids'] = result['entity-ids'] or {}
for i, entityString in ipairs(options.entities) do
if entities[entityString] then
Line 412 ⟶ 440:
 
-- Add any missing reason fields from entities.
iffor id, entityData in pairs(result.entities) thendo
for id, entityData.reason in= pairs(resultentityData.entities)reason or do'political'
entityData.reason = entityData.reason or 'political'
end
end
 
Line 422 ⟶ 448:
 
if options.format == 'json' then
-- Load jf-JSON
return mw.text.jsonEncode(result)
JSON = JSON or require('Module:jf-JSON')
JSON.strictTypes = true -- Necessary for correct blank-object encoding
-- Decode a skeleton result JSON string. This ensures that blank objects
-- are re-encoded as blank objects and not as blank arrays.
local jsonResult = JSON:decode([[{"sensitiveips": {
"matches": [],
"matched-ranges": {},
"entities": {},
"entity-ids": []
}}]])
for i, key in ipairs{'matches', 'matched-ranges', 'entities', 'entity-ids'} do
deepCopyInto(result.sensitiveips[key], jsonResult.sensitiveips[key])
end
return JSON:encode(jsonResult)
elseif options.format == nil or options.format == 'lua' then
return result
elseif type(options.format) ~= 'string' then
return makeError(
'sipa-format-type-error',
string.format(
"'format' options key was type %s (expected string or nil)",
type(options.format)
)
)
else
return resultmakeError(
'sipa-invalid-format',
string.format(
"invalid format '%s' (expected 'json' or 'lua')",
type(options.format)
)
)
end
end
 
-------------------------------------------------------------------------------
-- Summary table
-- A table of sensitive IP data to be used in
-- [[Template:Sensitive IP addresses]].
-------------------------------------------------------------------------------
 
local function makeSummaryTable(options)
-- Return a wikitext table summarizing all the sensitive IP ranges
-- and the entities they belong to.
 
-- Load necessary modules
local yesno = require('Module:Yesno')
 
-- Set up options
options = options or {}
local separator = options.separator or ', '
local showNotes = yesno(options.notes)
local nColumns = showNotes and 3 or 4
 
-- Get the entity data
local data = query{entities={'all'}}
if data['error'] then
error(string.format('%s: %s', data['error'].code, data['error'].info))
end
 
-- Make the table root
local root = mw.html.create('table')
if options.class then
root:addClass(options.class)
end
if options.style then
root:cssText(options.style)
end
 
-- Add main header
if yesno(options.mainheader) then
local mainHeader = root:tag('tr'):tag('td')
mainHeader:attr('colspan', nColumns)
local mainHeaderText = '[[Wikipedia:Blocking IP addresses#Sensitive IP addresses|Sensitive IP addresses]]'
if yesno(options.rangecalculator) then
mainHeaderText = mainHeaderText .. ' ([http://www.subnet-calculator.com/cidr.php IPv4 range calculator] - [http://www.gestioip.net/cgi-bin/subnet_calculator.cgi IPv6 range calculator])'
end
if options.mainheaderrule then
mainHeaderText = mainHeaderText .. '\n<hr style="margin: 4px 0;" />'
end
mainHeader:wikitext(mainHeaderText)
end
 
-- Add column headers
local headerRow = root:tag('tr')
headerRow
:tag('th')
:wikitext('[[IPv4]]')
:done()
:tag('th')
:wikitext('[[IPv6]]')
:done()
:tag('th')
:wikitext('Description')
if showNotes then
headerRow:tag('th'):wikitext('Notes')
end
 
-- Add data cells
for i, id in ipairs(data.sensitiveips['entity-ids']) do
local entityData = data.sensitiveips.entities[id]
if not options.reason or options.reason == entityData.reason then
local dataRow = root:tag('tr')
dataRow
:tag('td')
:wikitext(entityData.ipv4Ranges
and table.concat(entityData.ipv4Ranges, separator)
or nil
)
:done()
:tag('td')
:wikitext(entityData.ipv6Ranges
and table.concat(entityData.ipv6Ranges, separator)
or nil
)
:done()
:tag('td')
:wikitext(entityData.description or entityData.name)
if showNotes then
dataRow:tag('td'):wikitext(entityData.notes)
end
end
end
 
return tostring(root)
end
 
Line 526 ⟶ 490:
local p = {}
 
function p.isValidSensitivityReason_isValidSensitivityReason(s)
-- Return true if s is a valid sensitivity reason; otherwise return false.
return s ~= nil and SensitiveEntity.reasons[s] ~= nil
checkType('isValidSensitivityReason', 1, s, 'string')
return SensitiveEntity.reasons[s] ~= nil
end
 
function p.getSensitivityReasons_getSensitivityReasons(separator, conjunction)
-- Return an arraystring of valid sensitivity reasons, ordered alphabetically.
-- The reasons are separated by an optional separator; if conjunction is
local ret = {}
-- specified it is used instead of the last separator, as in
-- mw.text.listToText.
 
-- Get an array of valid sensitivity reasons.
local reasons = {}
for reason in pairs(SensitiveEntity.reasons) do
retreasons[#retreasons + 1] = reason
end
table.sort(retreasons)
 
return ret
-- Convert arguments if we are being called from wikitext.
if type(separator) == 'table' and type(separator.getParent) == 'function' then
-- separator is a frame object
local frame = separator
separator = frame.args[1]
conjunction = frame.args[2]
end
 
-- Return a formatted string
return mw.text.listToText(reasons, separator, conjunction)
end
 
-- Export the API query function
p.query = query
 
-- Export the summary table function
function p.summary(frame)
local args = require('Module:Arguments').getArgs(frame, {
wrappers = 'Template:Sensitive IP addresses'
})
return makeSummaryTable(args)
end
 
return p