'use strict' var assert = require('assert') var path = require('path') var fs = require('fs') var yaml = require('yamlparser') var regexes = readYAML('../regexes.yaml') var safe = require('safe-regex') var refImpl = require('uap-ref-impl') function readYAML (fileName) { var file = path.join(__dirname, fileName) var data = fs.readFileSync(file, 'utf8') return yaml.eval(data) } suite('regexes', function () { Object.keys(regexes).forEach(function (parser) { suite(parser, function () { regexes[parser].forEach(function(item) { test(item.regex, function () { assert.ok(safe(item.regex)) }) }) }) }) Object.keys(regexes).forEach(function (parser) { suite(`no reverse lookup in ${parser}`, function () { regexes[parser].forEach(function(item) { test(item.regex, function () { if (/\(\?<[!=]/.test(item.regex)) { assert.ok(false, 'go parser does not support regex lookbehind. See https://github.com/google/re2/wiki/Syntax') } if (/\(\?[!=]/.test(item.regex)) { assert.ok(false, 'go parser does not support regex lookahead. See https://github.com/google/re2/wiki/Syntax') } }) }) }) }) }) suite('redos', function(){ const parse = refImpl(regexes).parse const tests = [ '"a"+"a"*3500+"a"', '"SmartWatch"+" "*3500+"z"', '";A Build HuaweiA"+"4"*3500+"z"', '"HbbTV/0.0.0 (;LGE;"+" "*3500+"z"', '"HbbTV/0.0.0 (;CUS:;"+" "*3500+"z"', '"HbbTV/0.0.0 (;"+" "*3500+"z"', '"HbbTV/0.0.0 (;z;"+" "*3500+"z"', '"AppleWebKit/1."+"0"*10000+"!"', '"AppleWebKit/1.1"+" Safari"*10000+"!"', '"/0"+"0"*10000+"◎"', '"Mozilla"+"Mobile"*10000+"!"', '"Mozilla"+"Mobile"*10000+"!"', '"Mozilla"+"Mobile"*10000+"!"', '"Mozilla"+"Mobile"*10000+"!"', '"Mozilla"+"Mobile"*10000+"!"', '"Opera/"+"Opera Mobi"*10000+"!"', '"Opera/1."+"0"*10000+"!"', '"Mozilla"+"Android"*10000+"!"', '"Chrome/1.1."+"0"*10000+"!"', '"Chrome/1.1."+"0"*10000+"!"', '"MSIE 1."+"0"*10000+"!"', '"iPod"+"Version/1.1"*10000+"!"', '"iPod;ACPUAOS 0_0"+"0"*10000+"◎"', '"iPod;"+"CPU"*10000+"!"', '"iPod;"+"CPUOS 1_1"*10000+"!"', '"iPod;CPU"+"OS 1_1"*10000+"!"', '"Version/0.0"+"0"*10000+"◎\n"', '"HbbTV/0.0.0"+"0"*10000+"◎"', '"HbbTV/1.1.1 ("+";a;"*10000+"!"', '"HbbTV/1.1.1 ("+";a;2011"*10000+"!"', '"HbbTV/1.1.1 (;a;"+"2011"*10000+"!"', '"CPU OS 0.0"+"0"*10000+"◎"', '"ArcGIS.iOS-0.0"+"0"*10000+"◎"', '"x86_64 1.1."+"0"*10000+"!"', '"x86_64 1.1.1"+"Chrome"*10000+"!"', '" Darwin/91"+"0"*10000+"!"', '" Darwin/101"+"0"*10000+"!"', '" Darwin/111"+"0"*10000+"!"', '" Darwin/121"+"0"*10000+"!"', '" Darwin/131"+"0"*10000+"!"', '"iPhone"+"Mac OS X"*10000+"!"', '"CFNetwork/C Darwin/17.0"+"0"*10000+"◎"', '"CFNetwork/"+" Darwin/17.1"*10000+"!"', '"CFNetwork/"+" Darwin/16.1"*10000+"!"', '"CFNetwork/ Darwin/16."+"0"*10000+"!"', '"CFNetwork/8"+" Darwin/15.1"*10000+"!"', '"CFNetwork/8 Darwin/15."+"0"*10000+"!"', '"Linux 0.0"+"0"*10000+"◎"', '" PTST/0"+"0"*10000+"◎\n"', '"Mozilla"+"Mobile"*10000+"!"', '"; AIRIS "+" "*10000+"◎"', '";ASUS"+"_"*10000+"!"', '";Excite "+"0"*10000+"!"', '"; "+" "*10000+"◎"', '";"+"Coolpad_"*10000+"!"', '";TAC-"+"0"*10000+"!"', '"; "+" "*10000+"◎"', '"; Fly F30"+"0"*10000+"◎"', '"; FONE 0"+"0"*10000+"◎"', '"; "+" "*10000+"◎"', '"; "+" "*10000+"◎"', '"; "+" "*10000+"◎"', '"; Build HuaweiA0"+"0"*10000+"◎"', '"; "+" "*10000+"◎\n"', '"; Ideos "+" "*10000+"◎"', '"; NT-0"+"0"*10000+"◎"', '";ImPAD"+"0"*10000+"!"', '"; Intex AQUA "+" "*10000+"◎"', '"; IBuddy Connect "+" "*10000+"◎"', '"; I-Buddy "+" "*10000+"◎"', '"; Karbonn "+" "*10000+"◎"', '"; "+" "*10000+"◎\n"', '"; LAVA IRIS "+" "*10000+"◎"', '"; VS60"+"0"*10000+"◎"', '"; VS60 "+" "*10000+"◎"', '"; PhonePad 000"+"0"*10000+"◎"', '"; SmartPad 000"+"0"*10000+"◎"', '"; meizu_ "+" "*10000+"◎"', '"; Cynus F5 "+" "*10000+"◎"', '"; NXM0"+"0"*10000+"◎"', '";Nokia"+"_"*10000+"!"', '";IM-A111"+"0"*10000+"!"', '";Pantech"+"0"*10000+"!"', '"; Polaroid MIDC0000"+"0"*10000+"◎"', '"; POMP "+" "*10000+"◎"', '"; SAMSUNG Galaxy Note II "+" "*10000+"◎"', '"; SAMSUNG-"+"0"*10000+"!"', '"; SCH-0"+"0"*10000+"◎\n"', '"; SC-0"+"0"*10000+"◎"', '" SCH-0"+"0"*10000+"◎"', '"; Xperia X0"+"0"*10000+"◎"', '"; Sprint "+" "*10000+"◎"', '"; TM-MID0"+"0"*10000+"◎"', '";TM-SM"+"0"*10000+"!"', '"; Videocon "+" "*10000+"◎"', '";XOLO "+"tab"*10000+"!"', '"; PAD 70"+"0"*10000+"◎"', '";SmartTab"+"0"*10000+"!"', '"; v89_"+"0"*10000+"◎"', '"; e0000a_v0"+"0"*10000+"◎"', '"Windows Phone ; "+"IEMobile/"*10000+"!"', '"Windows Phone ; "+"IEMobile/"*10000+"!"', '"Windows Phone ; "+"IEMobile/"*10000+"!"', '"Windows Phone ; IEMobile/ ; ARM; Touch; HTC_blocked "+" "*10000+"◎"', '"Windows Phone ; "+"IEMobile/"*10000+"!"', '"Windows Phone ; "+"IEMobile/"*10000+"!"', '"Windows Phone ; "+"IEMobile/"*10000+"!"', '"Windows Phone ; "+"IEMobile/"*10000+"!"', '"Windows Phone ; "+"IEMobile/"*10000+"!"', '"Windows Phone ; "+"IEMobile/"*10000+"!"', '"Windows Phone ; "+"IEMobile/"*10000+"!"', '"Windows Phone ; "+"IEMobile/"*10000+"!"', '"Windows Phone ; "+"IEMobile/"*10000+"!"', '"SAMSUNG-"+"0"*10000+"!"', '"(Mobile; LYF/0/ ;"+";"*10000+"◎"', '"(Mobile; LYF/A/"+";0rv:"*10000+"!"', '"(Mobile; LYF/A/1;"+"rv:"*10000+"!"', '"(Mobile; Nokia_A_"+"; rv:"*10000+"!"', '"CFNetwork/"+" Darwin/1"*10000+"!"', '"CFNetwork/ Darwin/1"+"(Mac"*10000+"!"', '"Android 0.0-update1; AA-A ; "+" "*10000+"◎\n"', '"Android 0.0.0; AA-A- ; "+" "*10000+"◎"', '"Android 0.0.0; A- ; "+" "*10000+"◎"', '"Android 0.0.0; -AA; "+" "*10000+"◎\n"', '"Android 1; "+" Build"*10000+"!"', '"Android 1; "+" Build"*10000+"!"', '"foobar!/!./"+"/"*40000+"◎"', '" #- regex: \'(iPad;(Version/0.0.08"+"8"*40000+"◎"', '" #- regex: \'(iPad;"*8000', '" #- regex: \'HbbTV/0.0.0 (; Sony;H;"+";"*40000+"◎1\n_\n"', '" #- regex: \'HbbTV/1.1.1 (; Sony;"*600', '"Windows Phone ; IEMobile/ ; ARM; Touch; HTC_blockedd"+"d"*40000+"◎1\n_\n)"', '"Windows Phone "*8000', '"HTC/HTC "+" "*20000+"\n"', '"HTC/HTC "+" "*10000+"\n"', '""+"Google"*5000+"! _1SLQ_2"', '""+"MSIE 1.1;"*10000+"! _1SLQ_2"', '""+"[FB"*10000+"! _1SLQ_2"', '""+"[FB"*10000+"! _1SLQ_2"', '""+"[Pinterest/"*5000+"@1 _SLQ_2"', '""+"Mobile;"*5000+"! _1SLQ_2"', '""+"FirefoxTablet browser 1."*3000+"! _1SLQ_2"', '""+"Opera TabletVersion/1."*3000+"! _1SLQ_2"', '""+"Opera/9180Version/"*5000+"! _1SLQ_2"', '""+"Chrome/1 MMS/11"*5000+"! _1SLQ_2"', '""+"PLAYSTATION 3"*5000+"! _1SLQ_2"', '""+"AppleWebKit1 NX/1."*5000+"! _1SLQ_2"', '""+"Windows Phone Edge/1."*3000+"! _1SLQ_2"', '""+"amarok/"*10000+"@1 _SLQ_2"', '""+"iPod1GSA/1."*5000+"! _1SLQ_2"', '""+"iPod"*10000+"! _1SLQ_2"', '""+"PlayBook"*10000+"! _1SLQ_2"', '""+"Blackberry1Version/"*5000+"! _1SLQ_2"', '""+"AppleWebKit/1+ "*5000+"! _1SLQ_2"', '""+"HbbTV/1.1.1 (;Samsung;SmartTV0000;"*2000+"! _1SLQ_2"', '""+"HbbTV/1.1.1 (;Samsung;SmartTV0000;"*2000+"! _1SLQ_2"', '""+"HbbTV/1.1.1 (; Philips;"*3000+"! _1SLQ_2"', '""+"HbbTV/1.1.1 (; Philips;"*3000+"! _1SLQ_2"', '""+"HbbTV/1.1.1 (; Philips;"*3000+"! _1SLQ_2"', '""+"Symbian/3"*10000+"! _1SLQ_2"', '""+"Symbian/3"*10000+"! _1SLQ_2"', '""+"BB10;1Version/"*5000+"! _1SLQ_2"', '""+"BlackBerry"*5000+"! _1SLQ_2"', '""+"(Mobile;1Gecko/1810 Firefox/"*3000+"! _1SLQ_2"', '""+"(Mobile;1Gecko/1811 Firefox/"*3000+"! _1SLQ_2"', '""+"(Mobile;1Gecko/2610 Firefox/"*3000+"! _1SLQ_2"', '""+"(Mobile;1Gecko/2810 Firefox/"*3000+"! _1SLQ_2"', '""+"(Mobile;1Gecko/3010 Firefox/"*3000+"! _1SLQ_2"', '""+"(Mobile;1Gecko/3210 Firefox/"*3000+"! _1SLQ_2"', '""+"(Mobile;1Gecko/3410 Firefox/"*3000+"! _1SLQ_2"', '""+"(Mobile;1Firefox/1."*5000+"! _1SLQ_2"', '""+"DoCoMo"*10000+"! _1SLQ_2"', '""+"Mozilla"*10000+"! _1SLQ_2"', '""+"SmartWatch("*10000+"@1 _SLQ_2"', '""+"Android Application - Sony 1 "*3000+"! _1SLQ_2"', '""+"Android Application - HTC HTC 1 "*3000+"! _1SLQ_2"', '""+"Android Application - - 1 "*3000+"! _1SLQ_2"', '""+"Android 3"*10000+"! _1SLQ_2"', '""+";Vega"*10000+"! _1SLQ_2"', '""+";ALLVIEWSpeed"*5000+"! _1SLQ_2"', '""+";ARCHOSGAMEPAD"*5000+"! _1SLQ_2"', '""+";BlackBird I8"*5000+"! _1SLQ_2"', '""+";BlackBird "*5000+"! _1SLQ_2"', '""+";CatNova"*10000+"! _1SLQ_2"', '""+";P-1"*1000+"@1 _SLQ_2"', '""+";Explay_"*10000+"! _1SLQ_2"', '""+";IQ"*10000+"! _1SLQ_2"', '""+";Pixel"*10000+"! _1SLQ_2"', '""+";GSmart "*10000+"! _1SLQ_2"', '""+";imx51_"*10000+"! _1SLQ_2"', '""+";Haier "*10000+"! _1SLQ_2"', '""+"Build/HCL ME Tablet "*3000+"@1 _SLQ_2"', '""+";HP "*10000+"! _1SLQ_2"', '""+"HTC Streaming Player "*3000+"@1 _SLQ_2"', '""+";HYUNDAI T1"*5000+"! _1SLQ_2"', '""+";imobile "*10000+"! _1SLQ_2"', '""+";i-style"*10000+"! _1SLQ_2"', '""+";iOCEAN "*10000+"! _1SLQ_2"', '""+";NEC-"*10000+"! _1SLQ_2"', '""+";Pantech "*10000+"! _1SLQ_2"', '""+"Android 4."*5000+"! _1SLQ_2"', '""+";PLT0000"*10000+"! _1SLQ_2"', '""+";SAMSUNG "*10000+"@1 _SLQ_2"', '""+";GT-B1111"*10000+"@1 _SLQ_2"', '""+"; SAMSUNG-"*5000+"! _1SLQ_2"', '""+";SK-"*10000+"! _1SLQ_2"', '""+";ST1111"*10000+"! _1SLQ_2"', '""+";ST1111"*10000+"! _1SLQ_2"', '""+";Build/"*10000+"! _1SLQ_2"', '""+"TOOKY "*10000+"! _1SLQ_2"', '""+"TOUCHTAB"*10000+"! _1SLQ_2"', '""+"VERTU "*10000+"! _1SLQ_2"', '""+";GTablet"*10000+"! _1SLQ_2"', '""+"Vodafone "*10000+"! _1SLQ_2"', '""+"sprd-"*10000+"@1 _SLQ_2"', '""+"Windows Phone "*5000+"@1 _SLQ_2)"', '""+"Windows Phone "*5000+"@1 _SLQ_2)"', '""+"Windows Phone "*5000+"@1 _SLQ_2)"', '""+"Windows Phone "*5000+"@1 _SLQ_2)"', '""+"Windows Phone "*5000+"@1 _SLQ_2)"', '""+"Windows Phone "*5000+"@1 _SLQ_2)"', '""+"Windows Phone "*5000+"@1 _SLQ_2)"', '""+"Windows Phone "*5000+"@1 _SLQ_2)"', '""+"Windows Phone "*5000+"@1 _SLQ_2)"', '""+"Windows Phone "*5000+"@1 _SLQ_2)"', '""+"(Mobile; ALCATELOneTouch ; rv:"*3000+"@1 _SLQ_2"', '""+"(Mobile; ZTE ; rv:"*5000+"@1 _SLQ_2"', '""+"(Mobile; ALCATELA; rv:"*3000+"@1 _SLQ_2"', '""+"PlayBook"*10000+"! _1SLQ_2"', '""+"webOS"*10000+"! _1SLQ_2"', '""+"HPiPAQ"*10000+"!1 _SLQ_2"', '""+"HbbTV;CE-HTML;"*5000+"@1 _SLQ_2"', '""+"InettvBrowser/0.0 (;Sony"*3000+"@1 _SLQ_2"', '""+"InettvBrowser/0.0 ("*5000+"@1 _SLQ_2"', '""+"MSIE"*10000+"! _1SLQ_2"', '""+"SMART-TV; "*10000+"! _1SLQ_2"', '""+"SymbianOS/9.1"*5000+"! _1SLQ_2"', '""+"Android "*10000+"@1 _SLQ_2"', '""+"Android-1.1; AA-; WOWMobile "*3000+"! _1SLQ_2"', '""+"Android-1.1-update1; AA-;"*3000+"! _1SLQ_2"', '""+"Android-1.1;AA_;"*5000+"! _1SLQ_2"', '""+"Android-1.1;-;"*5000+"! _1SLQ_2"', '""+"Android 1; Build"*3000+"! _1SLQ_2"', '""+"Android 1; Build"*3000+"! _1SLQ_2"' ] function buildAttackString (attackString) { const uas = attackString .replace(/^"|"$/g, '') .replace(/"?\+"([^"]+)"\*(\d+)/, (m, str, i) => { // console.error({m, str, i}) const size = parseInt(i, 10) if (!isNaN(size)) { return (new Array(size).fill(str).join('')) } else { return m } }) .replace(/\+"/, '') return uas } tests.forEach(attackString => { test(attackString, function() { const ua = buildAttackString(attackString) const start = Date.now() const parsed = parse(ua) // console.log(parsed) const diff = Date.now() - start assert.ok(diff < 500) }) }) })