diff --git a/.inscode b/.inscode index ecc8bdde946f464a2c4d431d8f8196413737d922..e1777316cc8a34b6c53f0ae12504b6c66fbdb272 100644 --- a/.inscode +++ b/.inscode @@ -1,6 +1,10 @@ run = "npm i && npm run dev" +language = "node" [env] PATH = "/root/${PROJECT_DIR}/.config/npm/node_global/bin:/root/${PROJECT_DIR}/node_modules/.bin:${PATH}" XDG_CONFIG_HOME = "/root/.config" -npm_config_prefix = "/root/${PROJECT_DIR}/.config/npm/node_global" \ No newline at end of file +npm_config_prefix = "/root/${PROJECT_DIR}/.config/npm/node_global" + +[debugger] +program = "main.js" diff --git a/.pnpm-store/v3/files/01/6ef54e9c511cd83c329950563bbdb4416f5cfbd7e367b4c0f6249eeb524ad0ee02357df6f59359879de23c6bfe0ae4d85b4a02ebf62af749c5c9f65b9f6aca-index.json b/.pnpm-store/v3/files/01/6ef54e9c511cd83c329950563bbdb4416f5cfbd7e367b4c0f6249eeb524ad0ee02357df6f59359879de23c6bfe0ae4d85b4a02ebf62af749c5c9f65b9f6aca-index.json new file mode 100644 index 0000000000000000000000000000000000000000..5f8c3c9c786bb0e8e68a5b90a8bffe5042f54581 --- /dev/null +++ b/.pnpm-store/v3/files/01/6ef54e9c511cd83c329950563bbdb4416f5cfbd7e367b4c0f6249eeb524ad0ee02357df6f59359879de23c6bfe0ae4d85b4a02ebf62af749c5c9f65b9f6aca-index.json @@ -0,0 +1 @@ +{"name":"nuxi","version":"3.11.1","files":{"LICENSE":{"checkedAt":1715158492551,"integrity":"sha512-Xxi7X7FVqA9+SoKwU4qJToWGtqDgzbWlYwpMC1FwFXihO57B5xXALXavysMMh8E4uwqkGQJjCika9SXMGSzjyg==","mode":420,"size":1071},"package.json":{"checkedAt":1715158492552,"integrity":"sha512-GcWMOlpDnb8NpNRHLXT/pawieaX1+/S2B1CLlS1CbyH25apLAtBDnoCE6yVMhEhd8CYYmYE3bW3dE7gHfFBjtw==","mode":420,"size":2465},"README.md":{"checkedAt":1715158492551,"integrity":"sha512-e2BJzsmfaPvOS2PUooCkBmBowRN1FfX2b+aSn46VCrfQspBwvVqJCfm7DFZi7IMwpG5mltfAx088ANWUQ61gPw==","mode":420,"size":922},"dist/chunks/add.mjs":{"checkedAt":1715158492553,"integrity":"sha512-dFV50x8iAkGZmuItO1Zyvf0ZPiPx9Jx1tku9d0axsvEPSzOQg5sBmcGiBb5E/BXZQAdVst77uk/uw2QLv67T0A==","mode":420,"size":4964},"dist/chunks/add2.mjs":{"checkedAt":1715158492597,"integrity":"sha512-dKB/UtXdxgMkhhK97yuRLhznBZHzWoBUnZUKuD0edHWbyrmqTqJlmzQgJYbJxZCLYiVXFBA5+HQ/Xb+8qcjABw==","mode":420,"size":889260},"dist/chunks/analyze.mjs":{"checkedAt":1715158492597,"integrity":"sha512-iGo9t2j6fi2yP3bZ7tkQ8GNKa71neFCydQjFSntiOIlxsPw55wlYoz3VfDCdh9zZcdgaehPhwS8eCb485lWxUg==","mode":420,"size":4362},"dist/chunks/build-module.mjs":{"checkedAt":1715158492597,"integrity":"sha512-UVRE5UXWLqfQuolE1js6UwJiEzlD+1GqzT+d8uLTiJHdc9bueuDs9ADElWIxEOSU6eSp1g3ucuFF5EfkzkDhyA==","mode":420,"size":2106},"dist/chunks/build.mjs":{"checkedAt":1715158492597,"integrity":"sha512-Pbf719mlHW3qhuHaedp/FO4ixa8SLGsj2ZKdjW6d2vkhHSJWQN6Gq46DyWDQe5uoEnod4kgQwBu2Xvurv8AUxg==","mode":420,"size":3235},"dist/chunks/cleanup.mjs":{"checkedAt":1715158492597,"integrity":"sha512-JEFbCBSBTEZSQIGbYgKiEMqccRK1qvdEMycQ0XUbZT/dCl0rHjkWRDpj8WWu/eofxdQ2OJX4peusDIIFKktieg==","mode":420,"size":1483},"dist/chunks/dev-child.mjs":{"checkedAt":1715158492597,"integrity":"sha512-wwW+mrE5NMjvCYgy/4VpdZAJ7I4BBJrn5u3Tnhqe73clGsdE99k7VnDLOvR5TP+bkGkNdXOfDaA+BnVxUOgQdw==","mode":420,"size":2937},"dist/chunks/dev.mjs":{"checkedAt":1715158492600,"integrity":"sha512-1aWH8/JQEWPl8EjELRDcZpmC62mDQiG80obt7yuvxVE4Pd4du/8GjXTX6qOR0DsxDwJI1wzibgysR/J8LN1B6g==","mode":420,"size":10090},"dist/chunks/dev2.mjs":{"checkedAt":1715158492606,"integrity":"sha512-qdCtXbOWsT1L8ztlkQnJqaTdB5eYWNI90vqYXxiH7axGIHL5Qj1Y3CpYxxExAdipv3L2kdxO+x6T4mV0WqW0eQ==","mode":420,"size":185516},"dist/chunks/devtools.mjs":{"checkedAt":1715158492606,"integrity":"sha512-HwBRjydqn8kq8v2s9M2k8jUgF33k/jFdF8fZNlHQlT73qWO2FaGA/1GC+fhueRYxlIU/cbXuWZT3XKfwZdFScg==","mode":420,"size":1279},"dist/chunks/generate.mjs":{"checkedAt":1715158492606,"integrity":"sha512-dkOuOfVtMLrtrs0m4xkjl3N+Ug8VCwGX8WcpuODcr04gsW6/Gcerv9lR0yrLZGcffvCwIH24hu179Ws7mGfYdA==","mode":420,"size":1473},"dist/chunks/index.mjs":{"checkedAt":1715158492606,"integrity":"sha512-oP3wGmWQ0SQw9cmaGK+TsN4abdM1LvEa2cdD4eTDygSJreMbMDjXV/gS1+cXWSGdb96TjDExc7YiV4ayO6IcrQ==","mode":420,"size":473},"dist/index.mjs":{"checkedAt":1715158492607,"integrity":"sha512-pBNDCbJJCxGNKTCptfAGeQJ5ldZ1iGdI27/PpLmqZwUqrvXVXnysAUMUtDSAs08jYiFj0YSMhByLlCOppG2PLw==","mode":420,"size":188},"dist/chunks/index2.mjs":{"checkedAt":1715158492641,"integrity":"sha512-PS08FathScChFehwsJeKjNzn0im5CtDEwJM6UvML6sbO639hgx1ntxKOZRzM3PZabtacOyWkvx1/yWJygUz9Fw==","mode":420,"size":902613},"dist/chunks/index3.mjs":{"checkedAt":1715158492643,"integrity":"sha512-pqm5fHGUpr3wmIZzzqA8PE5RI1CeR+3Ps3aYoFkZcbVbsQWqDWKUXWCgQwbQpOyTcFbK6BUWHVBrPTurpqq1MQ==","mode":420,"size":70175},"dist/chunks/index4.mjs":{"checkedAt":1715158492643,"integrity":"sha512-FkihMUJMYTWPps9+30volQ6riEYZUBPzIKJa/M7DHk83BprTnO95yL6VWmjSyo0nHooB1KfljEPloSC4CUDE4w==","mode":420,"size":17660},"dist/chunks/index5.mjs":{"checkedAt":1715158492643,"integrity":"sha512-LDaX+aE9yV5TV7yPJLkA2FXx1GoCkRvteIoCVQqFiBzKBMPgOpUg9gv3x4l+lQCI93oyRZCPTAo46AimIOxQdQ==","mode":420,"size":1489},"dist/chunks/index6.mjs":{"checkedAt":1715158492643,"integrity":"sha512-cy15RybftksjsoOkONGnADxltwz9xdflgsOOT2vbfyL9J9hQcwhRbbDs7HUe9XtcX7RImEY5YLg0a7kfIa9W3g==","mode":420,"size":7304},"dist/chunks/index7.mjs":{"checkedAt":1715158492643,"integrity":"sha512-6t083A0P/ukPzBmuAE9GBXLVDjSCx2x1olLt6xO8spzLRM+tNZ2DQ5iy1VCCUwgPjlgm2+aBio94wtNnfAcNVg==","mode":420,"size":6253},"dist/chunks/info.mjs":{"checkedAt":1715158492646,"integrity":"sha512-9cnZwlV9ma8QP08R8PWjPlSe5VFchSHSLqW8UeiDld8uO3tRYUgjgn8MMXR6k+/M7rHEdJL17SAg/qUzs3Ya6A==","mode":420,"size":5481},"dist/chunks/init.mjs":{"checkedAt":1715158492650,"integrity":"sha512-vzTYDwjm0LkY0uc+3fWQhYiQmrFFSKP/HaD7FAaApsPuzz/upBI5c7c67+twhpMUWlnbg1Ai8MMZhUE5X3Iiaw==","mode":420,"size":193228},"dist/chunks/multipart-parser.mjs":{"checkedAt":1715158492650,"integrity":"sha512-GMOg4R5Jk97NW++eoZfBznwoN0GXrd/iBSWEbLMU+7r3kZ8Pm5C10DfpT6YdgDesAJjgQRoLUvSz+wWCGTyJdw==","mode":420,"size":5242},"dist/chunks/node.mjs":{"checkedAt":1715158492655,"integrity":"sha512-j44zgoHCh5ZYR8B6WYSRHwXUbcUIGHFqBmFF8vDDKq0F6B8bH2u2aWTexyNw+lzUREv3fE7nKgU4621bXDdYyw==","mode":420,"size":126062},"dist/shared/nuxi.0f575f79.mjs":{"checkedAt":1715158492655,"integrity":"sha512-0iDkjJUcWoNbyGd8/XdnLYT5PZqhclvYs20FFtdI5a3F24vCfirVMeQ+PuKh6F1ZVnNwbpy2rhm4V9zldFt4bg==","mode":420,"size":6292},"dist/shared/nuxi.17654120.mjs":{"checkedAt":1715158492657,"integrity":"sha512-o8cZagZZ0jyHbDo1diDM+a3IhHQaFV8Bx0n5/8WIHOLq8NqkDutd6vC4x/L292/xuJi2/CyaxGMK2KoKczYwCQ==","mode":420,"size":778},"dist/shared/nuxi.1902c37d.mjs":{"checkedAt":1715158492672,"integrity":"sha512-xAOPcGhlu1fNtPcHDy5OPazH66PRuBx8pIq6EzZRQd08e6PqvPm7H/wAWsMU0hgqltjKFM0PltHLEX7zmujrtQ==","mode":420,"size":273826},"dist/shared/nuxi.1e36f2d5.mjs":{"checkedAt":1715158492671,"integrity":"sha512-9e1j+ZqJz3L6rKeKkCiDx44/PiroCwg/ROVNbI4rI/yylmQ9n1pvYDVt8tJiTuO1Seyu40/V3ZAJbfhMNCI4rA==","mode":420,"size":17431},"dist/shared/nuxi.1ff5d6e2.mjs":{"checkedAt":1715158492672,"integrity":"sha512-dN+oynjTX43KpMU47ey2kZo+Ibnvvog9d+fcvLkFZHzjkJ4MkTOOLPEfCxjoDaef+QFbYtj129xeB23CvfAgbw==","mode":420,"size":1499},"dist/shared/nuxi.2155838d.mjs":{"checkedAt":1715158492672,"integrity":"sha512-EAN3JrcDYMoPPgJYj9kRfI0W3rv79I52So/z36C10kAa4OjlL7IwgucUd6e6Wz+k9EDFZSk9PTErAFJsJGTQJQ==","mode":420,"size":1035},"dist/shared/nuxi.2509f57e.mjs":{"checkedAt":1715158492672,"integrity":"sha512-S7ClWljw/yrn3Hug6b+gOlmVuXnRrDg4ng3KThe8Xvqb4UTFyYCDhbvpDgARd+PVJyCG5vCcjqeAiFEXn/9Nzw==","mode":420,"size":330},"dist/shared/nuxi.29475410.mjs":{"checkedAt":1715158492672,"integrity":"sha512-qjqJy7bt9OTn+o7wccIMnwTlMxK3GqUILBsKvsYyQjJzY8imgg8fxk0Poi82NGcRCoaq++bq4s7VTfivyBlEuA==","mode":420,"size":15276},"dist/shared/nuxi.349af404.mjs":{"checkedAt":1715158492672,"integrity":"sha512-DIKc2VPM/qrgSOmwH8UL80nh1FZxf2ml/L+uMoIcP9dSZCN3JBZKzMzqVmpATMl5Iq1BNgU1Z3bf9/Sp0cITMQ==","mode":420,"size":1580},"dist/shared/nuxi.34ba5283.mjs":{"checkedAt":1715158492693,"integrity":"sha512-Lc5qacpi4ViMW5+KThTYtkwe9PwlZrWkPa5vW3QyKLkfdpe7KCVNr9yvMUHYU34XUFNEtZ259j20ctw8CJ4V5w==","mode":420,"size":146515},"dist/shared/nuxi.4ac76f59.mjs":{"checkedAt":1715158492693,"integrity":"sha512-EBIW3pPx0TZb22ys+CqLUEhEanuAACWlc4bDRT2dmKncTrQ1xbYbtIZs5FOtIKzF+FQcSARoo/ky1bWZ4Hlf+Q==","mode":420,"size":2085},"dist/shared/nuxi.53f5921c.mjs":{"checkedAt":1715158492694,"integrity":"sha512-xrNnJyyFv1md+t1xQuWDq+oLrNPd3Fy7eD4hVGByUQufEcxAmcrYvNZu4AfTKy858vQmOzxfvZpSy0s916XGag==","mode":420,"size":7021},"dist/shared/nuxi.5aaa4630.mjs":{"checkedAt":1715158492695,"integrity":"sha512-7nT7F3Dbl8IMCj/M/R/NQ2fs4xat/puQvq7MJaHv9HkxvPjqYIqS9ugpaxHv/U352p7i54Q1tocm1vwceAoouw==","mode":420,"size":660},"dist/shared/nuxi.610c92ff.mjs":{"checkedAt":1715158492695,"integrity":"sha512-u5bFXlIervtqaRkB8WK+ZJLBYHxtmxTT0NsQncJDTtZ/WkcOASN9Pg4kHXurvF0Ij24kiuQ/cPFX3vv2dmUgNA==","mode":420,"size":6782},"dist/shared/nuxi.73800aa7.mjs":{"checkedAt":1715158492741,"integrity":"sha512-/k9ztWp6NnBFe0LIYkgpJLIdM4mmeir89Bkc5TpTwyWq0h6D/WNG0atkhBmrLkzr27jPqutloYJcD2g+5U2bTw==","mode":420,"size":1905463},"dist/shared/nuxi.9edf0930.mjs":{"checkedAt":1715158492743,"integrity":"sha512-dTTMP2+SBds4kZpNbrGXgYZjMRxCcJ0pkhQQusm87kvS354AQaCMdjRYQic8sGUT2dwBtpjWo8YE++t7ds4QIg==","mode":420,"size":75206},"dist/shared/nuxi.c282fbf5.mjs":{"checkedAt":1715158492744,"integrity":"sha512-5k2EIpdYdL/YKoHf2p1bhF71eLEoCiUAZzCdZ0yMaVitZ34QKTRM7BwyAshPU6AD+FzEz+MUEwC+ESzwg+byFw==","mode":420,"size":19969},"dist/shared/nuxi.c8477004.mjs":{"checkedAt":1715158492745,"integrity":"sha512-CspyHUXcmdcCc+1IKAwwZ+cpW402HvsO6p6yrrO/oYlcmhP8nbPJQjgjkUATlgIFbMA9rsUaCv028/bxjhrlMA==","mode":420,"size":665},"dist/shared/nuxi.cc8dd4a9.mjs":{"checkedAt":1715158492745,"integrity":"sha512-i4qiduA5Hhxiqj677fc871PKSRQCD2MNVQDzKfo1GAKOy+adtTZyz7sRcHmN/8of75FvMXMyvNhaS146OLGZWQ==","mode":420,"size":8930},"dist/shared/nuxi.d3241ca4.mjs":{"checkedAt":1715158492745,"integrity":"sha512-23rTdZCwH1GvBbYIItyTm13OHY3pZvWWPoiKkT1lQbvZbRAwyF9M0FGbks8+tJsJ9D6/L4hrrkucI7HXsQIZZA==","mode":420,"size":3460},"dist/shared/nuxi.dc1b30dc.mjs":{"checkedAt":1715158492748,"integrity":"sha512-JdzwNWaHq++d8zuZI1oNfPR6Xt8khnIyCSLOyCFst/rBjaKp2x1KU7nuZ9zYSKNmZe7bcnC1paqs2IRGZywZXA==","mode":420,"size":68932},"dist/shared/nuxi.eaa29140.mjs":{"checkedAt":1715158492748,"integrity":"sha512-6QM77w4EVBUZWKRclsMBW7f8PJpLVydgq0T8L+1b+WWe2mBubcgEKCp7SfzGAk96tTJUCSfAyRCDTg9N85qtbQ==","mode":420,"size":1600},"bin/nuxi.mjs":{"checkedAt":1715158492748,"integrity":"sha512-fZWFwXMMjDoOEG9aJaU6jgUJclrX+6e34zfVxHjLllI/I9n6cp6f+ieZrvcE5/T1lklIbBAcmbcMoPWpAWGlvQ==","mode":493,"size":210},"dist/chunks/satisfies.mjs":{"checkedAt":1715158492750,"integrity":"sha512-xnK1t9bcWb6NIYV6NPgR5DIAtQ45nPBY4HbXobOlCvw6nDHAacwxSaRv7dB2x/secI9LSRBKxdR9MAtBkk6YcQ==","mode":420,"size":48907},"dist/chunks/prepare.mjs":{"checkedAt":1715158492752,"integrity":"sha512-4kXg4CIZhwObu4eu8PVifZrBwlVUZWFkzfJgtWVVLtRSDcJrlkxHk76pvBMWPrkVnulfUFR4TO8Un9iHw2iiFA==","mode":420,"size":1875},"dist/chunks/preview.mjs":{"checkedAt":1715158492756,"integrity":"sha512-eVn7m2aetFbXiWZSqY4XBrI0cYUNdFWXij4ueSLUzU8zmM6fupfRMD+iTaCMqxchfvf39Xh/R43MRQnuq4xQ9g==","mode":420,"size":4123},"dist/chunks/prompt.mjs":{"checkedAt":1715158492756,"integrity":"sha512-O/Epnph0tKqH6cQxZEeyQufomoOU+HOh54uyntjMV9cbbc70fLUfUyifooIwroLyzVtY//Oe6ZSMNKCfOBCW3g==","mode":420,"size":44064},"dist/chunks/upgrade.mjs":{"checkedAt":1715158492756,"integrity":"sha512-2rAKD7cbZ7eMDfDmayMooAvp6DQgFEwMEkksr+WJjgNcEeP6rU1B1D4vTEs69QxA+B6xEpt26SQKCtt+1F4HDQ==","mode":420,"size":4765},"dist/chunks/typecheck.mjs":{"checkedAt":1715158492756,"integrity":"sha512-5zIyM/wRThgpGE1RTvEISZD6yvFbT3Lq3N4u0/dDWpvUSy8KweKGT1FejfaxK6KSqcJdFYT6LAAzNg+LVbvO8A==","mode":420,"size":2398},"dist/chunks/search.mjs":{"checkedAt":1715158492756,"integrity":"sha512-KD1m9fQenjfI4m3X1bfUh6eeKGjoC4KqRDKIZXVTKaqasq+EM/DiYOzv60fvE0/yK7v3LTd2SLJ4mplMcksmNw==","mode":420,"size":45221},"dist/chunks/test.mjs":{"checkedAt":1715158492759,"integrity":"sha512-evjrwZ+KiCpv97hVvwJGWAl5xt9IYf4W33WxL87wDzoCwnpX1c0CDT6Gq5giBAJkTMSUkeVH6yBvQ3JNP2CpXg==","mode":420,"size":1596},"dist/chunks/xdg-open.mjs":{"checkedAt":1715158492760,"integrity":"sha512-B8w8NzhEmKEhDmTKTJ4zQfyjjNolXJttrcEaIqc2eKlIRAge8ZH88jk5Ogdy+p+R7UET86jsGCfVxTcIbaBROw==","mode":420,"size":25951},"dist/index.d.mts":{"checkedAt":1715158492762,"integrity":"sha512-bKZ9GYaM6GOK4Kqp5MnPttibrm+SzfQPZK0DYSMJ5AHBC2v2ReDJboYiRzPTvG4F9sd+HTYXnrVVO85UQBdhdg==","mode":420,"size":253},"dist/index.d.ts":{"checkedAt":1715158492762,"integrity":"sha512-bKZ9GYaM6GOK4Kqp5MnPttibrm+SzfQPZK0DYSMJ5AHBC2v2ReDJboYiRzPTvG4F9sd+HTYXnrVVO85UQBdhdg==","mode":420,"size":253}}} \ No newline at end of file diff --git a/.pnpm-store/v3/files/07/cc3c37384498a1210e64ca4c9e3341fca38cda255c9b6dadc11a22a73678a94844081ef191fcf239393a0772fa9f91ed4113f3a8ec1827d5c537086da0513b b/.pnpm-store/v3/files/07/cc3c37384498a1210e64ca4c9e3341fca38cda255c9b6dadc11a22a73678a94844081ef191fcf239393a0772fa9f91ed4113f3a8ec1827d5c537086da0513b new file mode 100644 index 0000000000000000000000000000000000000000..8fd6b007c22016ceb16aba4b95d801f0250ad78d --- /dev/null +++ b/.pnpm-store/v3/files/07/cc3c37384498a1210e64ca4c9e3341fca38cda255c9b6dadc11a22a73678a94844081ef191fcf239393a0772fa9f91ed4113f3a8ec1827d5c537086da0513b @@ -0,0 +1,1069 @@ +const xdgOpenScript = () => `#!/bin/sh +#--------------------------------------------- +# xdg-open +# +# Utility script to open a URL in the registered default application. +# +# Refer to the usage() function below for usage. +# +# Copyright 2009-2010, Fathi Boudra +# Copyright 2009-2010, Rex Dieter +# Copyright 2006, Kevin Krammer +# Copyright 2006, Jeremy White +# +# LICENSE: +# +# Permission is hereby granted, free of charge, to any person obtaining a +# copy of this software and associated documentation files (the "Software"), +# to deal in the Software without restriction, including without limitation +# the rights to use, copy, modify, merge, publish, distribute, sublicense, +# and/or sell copies of the Software, and to permit persons to whom the +# Software is furnished to do so, subject to the following conditions: +# +# The above copyright notice and this permission notice shall be included +# in all copies or substantial portions of the Software. +# +# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS +# OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL +# THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR +# OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, +# ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR +# OTHER DEALINGS IN THE SOFTWARE. +# +#--------------------------------------------- + +manualpage() +{ +cat << _MANUALPAGE +Name + + xdg-open -- opens a file or URL in the user's preferred + application + +Synopsis + + xdg-open { file | URL } + + xdg-open { --help | --manual | --version } + +Description + + xdg-open opens a file or URL in the user's preferred + application. If a URL is provided the URL will be opened in the + user's preferred web browser. If a file is provided the file + will be opened in the preferred application for files of that + type. xdg-open supports file, ftp, http and https URLs. + + xdg-open is for use inside a desktop session only. It is not + recommended to use xdg-open as root. + +Options + + --help + Show command synopsis. + + --manual + Show this manual page. + + --version + Show the xdg-utils version information. + +Exit Codes + + An exit code of 0 indicates success while a non-zero exit code + indicates failure. The following failure codes can be returned: + + 1 + Error in command line syntax. + + 2 + One of the files passed on the command line did not + exist. + + 3 + A required tool could not be found. + + 4 + The action failed. + +See Also + + xdg-mime(1), xdg-settings(1), MIME applications associations + specification + +Examples + +xdg-open 'http://www.freedesktop.org/' + + Opens the freedesktop.org website in the user's default + browser. + +xdg-open /tmp/foobar.png + + Opens the PNG image file /tmp/foobar.png in the user's default + image viewing application. +_MANUALPAGE +} + +usage() +{ +cat << _USAGE + xdg-open -- opens a file or URL in the user's preferred + application + +Synopsis + + xdg-open { file | URL } + + xdg-open { --help | --manual | --version } + +_USAGE +} + +#@xdg-utils-common@ + +#---------------------------------------------------------------------------- +# Common utility functions included in all XDG wrapper scripts +#---------------------------------------------------------------------------- + +DEBUG() +{ + [ -z "\${XDG_UTILS_DEBUG_LEVEL}" ] && return 0; + [ \${XDG_UTILS_DEBUG_LEVEL} -lt $1 ] && return 0; + shift + echo "$@" >&2 +} + +# This handles backslashes but not quote marks. +first_word() +{ + read first rest + echo "$first" +} + +#------------------------------------------------------------- +# map a binary to a .desktop file +binary_to_desktop_file() +{ + search="\${XDG_DATA_HOME:-$HOME/.local/share}:\${XDG_DATA_DIRS:-/usr/local/share:/usr/share}" + binary="\`which "$1"\`" + binary="\`readlink -f "$binary"\`" + base="\`basename "$binary"\`" + IFS=: + for dir in $search; do + unset IFS + [ "$dir" ] || continue + [ -d "$dir/applications" ] || [ -d "$dir/applnk" ] || continue + for file in "$dir"/applications/*.desktop "$dir"/applications/*/*.desktop "$dir"/applnk/*.desktop "$dir"/applnk/*/*.desktop; do + [ -r "$file" ] || continue + # Check to make sure it's worth the processing. + grep -q "^Exec.*$base" "$file" || continue + # Make sure it's a visible desktop file (e.g. not "preferred-web-browser.desktop"). + grep -Eq "^(NoDisplay|Hidden)=true" "$file" && continue + command="\`grep -E "^Exec(\\[[^]=]*])?=" "$file" | cut -d= -f 2- | first_word\`" + command="\`which "$command"\`" + if [ x"\`readlink -f "$command"\`" = x"$binary" ]; then + # Fix any double slashes that got added path composition + echo "$file" | sed -e 's,//*,/,g' + return + fi + done + done +} + +#------------------------------------------------------------- +# map a .desktop file to a binary +desktop_file_to_binary() +{ + search="\${XDG_DATA_HOME:-$HOME/.local/share}:\${XDG_DATA_DIRS:-/usr/local/share:/usr/share}" + desktop="\`basename "$1"\`" + IFS=: + for dir in $search; do + unset IFS + [ "$dir" ] && [ -d "$dir/applications" ] || [ -d "$dir/applnk" ] || continue + # Check if desktop file contains - + if [ "\${desktop#*-}" != "$desktop" ]; then + vendor=\${desktop%-*} + app=\${desktop#*-} + if [ -r $dir/applications/$vendor/$app ]; then + file_path=$dir/applications/$vendor/$app + elif [ -r $dir/applnk/$vendor/$app ]; then + file_path=$dir/applnk/$vendor/$app + fi + fi + if test -z "$file_path" ; then + for indir in "$dir"/applications/ "$dir"/applications/*/ "$dir"/applnk/ "$dir"/applnk/*/; do + file="$indir/$desktop" + if [ -r "$file" ]; then + file_path=$file + break + fi + done + fi + if [ -r "$file_path" ]; then + # Remove any arguments (%F, %f, %U, %u, etc.). + command="\`grep -E "^Exec(\\[[^]=]*])?=" "$file_path" | cut -d= -f 2- | first_word\`" + command="\`which "$command"\`" + readlink -f "$command" + return + fi + done +} + +#------------------------------------------------------------- +# Exit script on successfully completing the desired operation + +exit_success() +{ + if [ $# -gt 0 ]; then + echo "$@" + echo + fi + + exit 0 +} + + +#----------------------------------------- +# Exit script on malformed arguments, not enough arguments +# or missing required option. +# prints usage information + +exit_failure_syntax() +{ + if [ $# -gt 0 ]; then + echo "xdg-open: $@" >&2 + echo "Try 'xdg-open --help' for more information." >&2 + else + usage + echo "Use 'man xdg-open' or 'xdg-open --manual' for additional info." + fi + + exit 1 +} + +#------------------------------------------------------------- +# Exit script on missing file specified on command line + +exit_failure_file_missing() +{ + if [ $# -gt 0 ]; then + echo "xdg-open: $@" >&2 + fi + + exit 2 +} + +#------------------------------------------------------------- +# Exit script on failure to locate necessary tool applications + +exit_failure_operation_impossible() +{ + if [ $# -gt 0 ]; then + echo "xdg-open: $@" >&2 + fi + + exit 3 +} + +#------------------------------------------------------------- +# Exit script on failure returned by a tool application + +exit_failure_operation_failed() +{ + if [ $# -gt 0 ]; then + echo "xdg-open: $@" >&2 + fi + + exit 4 +} + +#------------------------------------------------------------ +# Exit script on insufficient permission to read a specified file + +exit_failure_file_permission_read() +{ + if [ $# -gt 0 ]; then + echo "xdg-open: $@" >&2 + fi + + exit 5 +} + +#------------------------------------------------------------ +# Exit script on insufficient permission to write a specified file + +exit_failure_file_permission_write() +{ + if [ $# -gt 0 ]; then + echo "xdg-open: $@" >&2 + fi + + exit 6 +} + +check_input_file() +{ + if [ ! -e "$1" ]; then + exit_failure_file_missing "file '$1' does not exist" + fi + if [ ! -r "$1" ]; then + exit_failure_file_permission_read "no permission to read file '$1'" + fi +} + +check_vendor_prefix() +{ + file_label="$2" + [ -n "$file_label" ] || file_label="filename" + file=\`basename "$1"\` + case "$file" in + [[:alpha:]]*-*) + return + ;; + esac + + echo "xdg-open: $file_label '$file' does not have a proper vendor prefix" >&2 + echo 'A vendor prefix consists of alpha characters ([a-zA-Z]) and is terminated' >&2 + echo 'with a dash ("-"). An example '"$file_label"' is '"'example-$file'" >&2 + echo "Use --novendor to override or 'xdg-open --manual' for additional info." >&2 + exit 1 +} + +check_output_file() +{ + # if the file exists, check if it is writeable + # if it does not exists, check if we are allowed to write on the directory + if [ -e "$1" ]; then + if [ ! -w "$1" ]; then + exit_failure_file_permission_write "no permission to write to file '$1'" + fi + else + DIR=\`dirname "$1"\` + if [ ! -w "$DIR" ] || [ ! -x "$DIR" ]; then + exit_failure_file_permission_write "no permission to create file '$1'" + fi + fi +} + +#---------------------------------------- +# Checks for shared commands, e.g. --help + +check_common_commands() +{ + while [ $# -gt 0 ] ; do + parm="$1" + shift + + case "$parm" in + --help) + usage + echo "Use 'man xdg-open' or 'xdg-open --manual' for additional info." + exit_success + ;; + + --manual) + manualpage + exit_success + ;; + + --version) + echo "xdg-open 1.1.3" + exit_success + ;; + esac + done +} + +check_common_commands "$@" + +[ -z "\${XDG_UTILS_DEBUG_LEVEL}" ] && unset XDG_UTILS_DEBUG_LEVEL; +if [ \${XDG_UTILS_DEBUG_LEVEL-0} -lt 1 ]; then + # Be silent + xdg_redirect_output=" > /dev/null 2> /dev/null" +else + # All output to stderr + xdg_redirect_output=" >&2" +fi + +#-------------------------------------- +# Checks for known desktop environments +# set variable DE to the desktop environments name, lowercase + +detectDE() +{ + # see https://bugs.freedesktop.org/show_bug.cgi?id=34164 + unset GREP_OPTIONS + + if [ -n "\${XDG_CURRENT_DESKTOP}" ]; then + case "\${XDG_CURRENT_DESKTOP}" in + # only recently added to menu-spec, pre-spec X- still in use + Cinnamon|X-Cinnamon) + DE=cinnamon; + ;; + ENLIGHTENMENT) + DE=enlightenment; + ;; + # GNOME, GNOME-Classic:GNOME, or GNOME-Flashback:GNOME + GNOME*) + DE=gnome; + ;; + KDE) + DE=kde; + ;; + # Deepin Desktop Environments + DEEPIN|Deepin|deepin) + DE=dde; + ;; + LXDE) + DE=lxde; + ;; + LXQt) + DE=lxqt; + ;; + MATE) + DE=mate; + ;; + XFCE) + DE=xfce + ;; + X-Generic) + DE=generic + ;; + esac + fi + + if [ x"$DE" = x"" ]; then + # classic fallbacks + if [ x"$KDE_FULL_SESSION" != x"" ]; then DE=kde; + elif [ x"$GNOME_DESKTOP_SESSION_ID" != x"" ]; then DE=gnome; + elif [ x"$MATE_DESKTOP_SESSION_ID" != x"" ]; then DE=mate; + elif \`dbus-send --print-reply --dest=org.freedesktop.DBus /org/freedesktop/DBus org.freedesktop.DBus.GetNameOwner string:org.gnome.SessionManager > /dev/null 2>&1\` ; then DE=gnome; + elif xprop -root _DT_SAVE_MODE 2> /dev/null | grep ' = \\"xfce4\\"$' >/dev/null 2>&1; then DE=xfce; + elif xprop -root 2> /dev/null | grep -i '^xfce_desktop_window' >/dev/null 2>&1; then DE=xfce + elif echo $DESKTOP | grep -q '^Enlightenment'; then DE=enlightenment; + elif [ x"$LXQT_SESSION_CONFIG" != x"" ]; then DE=lxqt; + fi + fi + + if [ x"$DE" = x"" ]; then + # fallback to checking $DESKTOP_SESSION + case "$DESKTOP_SESSION" in + gnome) + DE=gnome; + ;; + LXDE|Lubuntu) + DE=lxde; + ;; + MATE) + DE=mate; + ;; + xfce|xfce4|'Xfce Session') + DE=xfce; + ;; + esac + fi + + if [ x"$DE" = x"" ]; then + # fallback to uname output for other platforms + case "$(uname 2>/dev/null)" in + CYGWIN*) + DE=cygwin; + ;; + Darwin) + DE=darwin; + ;; + esac + fi + + if [ x"$DE" = x"gnome" ]; then + # gnome-default-applications-properties is only available in GNOME 2.x + # but not in GNOME 3.x + which gnome-default-applications-properties > /dev/null 2>&1 || DE="gnome3" + fi + + if [ -f "$XDG_RUNTIME_DIR/flatpak-info" ]; then + DE="flatpak" + fi +} + +#---------------------------------------------------------------------------- +# kfmclient exec/openURL can give bogus exit value in KDE <= 3.5.4 +# It also always returns 1 in KDE 3.4 and earlier +# Simply return 0 in such case + +kfmclient_fix_exit_code() +{ + version=\`LC_ALL=C.UTF-8 kde-config --version 2>/dev/null | grep '^KDE'\` + major=\`echo $version | sed 's/KDE.*: \\([0-9]\\).*/\\1/'\` + minor=\`echo $version | sed 's/KDE.*: [0-9]*\\.\\([0-9]\\).*/\\1/'\` + release=\`echo $version | sed 's/KDE.*: [0-9]*\\.[0-9]*\\.\\([0-9]\\).*/\\1/'\` + test "$major" -gt 3 && return $1 + test "$minor" -gt 5 && return $1 + test "$release" -gt 4 && return $1 + return 0 +} + +#---------------------------------------------------------------------------- +# Returns true if there is a graphical display attached. + +has_display() +{ + if [ -n "$DISPLAY" ] || [ -n "$WAYLAND_DISPLAY" ]; then + return 0 + else + return 1 + fi +} + +# This handles backslashes but not quote marks. +last_word() +{ + read first rest + echo "$rest" +} + +# Get the value of a key in a desktop file's Desktop Entry group. +# Example: Use get_key foo.desktop Exec +# to get the values of the Exec= key for the Desktop Entry group. +get_key() +{ + local file="\${1}" + local key="\${2}" + local desktop_entry="" + + IFS_="\${IFS}" + IFS="" + while read line + do + case "$line" in + "[Desktop Entry]") + desktop_entry="y" + ;; + # Reset match flag for other groups + "["*) + desktop_entry="" + ;; + "\${key}="*) + # Only match Desktop Entry group + if [ -n "\${desktop_entry}" ] + then + echo "\${line}" | cut -d= -f 2- + fi + esac + done < "\${file}" + IFS="\${IFS_}" +} + +# Returns true if argument is a file:// URL or path +is_file_url_or_path() +{ + if echo "$1" | grep -q '^file://' \\ + || ! echo "$1" | egrep -q '^[[:alpha:]+\\.\\-]+:'; then + return 0 + else + return 1 + fi +} + +# If argument is a file URL, convert it to a (percent-decoded) path. +# If not, leave it as it is. +file_url_to_path() +{ + local file="$1" + if echo "$file" | grep -q '^file:///'; then + file=\${file#file://} + file=\${file%%#*} + file=$(echo "$file" | sed -r 's/\\?.*$//') + local printf=printf + if [ -x /usr/bin/printf ]; then + printf=/usr/bin/printf + fi + file=$($printf "$(echo "$file" | sed -e 's@%\\([a-f0-9A-F]\\{2\\}\\)@\\\\x\\1@g')") + fi + echo "$file" +} + +open_cygwin() +{ + cygstart "$1" + + if [ $? -eq 0 ]; then + exit_success + else + exit_failure_operation_failed + fi +} + +open_darwin() +{ + open "$1" + + if [ $? -eq 0 ]; then + exit_success + else + exit_failure_operation_failed + fi +} + +open_kde() +{ + if [ -n "\${KDE_SESSION_VERSION}" ]; then + case "\${KDE_SESSION_VERSION}" in + 4) + kde-open "$1" + ;; + 5) + kde-open\${KDE_SESSION_VERSION} "$1" + ;; + esac + else + kfmclient exec "$1" + kfmclient_fix_exit_code $? + fi + + if [ $? -eq 0 ]; then + exit_success + else + exit_failure_operation_failed + fi +} + +open_dde() +{ + if dde-open -version >/dev/null 2>&1; then + dde-open "$1" + else + open_generic "$1" + fi + + if [ $? -eq 0 ]; then + exit_success + else + exit_failure_operation_failed + fi +} + +open_gnome3() +{ + if gio help open 2>/dev/null 1>&2; then + gio open "$1" + elif gvfs-open --help 2>/dev/null 1>&2; then + gvfs-open "$1" + else + open_generic "$1" + fi + + if [ $? -eq 0 ]; then + exit_success + else + exit_failure_operation_failed + fi +} + +open_gnome() +{ + if gio help open 2>/dev/null 1>&2; then + gio open "$1" + elif gvfs-open --help 2>/dev/null 1>&2; then + gvfs-open "$1" + elif gnome-open --help 2>/dev/null 1>&2; then + gnome-open "$1" + else + open_generic "$1" + fi + + if [ $? -eq 0 ]; then + exit_success + else + exit_failure_operation_failed + fi +} + +open_mate() +{ + if gio help open 2>/dev/null 1>&2; then + gio open "$1" + elif gvfs-open --help 2>/dev/null 1>&2; then + gvfs-open "$1" + elif mate-open --help 2>/dev/null 1>&2; then + mate-open "$1" + else + open_generic "$1" + fi + + if [ $? -eq 0 ]; then + exit_success + else + exit_failure_operation_failed + fi +} + +open_xfce() +{ + if exo-open --help 2>/dev/null 1>&2; then + exo-open "$1" + elif gio help open 2>/dev/null 1>&2; then + gio open "$1" + elif gvfs-open --help 2>/dev/null 1>&2; then + gvfs-open "$1" + else + open_generic "$1" + fi + + if [ $? -eq 0 ]; then + exit_success + else + exit_failure_operation_failed + fi +} + +open_enlightenment() +{ + if enlightenment_open --help 2>/dev/null 1>&2; then + enlightenment_open "$1" + else + open_generic "$1" + fi + + if [ $? -eq 0 ]; then + exit_success + else + exit_failure_operation_failed + fi +} + +open_flatpak() +{ + gdbus call --session \\ + --dest org.freedesktop.portal.Desktop \\ + --object-path /org/freedesktop/portal/desktop \\ + --method org.freedesktop.portal.OpenURI.OpenURI \\ + "" "$1" {} + + if [ $? -eq 0 ]; then + exit_success + else + exit_failure_operation_failed + fi +} + +#----------------------------------------- +# Recursively search .desktop file + +search_desktop_file() +{ + local default="$1" + local dir="$2" + local target="$3" + + local file="" + # look for both vendor-app.desktop, vendor/app.desktop + if [ -r "$dir/$default" ]; then + file="$dir/$default" + elif [ -r "$dir/\`echo $default | sed -e 's|-|/|'\`" ]; then + file="$dir/\`echo $default | sed -e 's|-|/|'\`" + fi + + if [ -r "$file" ] ; then + command="$(get_key "\${file}" "Exec" | first_word)" + command_exec=\`which $command 2>/dev/null\` + icon="$(get_key "\${file}" "Icon")" + # FIXME: Actually LC_MESSAGES should be used as described in + # http://standards.freedesktop.org/desktop-entry-spec/latest/ar01s04.html + localised_name="$(get_key "\${file}" "Name")" + set -- $(get_key "\${file}" "Exec" | last_word) + # We need to replace any occurrence of "%f", "%F" and + # the like by the target file. We examine each + # argument and append the modified argument to the + # end then shift. + local args=$# + local replaced=0 + while [ $args -gt 0 ]; do + case $1 in + %[c]) + replaced=1 + arg="\${localised_name}" + shift + set -- "$@" "$arg" + ;; + %[fFuU]) + replaced=1 + arg="$target" + shift + set -- "$@" "$arg" + ;; + %[i]) + replaced=1 + shift + set -- "$@" "--icon" "$icon" + ;; + *) + arg="$1" + shift + set -- "$@" "$arg" + ;; + esac + args=$(( $args - 1 )) + done + [ $replaced -eq 1 ] || set -- "$@" "$target" + "$command_exec" "$@" + + if [ $? -eq 0 ]; then + exit_success + fi + fi + + for d in $dir/*/; do + [ -d "$d" ] && search_desktop_file "$default" "$d" "$target" + done +} + + +open_generic_xdg_mime() +{ + filetype="$2" + default=\`xdg-mime query default "$filetype"\` + if [ -n "$default" ] ; then + xdg_user_dir="$XDG_DATA_HOME" + [ -n "$xdg_user_dir" ] || xdg_user_dir="$HOME/.local/share" + + xdg_system_dirs="$XDG_DATA_DIRS" + [ -n "$xdg_system_dirs" ] || xdg_system_dirs=/usr/local/share/:/usr/share/ + +DEBUG 3 "$xdg_user_dir:$xdg_system_dirs" + for x in \`echo "$xdg_user_dir:$xdg_system_dirs" | sed 's/:/ /g'\`; do + search_desktop_file "$default" "$x/applications/" "$1" + done + fi +} + +open_generic_xdg_file_mime() +{ + filetype=\`xdg-mime query filetype "$1" | sed "s/;.*//"\` + open_generic_xdg_mime "$1" "$filetype" +} + +open_generic_xdg_x_scheme_handler() +{ + scheme="\`echo $1 | sed -n 's/\\(^[[:alnum:]+\\.-]*\\):.*$/\\1/p'\`" + if [ -n $scheme ]; then + filetype="x-scheme-handler/$scheme" + open_generic_xdg_mime "$1" "$filetype" + fi +} + +has_single_argument() +{ + test $# = 1 +} + +open_envvar() +{ + local oldifs="$IFS" + local browser browser_with_arg + + IFS=":" + for browser in $BROWSER; do + IFS="$oldifs" + + if [ -z "$browser" ]; then + continue + fi + + if echo "$browser" | grep -q %s; then + # Avoid argument injection. + # See https://bugs.freedesktop.org/show_bug.cgi?id=103807 + # URIs don't have IFS characters spaces anyway. + has_single_argument $1 && $(printf "$browser" "$1") + else + $browser "$1" + fi + + if [ $? -eq 0 ]; then + exit_success + fi + done +} + +open_generic() +{ + if is_file_url_or_path "$1"; then + local file="$(file_url_to_path "$1")" + + check_input_file "$file" + + if has_display; then + filetype=\`xdg-mime query filetype "$file" | sed "s/;.*//"\` + open_generic_xdg_mime "$file" "$filetype" + fi + + if which run-mailcap 2>/dev/null 1>&2; then + run-mailcap --action=view "$file" + if [ $? -eq 0 ]; then + exit_success + fi + fi + + if has_display && mimeopen -v 2>/dev/null 1>&2; then + mimeopen -L -n "$file" + if [ $? -eq 0 ]; then + exit_success + fi + fi + fi + + if has_display; then + open_generic_xdg_x_scheme_handler "$1" + fi + + if [ -n "$BROWSER" ]; then + open_envvar "$1" + fi + + # if BROWSER variable is not set, check some well known browsers instead + if [ x"$BROWSER" = x"" ]; then + BROWSER=www-browser:links2:elinks:links:lynx:w3m + if has_display; then + BROWSER=x-www-browser:firefox:iceweasel:seamonkey:mozilla:epiphany:konqueror:chromium:chromium-browser:google-chrome:microsoft-edge:$BROWSER + fi + fi + + open_envvar "$1" + + exit_failure_operation_impossible "no method available for opening '$1'" +} + +open_lxde() +{ + + # pcmanfm only knows how to handle file:// urls and filepaths, it seems. + if pcmanfm --help >/dev/null 2>&1 && is_file_url_or_path "$1"; then + local file="$(file_url_to_path "$1")" + + # handle relative paths + if ! echo "$file" | grep -q ^/; then + file="$(pwd)/$file" + fi + + pcmanfm "$file" + else + open_generic "$1" + fi + + if [ $? -eq 0 ]; then + exit_success + else + exit_failure_operation_failed + fi +} + +open_lxqt() +{ + open_generic "$1" +} + +[ x"$1" != x"" ] || exit_failure_syntax + +url= +while [ $# -gt 0 ] ; do + parm="$1" + shift + + case "$parm" in + -*) + exit_failure_syntax "unexpected option '$parm'" + ;; + + *) + if [ -n "$url" ] ; then + exit_failure_syntax "unexpected argument '$parm'" + fi + url="$parm" + ;; + esac +done + +if [ -z "\${url}" ] ; then + exit_failure_syntax "file or URL argument missing" +fi + +detectDE + +if [ x"$DE" = x"" ]; then + DE=generic +fi + +DEBUG 2 "Selected DE $DE" + +# sanitize BROWSER (avoid caling ourselves in particular) +case "\${BROWSER}" in + *:"xdg-open"|"xdg-open":*) + BROWSER=$(echo $BROWSER | sed -e 's|:xdg-open||g' -e 's|xdg-open:||g') + ;; + "xdg-open") + BROWSER= + ;; +esac + +case "$DE" in + kde) + open_kde "$url" + ;; + + dde) + open_dde "$url" + ;; + + gnome3|cinnamon) + open_gnome3 "$url" + ;; + + gnome) + open_gnome "$url" + ;; + + mate) + open_mate "$url" + ;; + + xfce) + open_xfce "$url" + ;; + + lxde) + open_lxde "$url" + ;; + + lxqt) + open_lxqt "$url" + ;; + + enlightenment) + open_enlightenment "$url" + ;; + + cygwin) + open_cygwin "$url" + ;; + + darwin) + open_darwin "$url" + ;; + + flatpak) + open_flatpak "$url" + ;; + + generic) + open_generic "$url" + ;; + + *) + exit_failure_operation_impossible "no method available for opening '$url'" + ;; +esac +`; + +export { xdgOpenScript }; diff --git a/.pnpm-store/v3/files/0a/ca721d45dc99d70273ed48280c3067e7295b8d361efb0eea9eb2aeb3bfa1895c9a13fc9db3c94238239140139602056cc03daec51a0afd36f3f6f18e1ae530 b/.pnpm-store/v3/files/0a/ca721d45dc99d70273ed48280c3067e7295b8d361efb0eea9eb2aeb3bfa1895c9a13fc9db3c94238239140139602056cc03daec51a0afd36f3f6f18e1ae530 new file mode 100644 index 0000000000000000000000000000000000000000..7ac92ff0b66bda08bba0d7f621961f789ed44cff --- /dev/null +++ b/.pnpm-store/v3/files/0a/ca721d45dc99d70273ed48280c3067e7295b8d361efb0eea9eb2aeb3bfa1895c9a13fc9db3c94238239140139602056cc03daec51a0afd36f3f6f18e1ae530 @@ -0,0 +1,17 @@ +import { g as gray, a as green, b as bold } from './nuxi.d3241ca4.mjs'; +import { t as tryRequireModule } from './nuxi.5aaa4630.mjs'; + +function showVersions(cwd) { + const getPkgVersion = (pkg) => { + return tryRequireModule(`${pkg}/package.json`, cwd)?.version || ""; + }; + const nuxtVersion = getPkgVersion("nuxt") || getPkgVersion("nuxt-nightly") || getPkgVersion("nuxt3") || getPkgVersion("nuxt-edge"); + const nitroVersion = getPkgVersion("nitropack") || getPkgVersion("nitropack-edge"); + console.log( + gray( + green(`Nuxt ${bold(nuxtVersion)}`) + (nitroVersion ? ` with Nitro ${bold(nitroVersion)}` : "") + ) + ); +} + +export { showVersions as s }; diff --git a/.pnpm-store/v3/files/0c/829cd953ccfeaae048e9b01fc50bf349e1d456717f69a5fcbfae32821c3fd75264237724164accccea566a404cc97922ad413605356776dff7f4a9d1c21331 b/.pnpm-store/v3/files/0c/829cd953ccfeaae048e9b01fc50bf349e1d456717f69a5fcbfae32821c3fd75264237724164accccea566a404cc97922ad413605356776dff7f4a9d1c21331 new file mode 100644 index 0000000000000000000000000000000000000000..39257c296e67f2e252c114830471d3f8d0d0978a --- /dev/null +++ b/.pnpm-store/v3/files/0c/829cd953ccfeaae048e9b01fc50bf349e1d456717f69a5fcbfae32821c3fd75264237724164accccea566a404cc97922ad413605356776dff7f4a9d1c21331 @@ -0,0 +1,56 @@ +const NUMBER_CHAR_RE = /\d/; +const STR_SPLITTERS = ["-", "_", "/", "."]; +function isUppercase(char = "") { + if (NUMBER_CHAR_RE.test(char)) { + return void 0; + } + return char !== char.toLowerCase(); +} +function splitByCase(str, separators) { + const splitters = separators ?? STR_SPLITTERS; + const parts = []; + if (!str || typeof str !== "string") { + return parts; + } + let buff = ""; + let previousUpper; + let previousSplitter; + for (const char of str) { + const isSplitter = splitters.includes(char); + if (isSplitter === true) { + parts.push(buff); + buff = ""; + previousUpper = void 0; + continue; + } + const isUpper = isUppercase(char); + if (previousSplitter === false) { + if (previousUpper === false && isUpper === true) { + parts.push(buff); + buff = char; + previousUpper = isUpper; + continue; + } + if (previousUpper === true && isUpper === false && buff.length > 1) { + const lastChar = buff.at(-1); + parts.push(buff.slice(0, Math.max(0, buff.length - 1))); + buff = lastChar + char; + previousUpper = isUpper; + continue; + } + } + buff += char; + previousUpper = isUpper; + previousSplitter = isSplitter; + } + parts.push(buff); + return parts; +} +function upperFirst(str) { + return str ? str[0].toUpperCase() + str.slice(1) : ""; +} +function kebabCase(str, joiner) { + return str ? (Array.isArray(str) ? str : splitByCase(str)).map((p) => p.toLowerCase()).join(joiner ?? "-") : ""; +} + +export { kebabCase as k, splitByCase as s, upperFirst as u }; diff --git a/.pnpm-store/v3/files/10/037726b70360ca0f3e02588fd9117c8d16debbfbf48e764a8ff3dfa0b5d2401ae0e8e52fb23082e71477a7ba5b3fa4f440c565293d3d312b00526c2464d025 b/.pnpm-store/v3/files/10/037726b70360ca0f3e02588fd9117c8d16debbfbf48e764a8ff3dfa0b5d2401ae0e8e52fb23082e71477a7ba5b3fa4f440c565293d3d312b00526c2464d025 new file mode 100644 index 0000000000000000000000000000000000000000..eeea0b9c947337f8afa3eba2bb23e3e754d7beef --- /dev/null +++ b/.pnpm-store/v3/files/10/037726b70360ca0f3e02588fd9117c8d16debbfbf48e764a8ff3dfa0b5d2401ae0e8e52fb23082e71477a7ba5b3fa4f440c565293d3d312b00526c2464d025 @@ -0,0 +1,32 @@ +var commonjsGlobal = typeof globalThis !== 'undefined' ? globalThis : typeof window !== 'undefined' ? window : typeof global !== 'undefined' ? global : typeof self !== 'undefined' ? self : {}; + +function getDefaultExportFromCjs (x) { + return x && x.__esModule && Object.prototype.hasOwnProperty.call(x, 'default') ? x['default'] : x; +} + +function getAugmentedNamespace(n) { + if (n.__esModule) return n; + var f = n.default; + if (typeof f == "function") { + var a = function a () { + if (this instanceof a) { + return Reflect.construct(f, arguments, this.constructor); + } + return f.apply(this, arguments); + }; + a.prototype = f.prototype; + } else a = {}; + Object.defineProperty(a, '__esModule', {value: true}); + Object.keys(n).forEach(function (k) { + var d = Object.getOwnPropertyDescriptor(n, k); + Object.defineProperty(a, k, d.get ? d : { + enumerable: true, + get: function () { + return n[k]; + } + }); + }); + return a; +} + +export { getAugmentedNamespace as a, commonjsGlobal as c, getDefaultExportFromCjs as g }; diff --git a/.pnpm-store/v3/files/10/1216de93f1d1365bdb6cacf82a8b5048446a7b800025a57386c3453d9d98a9dc4eb435c5b61bb4866ce453ad20acc5f8541c480468a3f932d5b599e0795ff9 b/.pnpm-store/v3/files/10/1216de93f1d1365bdb6cacf82a8b5048446a7b800025a57386c3453d9d98a9dc4eb435c5b61bb4866ce453ad20acc5f8541c480468a3f932d5b599e0795ff9 new file mode 100644 index 0000000000000000000000000000000000000000..bf8bee245e263f1ebb57ac2bbff755f65e191e2c --- /dev/null +++ b/.pnpm-store/v3/files/10/1216de93f1d1365bdb6cacf82a8b5048446a7b800025a57386c3453d9d98a9dc4eb435c5b61bb4866ce453ad20acc5f8541c480468a3f932d5b599e0795ff9 @@ -0,0 +1,71 @@ +const suspectProtoRx = /"(?:_|\\u0{2}5[Ff]){2}(?:p|\\u0{2}70)(?:r|\\u0{2}72)(?:o|\\u0{2}6[Ff])(?:t|\\u0{2}74)(?:o|\\u0{2}6[Ff])(?:_|\\u0{2}5[Ff]){2}"\s*:/; +const suspectConstructorRx = /"(?:c|\\u0063)(?:o|\\u006[Ff])(?:n|\\u006[Ee])(?:s|\\u0073)(?:t|\\u0074)(?:r|\\u0072)(?:u|\\u0075)(?:c|\\u0063)(?:t|\\u0074)(?:o|\\u006[Ff])(?:r|\\u0072)"\s*:/; +const JsonSigRx = /^\s*["[{]|^\s*-?\d{1,16}(\.\d{1,17})?([Ee][+-]?\d+)?\s*$/; +function jsonParseTransform(key, value) { + if (key === "__proto__" || key === "constructor" && value && typeof value === "object" && "prototype" in value) { + warnKeyDropped(key); + return; + } + return value; +} +function warnKeyDropped(key) { + console.warn(`[destr] Dropping "${key}" key to prevent prototype pollution.`); +} +function destr(value, options = {}) { + if (typeof value !== "string") { + return value; + } + const _value = value.trim(); + if ( + // eslint-disable-next-line unicorn/prefer-at + value[0] === '"' && value.endsWith('"') && !value.includes("\\") + ) { + return _value.slice(1, -1); + } + if (_value.length <= 9) { + const _lval = _value.toLowerCase(); + if (_lval === "true") { + return true; + } + if (_lval === "false") { + return false; + } + if (_lval === "undefined") { + return void 0; + } + if (_lval === "null") { + return null; + } + if (_lval === "nan") { + return Number.NaN; + } + if (_lval === "infinity") { + return Number.POSITIVE_INFINITY; + } + if (_lval === "-infinity") { + return Number.NEGATIVE_INFINITY; + } + } + if (!JsonSigRx.test(value)) { + if (options.strict) { + throw new SyntaxError("[destr] Invalid JSON"); + } + return value; + } + try { + if (suspectProtoRx.test(value) || suspectConstructorRx.test(value)) { + if (options.strict) { + throw new Error("[destr] Possible prototype pollution"); + } + return JSON.parse(value, jsonParseTransform); + } + return JSON.parse(value); + } catch (error) { + if (options.strict) { + throw error; + } + return value; + } +} + +export { destr as d }; diff --git a/.pnpm-store/v3/files/16/48a131424c61358fa6cf7edf4be8950eab8846195013f320a25afccec31e4f37069ad39cef79c8be955a68d2ca8d271e8a01d4a7e58c43e5a120b80940c4e3 b/.pnpm-store/v3/files/16/48a131424c61358fa6cf7edf4be8950eab8846195013f320a25afccec31e4f37069ad39cef79c8be955a68d2ca8d271e8a01d4a7e58c43e5a120b80940c4e3 new file mode 100644 index 0000000000000000000000000000000000000000..14dd1e8f99f705cfe03b4f3dcda2f583b7b6d3d5 --- /dev/null +++ b/.pnpm-store/v3/files/16/48a131424c61358fa6cf7edf4be8950eab8846195013f320a25afccec31e4f37069ad39cef79c8be955a68d2ca8d271e8a01d4a7e58c43e5a120b80940c4e3 @@ -0,0 +1,556 @@ +import Et from 'node:http'; +import https from 'node:https'; +import { EventEmitter } from 'node:events'; + +const upgradeHeader = /(^|,)\s*upgrade\s*($|,)/i; +const isSSL = /^https|wss/; +function setupOutgoing(outgoing, options, req, forward) { + outgoing.port = options[forward || "target"].port || (isSSL.test(options[forward || "target"].protocol) ? 443 : 80); + for (const e of [ + "host", + "hostname", + "socketPath", + "pfx", + "key", + "passphrase", + "cert", + "ca", + "ciphers", + "secureProtocol" + ]) { + outgoing[e] = options[forward || "target"][e]; + } + outgoing.method = options.method || req.method; + outgoing.headers = { ...req.headers }; + if (options.headers) { + outgoing.headers = { ...outgoing.headers, ...options.headers }; + } + if (options.auth) { + outgoing.auth = options.auth; + } + if (options.ca) { + outgoing.ca = options.ca; + } + if (isSSL.test(options[forward || "target"].protocol)) { + outgoing.rejectUnauthorized = options.secure === void 0 ? true : options.secure; + } + outgoing.agent = options.agent || false; + outgoing.localAddress = options.localAddress; + if (!outgoing.agent) { + outgoing.headers = outgoing.headers || {}; + if (typeof outgoing.headers.connection !== "string" || !upgradeHeader.test(outgoing.headers.connection)) { + outgoing.headers.connection = "close"; + } + } + const target = options[forward || "target"]; + const targetPath = target && options.prependPath !== false ? target.pathname || target.path || "" : ""; + const parsed = new URL(req.url, "http://localhost"); + let outgoingPath = options.toProxy ? req.url : parsed.pathname + parsed.search || ""; + outgoingPath = options.ignorePath ? "" : outgoingPath; + outgoing.path = urlJoin(targetPath, outgoingPath); + if (options.changeOrigin) { + outgoing.headers.host = /* required(outgoing.port, options[forward || "target"].protocol) && TODO: From requires-port */ + hasPort(outgoing.host) ? outgoing.host : outgoing.host + ":" + outgoing.port; + } + return outgoing; +} +function setupSocket(socket) { + socket.setTimeout(0); + socket.setNoDelay(true); + socket.setKeepAlive(true, 0); + return socket; +} +function getPort(req) { + const res = req.headers.host ? req.headers.host.match(/:(\d+)/) : ""; + if (res) { + return res[1]; + } + return hasEncryptedConnection(req) ? "443" : "80"; +} +function hasEncryptedConnection(req) { + return Boolean(req.connection.encrypted || req.connection.pair); +} +function urlJoin(...args) { + const lastIndex = args.length - 1; + const last = args[lastIndex]; + const lastSegs = last.split("?"); + args[lastIndex] = lastSegs.shift(); + const retSegs = [ + args.filter(Boolean).join("/").replace(/\/+/g, "/").replace("http:/", "http://").replace("https:/", "https://") + ]; + retSegs.push(...lastSegs); + return retSegs.join("?"); +} +function rewriteCookieProperty(header, config, property) { + if (Array.isArray(header)) { + return header.map(function(headerElement) { + return rewriteCookieProperty(headerElement, config, property); + }); + } + return header.replace( + new RegExp("(;\\s*" + property + "=)([^;]+)", "i"), + function(match, prefix, previousValue) { + let newValue; + if (previousValue in config) { + newValue = config[previousValue]; + } else if ("*" in config) { + newValue = config["*"]; + } else { + return match; + } + return newValue ? prefix + newValue : ""; + } + ); +} +function hasPort(host) { + return !!~host.indexOf(":"); +} + +function defineProxyMiddleware(m) { + return m; +} +function defineProxyOutgoingMiddleware(m) { + return m; +} + +const redirectRegex = /^201|30([1278])$/; +const removeChunked = defineProxyOutgoingMiddleware((req, res, proxyRes) => { + if (req.httpVersion === "1.0") { + delete proxyRes.headers["transfer-encoding"]; + } +}); +const setConnection = defineProxyOutgoingMiddleware((req, res, proxyRes) => { + if (req.httpVersion === "1.0") { + proxyRes.headers.connection = req.headers.connection || "close"; + } else if (req.httpVersion !== "2.0" && !proxyRes.headers.connection) { + proxyRes.headers.connection = req.headers.connection || "keep-alive"; + } +}); +const setRedirectHostRewrite = defineProxyOutgoingMiddleware( + (req, res, proxyRes, options) => { + if ((options.hostRewrite || options.autoRewrite || options.protocolRewrite) && proxyRes.headers.location && redirectRegex.test(String(proxyRes.statusCode))) { + const target = new URL(options.target); + const u = new URL(proxyRes.headers.location); + if (target.host !== u.host) { + return; + } + if (options.hostRewrite) { + u.host = options.hostRewrite; + } else if (options.autoRewrite) { + u.host = req.headers.host; + } + if (options.protocolRewrite) { + u.protocol = options.protocolRewrite; + } + proxyRes.headers.location = u.toString(); + } + } +); +const writeHeaders = defineProxyOutgoingMiddleware( + (req, res, proxyRes, options) => { + let rewriteCookieDomainConfig = options.cookieDomainRewrite; + let rewriteCookiePathConfig = options.cookiePathRewrite; + const preserveHeaderKeyCase = options.preserveHeaderKeyCase; + let rawHeaderKeyMap; + const setHeader = function(key, header) { + if (header === void 0) { + return; + } + if (rewriteCookieDomainConfig && key.toLowerCase() === "set-cookie") { + header = rewriteCookieProperty( + header, + rewriteCookieDomainConfig, + "domain" + ); + } + if (rewriteCookiePathConfig && key.toLowerCase() === "set-cookie") { + header = rewriteCookieProperty(header, rewriteCookiePathConfig, "path"); + } + res.setHeader(String(key).trim(), header); + }; + if (typeof rewriteCookieDomainConfig === "string") { + rewriteCookieDomainConfig = { "*": rewriteCookieDomainConfig }; + } + if (typeof rewriteCookiePathConfig === "string") { + rewriteCookiePathConfig = { "*": rewriteCookiePathConfig }; + } + if (preserveHeaderKeyCase && proxyRes.rawHeaders !== void 0) { + rawHeaderKeyMap = {}; + for (let i = 0; i < proxyRes.rawHeaders.length; i += 2) { + const key = proxyRes.rawHeaders[i]; + rawHeaderKeyMap[key.toLowerCase()] = key; + } + } + for (let key of Object.keys(proxyRes.headers)) { + const header = proxyRes.headers[key]; + if (preserveHeaderKeyCase && rawHeaderKeyMap) { + key = rawHeaderKeyMap[key] || key; + } + setHeader(key, header); + } + } +); +const writeStatusCode = defineProxyOutgoingMiddleware((req, res, proxyRes) => { + if (proxyRes.statusMessage) { + res.statusCode = proxyRes.statusCode; + res.statusMessage = proxyRes.statusMessage; + } else { + res.statusCode = proxyRes.statusCode; + } +}); +const webOutgoingMiddleware = [ + removeChunked, + setConnection, + setRedirectHostRewrite, + writeHeaders, + writeStatusCode +]; + +const nativeAgents = { http: Et, https: https }; +const deleteLength = defineProxyMiddleware((req) => { + if ((req.method === "DELETE" || req.method === "OPTIONS") && !req.headers["content-length"]) { + req.headers["content-length"] = "0"; + delete req.headers["transfer-encoding"]; + } +}); +const timeout = defineProxyMiddleware((req, res, options) => { + if (options.timeout) { + req.socket.setTimeout(options.timeout); + } +}); +const XHeaders$1 = defineProxyMiddleware((req, res, options) => { + if (!options.xfwd) { + return; + } + const encrypted = req.isSpdy || hasEncryptedConnection(req); + const values = { + for: req.connection.remoteAddress || req.socket.remoteAddress, + port: getPort(req), + proto: encrypted ? "https" : "http" + }; + for (const header of ["for", "port", "proto"]) { + req.headers["x-forwarded-" + header] = (req.headers["x-forwarded-" + header] || "") + (req.headers["x-forwarded-" + header] ? "," : "") + values[header]; + } + req.headers["x-forwarded-host"] = req.headers["x-forwarded-host"] || req.headers.host || ""; +}); +const stream$1 = defineProxyMiddleware( + (req, res, options, server, head, callback) => { + server.emit("start", req, res, options.target || options.forward); + const agents = nativeAgents; + const http = agents.http; + const https = agents.https; + if (options.forward) { + const forwardReq = (options.forward.protocol === "https:" ? https : http).request(setupOutgoing(options.ssl || {}, options, req, "forward")); + const forwardError = createErrorHandler(forwardReq, options.forward); + req.on("error", forwardError); + forwardReq.on("error", forwardError); + (options.buffer || req).pipe(forwardReq); + if (!options.target) { + res.end(); + return; + } + } + const proxyReq = (options.target.protocol === "https:" ? https : http).request(setupOutgoing(options.ssl || {}, options, req)); + proxyReq.on("socket", (socket) => { + if (server && !proxyReq.getHeader("expect")) { + server.emit("proxyReq", proxyReq, req, res, options); + } + }); + if (options.proxyTimeout) { + proxyReq.setTimeout(options.proxyTimeout, function() { + proxyReq.abort(); + }); + } + req.on("aborted", function() { + proxyReq.abort(); + }); + const proxyError = createErrorHandler(proxyReq, options.target); + req.on("error", proxyError); + proxyReq.on("error", proxyError); + function createErrorHandler(proxyReq2, url) { + return function proxyError2(err) { + if (req.socket.destroyed && err.code === "ECONNRESET") { + server.emit("econnreset", err, req, res, url); + return proxyReq2.abort(); + } + if (callback) { + callback(err, req, res, url); + } else { + server.emit("error", err, req, res, url); + } + }; + } + (options.buffer || req).pipe(proxyReq); + proxyReq.on("response", function(proxyRes) { + if (server) { + server.emit("proxyRes", proxyRes, req, res); + } + if (!res.headersSent && !options.selfHandleResponse) { + for (const pass of webOutgoingMiddleware) { + if (pass(req, res, proxyRes, options)) { + break; + } + } + } + if (res.finished) { + if (server) { + server.emit("end", req, res, proxyRes); + } + } else { + res.on("close", function() { + proxyRes.destroy(); + }); + proxyRes.on("end", function() { + if (server) { + server.emit("end", req, res, proxyRes); + } + }); + if (!options.selfHandleResponse) { + proxyRes.pipe(res); + } + } + }); + } +); +const webIncomingMiddleware = [ + deleteLength, + timeout, + XHeaders$1, + stream$1 +]; + +const checkMethodAndHeader = defineProxyMiddleware((req, socket) => { + if (req.method !== "GET" || !req.headers.upgrade) { + socket.destroy(); + return true; + } + if (req.headers.upgrade.toLowerCase() !== "websocket") { + socket.destroy(); + return true; + } +}); +const XHeaders = defineProxyMiddleware((req, socket, options) => { + if (!options.xfwd) { + return; + } + const values = { + for: req.connection.remoteAddress || req.socket.remoteAddress, + port: getPort(req), + proto: hasEncryptedConnection(req) ? "wss" : "ws" + }; + for (const header of ["for", "port", "proto"]) { + req.headers["x-forwarded-" + header] = (req.headers["x-forwarded-" + header] || "") + (req.headers["x-forwarded-" + header] ? "," : "") + values[header]; + } +}); +const stream = defineProxyMiddleware( + (req, socket, options, server, head, callback) => { + const createHttpHeader = function(line, headers) { + return Object.keys(headers).reduce( + function(head2, key) { + const value = headers[key]; + if (!Array.isArray(value)) { + head2.push(key + ": " + value); + return head2; + } + for (const element of value) { + head2.push(key + ": " + element); + } + return head2; + }, + [line] + ).join("\r\n") + "\r\n\r\n"; + }; + setupSocket(socket); + if (head && head.length > 0) { + socket.unshift(head); + } + const proxyReq = (isSSL.test(options.target.protocol) ? https : Et).request(setupOutgoing(options.ssl || {}, options, req)); + if (server) { + server.emit("proxyReqWs", proxyReq, req, socket, options, head); + } + proxyReq.on("error", onOutgoingError); + proxyReq.on("response", function(res) { + if (!res.upgrade) { + socket.write( + createHttpHeader( + "HTTP/" + res.httpVersion + " " + res.statusCode + " " + res.statusMessage, + res.headers + ) + ); + res.pipe(socket); + } + }); + proxyReq.on("upgrade", function(proxyRes, proxySocket, proxyHead) { + proxySocket.on("error", onOutgoingError); + proxySocket.on("end", function() { + server.emit("close", proxyRes, proxySocket, proxyHead); + }); + socket.on("error", function() { + proxySocket.end(); + }); + setupSocket(proxySocket); + if (proxyHead && proxyHead.length > 0) { + proxySocket.unshift(proxyHead); + } + socket.write( + createHttpHeader("HTTP/1.1 101 Switching Protocols", proxyRes.headers) + ); + proxySocket.pipe(socket).pipe(proxySocket); + server.emit("open", proxySocket); + server.emit("proxySocket", proxySocket); + }); + proxyReq.end(); + function onOutgoingError(err) { + if (callback) { + callback(err, req, socket); + } else { + server.emit("error", err, req, socket); + } + socket.end(); + } + } +); +const websocketIncomingMiddleware = [ + checkMethodAndHeader, + XHeaders, + stream +]; + +var __defProp = Object.defineProperty; +var __defNormalProp = (obj, key, value) => key in obj ? __defProp(obj, key, { enumerable: true, configurable: true, writable: true, value }) : obj[key] = value; +var __publicField = (obj, key, value) => { + __defNormalProp(obj, typeof key !== "symbol" ? key + "" : key, value); + return value; +}; +class ProxyServer extends EventEmitter { + /** + * Creates the proxy server with specified options. + * @param options - Config object passed to the proxy + */ + constructor(options = {}) { + super(); + __publicField(this, "_server"); + __publicField(this, "_webPasses", [...webIncomingMiddleware]); + __publicField(this, "_wsPasses", [...websocketIncomingMiddleware]); + __publicField(this, "options"); + __publicField(this, "web"); + __publicField(this, "ws"); + this.options = options || {}; + this.options.prependPath = options.prependPath !== false; + this.web = _createProxyFn("web", this); + this.ws = _createProxyFn("ws", this); + } + /** + * A function that wraps the object in a webserver, for your convenience + * @param port - Port to listen on + * @param hostname - The hostname to listen on + */ + listen(port, hostname) { + const closure = (req, res) => { + this.web(req, res); + }; + this._server = this.options.ssl ? https.createServer(this.options.ssl, closure) : Et.createServer(closure); + if (this.options.ws) { + this._server.on("upgrade", (req, socket, head) => { + this._ws(req, socket, head); + }); + } + this._server.listen(port, hostname); + return this; + } + /** + * A function that closes the inner webserver and stops listening on given port + */ + close(callback) { + if (this._server) { + this._server.close((...args) => { + this._server = void 0; + if (callback) { + Reflect.apply(callback, void 0, args); + } + }); + } + } + before(type, passName, pass) { + if (type !== "ws" && type !== "web") { + throw new Error("type must be `web` or `ws`"); + } + const passes = type === "ws" ? this._wsPasses : this._webPasses; + let i = false; + for (const [idx, v] of passes.entries()) { + if (v.name === passName) { + i = idx; + } + } + if (i === false) { + throw new Error("No such pass"); + } + passes.splice(i, 0, pass); + } + after(type, passName, pass) { + if (type !== "ws" && type !== "web") { + throw new Error("type must be `web` or `ws`"); + } + const passes = type === "ws" ? this._wsPasses : this._webPasses; + let i = false; + for (const [idx, v] of passes.entries()) { + if (v.name === passName) { + i = idx; + } + } + if (i === false) { + throw new Error("No such pass"); + } + passes.splice(i++, 0, pass); + } +} +function createProxyServer(options = {}) { + return new ProxyServer(options); +} +function _createProxyFn(type, server) { + return function(req, res, opts, head) { + const requestOptions = { ...opts, ...server.options }; + for (const key of ["target", "forward"]) { + if (typeof requestOptions[key] === "string") { + requestOptions[key] = new URL(requestOptions[key]); + } + } + if (!requestOptions.target && !requestOptions.forward) { + return this.emit( + "error", + new Error("Must provide a proper URL as target") + ); + } + let _resolve; + let _reject; + const callbackPromise = new Promise((resolve, reject) => { + _resolve = resolve; + _reject = reject; + }); + res.on("close", () => { + _resolve(); + }); + res.on("error", (error) => { + _reject(error); + }); + for (const pass of type === "ws" ? server._wsPasses : server._webPasses) { + const stop = pass( + req, + res, + requestOptions, + server, + head, + (error) => { + _reject(error); + } + ); + if (stop) { + _resolve(); + break; + } + } + return callbackPromise; + }; +} + +export { ProxyServer, createProxyServer }; diff --git a/.pnpm-store/v3/files/18/c3a0e11e4993decd5bef9ea197c1ce7c28374197addfe20525846cb314fbbaf7919f0f9b90b5d037e94fa61d8037ac0098e0411a0b52f4b3fb0582193c8977 b/.pnpm-store/v3/files/18/c3a0e11e4993decd5bef9ea197c1ce7c28374197addfe20525846cb314fbbaf7919f0f9b90b5d037e94fa61d8037ac0098e0411a0b52f4b3fb0582193c8977 new file mode 100644 index 0000000000000000000000000000000000000000..964cd44d15e89809edd12f4f94640994cc4b561c --- /dev/null +++ b/.pnpm-store/v3/files/18/c3a0e11e4993decd5bef9ea197c1ce7c28374197addfe20525846cb314fbbaf7919f0f9b90b5d037e94fa61d8037ac0098e0411a0b52f4b3fb0582193c8977 @@ -0,0 +1,24 @@ +import 'node:fs'; +import 'node:path'; +import { b as br, B as Bn } from '../shared/nuxi.34ba5283.mjs'; +import 'node:http'; +import 'node:https'; +import 'node:zlib'; +import 'node:stream'; +import 'node:buffer'; +import 'node:util'; +import 'node:url'; +import 'node:net'; +import '../shared/nuxi.4ac76f59.mjs'; +import '../shared/nuxi.53f5921c.mjs'; +import './satisfies.mjs'; +import '../shared/nuxi.2155838d.mjs'; +import '../shared/nuxi.cc8dd4a9.mjs'; +import '../shared/nuxi.5aaa4630.mjs'; +import 'node:module'; +import '../shared/nuxi.610c92ff.mjs'; + +var B=Object.defineProperty;var E=(u,a)=>B(u,"name",{value:a,configurable:!0});let D=0;const t={START_BOUNDARY:D++,HEADER_FIELD_START:D++,HEADER_FIELD:D++,HEADER_VALUE_START:D++,HEADER_VALUE:D++,HEADER_VALUE_ALMOST_DONE:D++,HEADERS_ALMOST_DONE:D++,PART_DATA_START:D++,PART_DATA:D++,END:D++};let w=1;const R={PART_BOUNDARY:w,LAST_BOUNDARY:w*=2},g=10,N=13,x=32,P=45,C=58,I=97,M=122,$=E(u=>u|32,"lower"),m=E(()=>{},"noop"),F=class F{constructor(a){this.index=0,this.flags=0,this.onHeaderEnd=m,this.onHeaderField=m,this.onHeadersEnd=m,this.onHeaderValue=m,this.onPartBegin=m,this.onPartData=m,this.onPartEnd=m,this.boundaryChars={},a=`\r +--`+a;const n=new Uint8Array(a.length);for(let r=0;r{this[h+"Mark"]=n;},"mark"),s=E(h=>{delete this[h+"Mark"];},"clear"),T=E((h,S,_,U)=>{(S===void 0||S!==_)&&this[h](U&&U.subarray(S,_));},"callback"),b=E((h,S)=>{const _=h+"Mark";_ in this&&(S?(T(h,this[_],n,a),delete this[_]):(T(h,this[_],a.length,a),this[_]=0));},"dataCallback");for(n=0;nM)return;break;case t.HEADER_VALUE_START:if(o===x)break;f("onHeaderValue"),i=t.HEADER_VALUE;case t.HEADER_VALUE:o===N&&(b("onHeaderValue",!0),T("onHeaderEnd"),i=t.HEADER_VALUE_ALMOST_DONE);break;case t.HEADER_VALUE_ALMOST_DONE:if(o!==g)return;i=t.HEADER_FIELD_START;break;case t.HEADERS_ALMOST_DONE:if(o!==g)return;T("onHeadersEnd"),i=t.PART_DATA_START;break;case t.PART_DATA_START:i=t.PART_DATA,f("onPartData");case t.PART_DATA:if(d=e,e===0){for(n+=O;n0)l[e-1]=o;else if(d>0){const h=new Uint8Array(l.buffer,l.byteOffset,l.byteLength);T("onPartData",0,d,h),d=0,f("onPartData"),n--;}break;case t.END:break;default:throw new Error(`Unexpected state entered: ${i}`)}b("onHeaderField"),b("onHeaderValue"),b("onPartData"),this.index=e,this.state=i,this.flags=A;}end(){if(this.state===t.HEADER_FIELD_START&&this.index===0||this.state===t.PART_DATA&&this.index===this.boundary.length)this.onPartEnd();else if(this.state!==t.END)throw new Error("MultipartParser.end(): stream ended unexpectedly")}};E(F,"MultipartParser");let k=F;function v(u){const a=u.match(/\bfilename=("(.*?)"|([^()<>@,;:\\"/[\]?={}\s\t]+))($|;\s)/i);if(!a)return;const n=a[2]||a[3]||"";let r=n.slice(n.lastIndexOf("\\")+1);return r=r.replace(/%22/g,'"'),r=r.replace(/&#(\d{4});/g,(d,l)=>String.fromCharCode(l)),r}E(v,"_fileName");async function Z(u,a){if(!/multipart/i.test(a))throw new TypeError("Failed to fetch");const n=a.match(/boundary=(?:"([^"]+)"|([^;]+))/i);if(!n)throw new TypeError("no or bad content-type header, no multipart boundary");const r=new k(n[1]||n[2]);let d,l,c,p,e,i;const A=[],H=new br,O=E(s=>{c+=f.decode(s,{stream:!0});},"onPartData"),y=E(s=>{A.push(s);},"appendToFile"),o=E(()=>{const s=new Bn(A,i,{type:e});H.append(p,s);},"appendFileToFormData"),L=E(()=>{H.append(p,c);},"appendEntryToFormData"),f=new TextDecoder("utf-8");f.decode(),r.onPartBegin=function(){r.onPartData=O,r.onPartEnd=L,d="",l="",c="",p="",e="",i=null,A.length=0;},r.onHeaderField=function(s){d+=f.decode(s,{stream:!0});},r.onHeaderValue=function(s){l+=f.decode(s,{stream:!0});},r.onHeaderEnd=function(){if(l+=f.decode(),d=d.toLowerCase(),d==="content-disposition"){const s=l.match(/\bname=("([^"]*)"|([^()<>@,;:\\"/[\]?={}\s\t]+))/i);s&&(p=s[2]||s[3]||""),i=v(l),i&&(r.onPartData=y,r.onPartEnd=o);}else d==="content-type"&&(e=l);l="",d="";};for await(const s of u)r.write(s);return r.end(),H}E(Z,"toFormData"); + +export { Z as toFormData }; diff --git a/.pnpm-store/v3/files/19/c58c3a5a439dbf0da4d4472d74ffa5ac2279a5f5fbf4b607508b952d426f21f6e5aa4b02d0439e8084eb254c84485df026189981376d6ddd13b8077c5063b7 b/.pnpm-store/v3/files/19/c58c3a5a439dbf0da4d4472d74ffa5ac2279a5f5fbf4b607508b952d426f21f6e5aa4b02d0439e8084eb254c84485df026189981376d6ddd13b8077c5063b7 new file mode 100644 index 0000000000000000000000000000000000000000..e6cc5b0562c7e54ca14a98c8baed54dc884a77c4 --- /dev/null +++ b/.pnpm-store/v3/files/19/c58c3a5a439dbf0da4d4472d74ffa5ac2279a5f5fbf4b607508b952d426f21f6e5aa4b02d0439e8084eb254c84485df026189981376d6ddd13b8077c5063b7 @@ -0,0 +1,92 @@ +{ + "name": "nuxi", + "version": "3.11.1", + "description": "⚡️ Nuxt Generation CLI Experience", + "repository": "nuxt/cli", + "license": "MIT", + "type": "module", + "exports": { + ".": "./dist/index.mjs", + "./cli": "./bin/nuxi.mjs" + }, + "types": "./dist/index.d.ts", + "bin": { + "nuxi": "./bin/nuxi.mjs", + "nuxi-ng": "./bin/nuxi.mjs", + "nuxt": "./bin/nuxi.mjs", + "nuxt-cli": "./bin/nuxi.mjs" + }, + "files": [ + "bin", + "dist" + ], + "scripts": { + "dev:prepare": "unbuild --stub", + "build": "unbuild", + "build:stub": "unbuild --stub", + "dev": "node ./bin/nuxi.mjs dev ./playground", + "dev:bun": "bun --bun ./bin/nuxi.mjs dev ./playground", + "lint": "eslint . && prettier --check src", + "lint:fix": "eslint --fix . && prettier --write src", + "nuxi": "node ./bin/nuxi.mjs", + "nuxi-bun": "bun --bun ./bin/nuxi.mjs", + "prepack": "unbuild", + "release": "pnpm test && changelogen --release && npm publish && git push --follow-tags", + "test": "pnpm lint && pnpm test:types && pnpm build && pnpm test:dist", + "test:dist": "node ./bin/nuxi.mjs info ./playground", + "test:types": "tsc --noEmit" + }, + "devDependencies": { + "@nuxt/eslint-config": "^0.2.0", + "@nuxt/kit": "^3.11.1", + "@nuxt/schema": "^3.11.1", + "@nuxt/test-utils": "^3.12.0", + "@types/http-proxy": "^1.17.14", + "@types/node": "^20.11.30", + "@types/semver": "^7.5.8", + "@types/ws": "^8.5.10", + "c12": "^1.10.0", + "changelogen": "^0.5.5", + "chokidar": "^3.6.0", + "citty": "^0.1.6", + "clipboardy": "^4.0.0", + "colorette": "^2.0.20", + "consola": "^3.2.3", + "destr": "^2.0.3", + "eslint": "^8.57.0", + "execa": "^8.0.1", + "fuse.js": "^7.0.0", + "giget": "^1.2.1", + "h3": "^1.11.1", + "httpxy": "^0.1.5", + "jiti": "^1.21.0", + "listhen": "^1.7.2", + "magicast": "^0.3.3", + "mlly": "^1.6.1", + "nuxt": "^3.11.1", + "nypm": "^0.3.8", + "ofetch": "^1.3.3", + "pathe": "^1.1.2", + "perfect-debounce": "^1.0.0", + "pkg-types": "^1.0.3", + "prettier": "^3.2.5", + "scule": "^1.3.0", + "semver": "^7.6.0", + "unbuild": "^2.0.0", + "unws": "^0.2.4", + "vue-tsc": "^2.0.6", + "ws": "^8.16.0" + }, + "optionalDependencies": { + "fsevents": "~2.3.3" + }, + "resolutions": { + "nitropack": "npm:nitropack-nightly", + "nuxt": "^3.11.1", + "h3": "^1.11.1" + }, + "packageManager": "pnpm@8.15.5", + "engines": { + "node": "^16.10.0 || >=18.0.0" + } +} \ No newline at end of file diff --git a/.pnpm-store/v3/files/1f/00518f276a9fc92af2fdacf4cda4f23520177de4fe315d17c7d93651d0953ef7a963b615a180ff5182f9f86e79163194853f71b5ee5994f75ca7f065d15272 b/.pnpm-store/v3/files/1f/00518f276a9fc92af2fdacf4cda4f23520177de4fe315d17c7d93651d0953ef7a963b615a180ff5182f9f86e79163194853f71b5ee5994f75ca7f065d15272 new file mode 100644 index 0000000000000000000000000000000000000000..8d1be459c81f0be0b06a1b3edd90813b264b5bb4 --- /dev/null +++ b/.pnpm-store/v3/files/1f/00518f276a9fc92af2fdacf4cda4f23520177de4fe315d17c7d93651d0953ef7a963b615a180ff5182f9f86e79163194853f71b5ee5994f75ca7f065d15272 @@ -0,0 +1,51 @@ +import { execa } from './index3.mjs'; +import { d as defineCommand } from '../shared/nuxi.9edf0930.mjs'; +import { s as sharedArgs, l as legacyRootDirArgs, r as resolve } from '../shared/nuxi.610c92ff.mjs'; +import 'node:buffer'; +import 'node:path'; +import 'node:child_process'; +import 'node:process'; +import '../shared/nuxi.2155838d.mjs'; +import 'child_process'; +import 'path'; +import 'fs'; +import 'node:url'; +import 'node:os'; +import 'node:fs'; +import 'node:timers/promises'; +import 'stream'; +import 'node:util'; +import 'node:tty'; + +const devtools = defineCommand({ + meta: { + name: "devtools", + description: "Enable or disable devtools in a Nuxt project" + }, + args: { + ...sharedArgs, + command: { + type: "positional", + description: "Command to run", + valueHint: "enable|disable" + }, + ...legacyRootDirArgs + }, + async run(ctx) { + const cwd = resolve(ctx.args.cwd || ctx.args.rootDir || "."); + if (!["enable", "disable"].includes(ctx.args.command)) { + console.error(`Unknown command \`${ctx.args.command}\`.`); + process.exit(1); + } + await execa( + "npx", + ["@nuxt/devtools-wizard@latest", ctx.args.command, cwd], + { + stdio: "inherit", + cwd + } + ); + } +}); + +export { devtools as default }; diff --git a/.pnpm-store/v3/files/24/415b0814814c465240819b6202a210ca9c7112b5aaf744332710d1751b653fdd0a5d2b1e3916443a63f165aefdea1fc5d4363895f8a5ebac0c82052a4b627a b/.pnpm-store/v3/files/24/415b0814814c465240819b6202a210ca9c7112b5aaf744332710d1751b653fdd0a5d2b1e3916443a63f165aefdea1fc5d4363895f8a5ebac0c82052a4b627a new file mode 100644 index 0000000000000000000000000000000000000000..e39938a3f19f01e5db1f98d048592dd6b2e289d8 --- /dev/null +++ b/.pnpm-store/v3/files/24/415b0814814c465240819b6202a210ca9c7112b5aaf744332710d1751b653fdd0a5d2b1e3916443a63f165aefdea1fc5d4363895f8a5ebac0c82052a4b627a @@ -0,0 +1,54 @@ +import { c as cleanupNuxtDirs } from '../shared/nuxi.1e36f2d5.mjs'; +import { d as defineCommand } from '../shared/nuxi.9edf0930.mjs'; +import { s as sharedArgs, l as legacyRootDirArgs, r as resolve } from '../shared/nuxi.610c92ff.mjs'; +import { l as loadKit } from '../shared/nuxi.dc1b30dc.mjs'; +import 'node:fs'; +import 'node:util'; +import 'node:path'; +import 'node:process'; +import 'node:tty'; +import '../shared/nuxi.1ff5d6e2.mjs'; +import 'node:url'; +import '../shared/nuxi.1902c37d.mjs'; +import 'node:module'; +import '../shared/nuxi.53f5921c.mjs'; +import 'node:assert'; +import 'node:v8'; +import 'node:perf_hooks'; +import '../shared/nuxi.eaa29140.mjs'; +import './satisfies.mjs'; +import '../shared/nuxi.2155838d.mjs'; +import '../shared/nuxi.cc8dd4a9.mjs'; +import '../shared/nuxi.73800aa7.mjs'; +import 'crypto'; +import 'fs'; +import 'module'; +import 'path'; +import 'perf_hooks'; +import 'os'; +import 'vm'; +import 'url'; +import 'assert'; +import 'process'; +import 'v8'; +import 'util'; +import 'tty'; + +const cleanup = defineCommand({ + meta: { + name: "cleanup", + description: "Clean up generated Nuxt files and caches" + }, + args: { + ...sharedArgs, + ...legacyRootDirArgs + }, + async run(ctx) { + const cwd = resolve(ctx.args.cwd || ctx.args.rootDir || "."); + const { loadNuxtConfig } = await loadKit(cwd); + const nuxtOptions = await loadNuxtConfig({ cwd }); + await cleanupNuxtDirs(nuxtOptions.rootDir, nuxtOptions.buildDir); + } +}); + +export { cleanup as default }; diff --git a/.pnpm-store/v3/files/25/dcf0356687abef9df33b99235a0d7cf47a5edf248672320922cec8216cb7fac18da2a9db1d4a53b9ee67dcd848a36665eedb7270b5a5aaacd88446672c195c b/.pnpm-store/v3/files/25/dcf0356687abef9df33b99235a0d7cf47a5edf248672320922cec8216cb7fac18da2a9db1d4a53b9ee67dcd848a36665eedb7270b5a5aaacd88446672c195c new file mode 100644 index 0000000000000000000000000000000000000000..2d9184e1462875502ff000108516e99628c8796c --- /dev/null +++ b/.pnpm-store/v3/files/25/dcf0356687abef9df33b99235a0d7cf47a5edf248672320922cec8216cb7fac18da2a9db1d4a53b9ee67dcd848a36665eedb7270b5a5aaacd88446672c195c @@ -0,0 +1,2437 @@ +import { r as resolvePath$1, t as tryResolveModule$1, i as importModule } from './nuxi.1902c37d.mjs'; +import { promises, statSync, lstatSync, existsSync } from 'node:fs'; +import 'node:perf_hooks'; +import { d as defu } from './nuxi.eaa29140.mjs'; +import './nuxi.9edf0930.mjs'; +import 'node:util'; +import 'node:path'; +import 'node:process'; +import 'node:tty'; +import '../chunks/satisfies.mjs'; +import { fileURLToPath } from 'node:url'; +import { j as jiti } from './nuxi.73800aa7.mjs'; +import { i as isAbsolute, r as resolve, j as join, n as normalizeWindowsPath, a as relative, d as dirname, c as normalize } from './nuxi.610c92ff.mjs'; +import { w as withTrailingSlash } from './nuxi.53f5921c.mjs'; + +const defaultFindOptions = { + startingFrom: ".", + rootPattern: /^node_modules$/, + reverse: false, + test: (filePath) => { + try { + if (statSync(filePath).isFile()) { + return true; + } + } catch { + } + } +}; +async function findFile(filename, _options = {}) { + const options = { ...defaultFindOptions, ..._options }; + const basePath = resolve(options.startingFrom); + const leadingSlash = basePath[0] === "/"; + const segments = basePath.split("/").filter(Boolean); + if (leadingSlash) { + segments[0] = "/" + segments[0]; + } + let root = segments.findIndex((r) => r.match(options.rootPattern)); + if (root === -1) { + root = 0; + } + if (!options.reverse) { + for (let index = segments.length; index > root; index--) { + const filePath = join(...segments.slice(0, index), filename); + if (await options.test(filePath)) { + return filePath; + } + } + } else { + for (let index = root + 1; index <= segments.length; index++) { + const filePath = join(...segments.slice(0, index), filename); + if (await options.test(filePath)) { + return filePath; + } + } + } + throw new Error( + `Cannot find matching ${filename} in ${options.startingFrom} or parent directories` + ); +} +function findNearestFile(filename, _options = {}) { + return findFile(filename, _options); +} +const FileCache = /* @__PURE__ */ new Map(); +async function readPackageJSON(id, options = {}) { + const resolvedPath = await resolvePackageJSON(id, options); + const cache = options.cache && typeof options.cache !== "boolean" ? options.cache : FileCache; + if (options.cache && cache.has(resolvedPath)) { + return cache.get(resolvedPath); + } + const blob = await promises.readFile(resolvedPath, "utf8"); + const parsed = JSON.parse(blob); + cache.set(resolvedPath, parsed); + return parsed; +} +async function resolvePackageJSON(id = process.cwd(), options = {}) { + const resolvedPath = isAbsolute(id) ? id : await resolvePath$1(id, options); + return findNearestFile("package.json", { + startingFrom: resolvedPath, + ...options + }); +} + +function createContext(opts = {}) { + let currentInstance; + let isSingleton = false; + const checkConflict = (instance) => { + if (currentInstance && currentInstance !== instance) { + throw new Error("Context conflict"); + } + }; + let als; + if (opts.asyncContext) { + const _AsyncLocalStorage = opts.AsyncLocalStorage || globalThis.AsyncLocalStorage; + if (_AsyncLocalStorage) { + als = new _AsyncLocalStorage(); + } else { + console.warn("[unctx] `AsyncLocalStorage` is not provided."); + } + } + const _getCurrentInstance = () => { + if (als && currentInstance === void 0) { + const instance = als.getStore(); + if (instance !== void 0) { + return instance; + } + } + return currentInstance; + }; + return { + use: () => { + const _instance = _getCurrentInstance(); + if (_instance === void 0) { + throw new Error("Context is not available"); + } + return _instance; + }, + tryUse: () => { + return _getCurrentInstance(); + }, + set: (instance, replace) => { + if (!replace) { + checkConflict(instance); + } + currentInstance = instance; + isSingleton = true; + }, + unset: () => { + currentInstance = void 0; + isSingleton = false; + }, + call: (instance, callback) => { + checkConflict(instance); + currentInstance = instance; + try { + return als ? als.run(instance, callback) : callback(); + } finally { + if (!isSingleton) { + currentInstance = void 0; + } + } + }, + async callAsync(instance, callback) { + currentInstance = instance; + const onRestore = () => { + currentInstance = instance; + }; + const onLeave = () => currentInstance === instance ? onRestore : void 0; + asyncHandlers.add(onLeave); + try { + const r = als ? als.run(instance, callback) : callback(); + if (!isSingleton) { + currentInstance = void 0; + } + return await r; + } finally { + asyncHandlers.delete(onLeave); + } + } + }; +} +function createNamespace(defaultOpts = {}) { + const contexts = {}; + return { + get(key, opts = {}) { + if (!contexts[key]) { + contexts[key] = createContext({ ...defaultOpts, ...opts }); + } + contexts[key]; + return contexts[key]; + } + }; +} +const _globalThis = typeof globalThis !== "undefined" ? globalThis : typeof self !== "undefined" ? self : typeof global !== "undefined" ? global : typeof window !== "undefined" ? window : {}; +const globalKey = "__unctx__"; +const defaultNamespace = _globalThis[globalKey] || (_globalThis[globalKey] = createNamespace()); +const getContext = (key, opts = {}) => defaultNamespace.get(key, opts); +const asyncHandlersKey = "__unctx_async_handlers__"; +const asyncHandlers = _globalThis[asyncHandlersKey] || (_globalThis[asyncHandlersKey] = /* @__PURE__ */ new Set()); + +// A simple implementation of make-array +function makeArray (subject) { + return Array.isArray(subject) + ? subject + : [subject] +} + +const EMPTY = ''; +const SPACE = ' '; +const ESCAPE = '\\'; +const REGEX_TEST_BLANK_LINE = /^\s+$/; +const REGEX_INVALID_TRAILING_BACKSLASH = /(?:[^\\]|^)\\$/; +const REGEX_REPLACE_LEADING_EXCAPED_EXCLAMATION = /^\\!/; +const REGEX_REPLACE_LEADING_EXCAPED_HASH = /^\\#/; +const REGEX_SPLITALL_CRLF = /\r?\n/g; +// /foo, +// ./foo, +// ../foo, +// . +// .. +const REGEX_TEST_INVALID_PATH = /^\.*\/|^\.+$/; + +const SLASH = '/'; + +// Do not use ternary expression here, since "istanbul ignore next" is buggy +let TMP_KEY_IGNORE = 'node-ignore'; +/* istanbul ignore else */ +if (typeof Symbol !== 'undefined') { + TMP_KEY_IGNORE = Symbol.for('node-ignore'); +} +const KEY_IGNORE = TMP_KEY_IGNORE; + +const define = (object, key, value) => + Object.defineProperty(object, key, {value}); + +const REGEX_REGEXP_RANGE = /([0-z])-([0-z])/g; + +const RETURN_FALSE = () => false; + +// Sanitize the range of a regular expression +// The cases are complicated, see test cases for details +const sanitizeRange = range => range.replace( + REGEX_REGEXP_RANGE, + (match, from, to) => from.charCodeAt(0) <= to.charCodeAt(0) + ? match + // Invalid range (out of order) which is ok for gitignore rules but + // fatal for JavaScript regular expression, so eliminate it. + : EMPTY +); + +// See fixtures #59 +const cleanRangeBackSlash = slashes => { + const {length} = slashes; + return slashes.slice(0, length - length % 2) +}; + +// > If the pattern ends with a slash, +// > it is removed for the purpose of the following description, +// > but it would only find a match with a directory. +// > In other words, foo/ will match a directory foo and paths underneath it, +// > but will not match a regular file or a symbolic link foo +// > (this is consistent with the way how pathspec works in general in Git). +// '`foo/`' will not match regular file '`foo`' or symbolic link '`foo`' +// -> ignore-rules will not deal with it, because it costs extra `fs.stat` call +// you could use option `mark: true` with `glob` + +// '`foo/`' should not continue with the '`..`' +const REPLACERS = [ + + [ + // remove BOM + // TODO: + // Other similar zero-width characters? + /^\uFEFF/, + () => EMPTY + ], + + // > Trailing spaces are ignored unless they are quoted with backslash ("\") + [ + // (a\ ) -> (a ) + // (a ) -> (a) + // (a \ ) -> (a ) + /\\?\s+$/, + match => match.indexOf('\\') === 0 + ? SPACE + : EMPTY + ], + + // replace (\ ) with ' ' + [ + /\\\s/g, + () => SPACE + ], + + // Escape metacharacters + // which is written down by users but means special for regular expressions. + + // > There are 12 characters with special meanings: + // > - the backslash \, + // > - the caret ^, + // > - the dollar sign $, + // > - the period or dot ., + // > - the vertical bar or pipe symbol |, + // > - the question mark ?, + // > - the asterisk or star *, + // > - the plus sign +, + // > - the opening parenthesis (, + // > - the closing parenthesis ), + // > - and the opening square bracket [, + // > - the opening curly brace {, + // > These special characters are often called "metacharacters". + [ + /[\\$.|*+(){^]/g, + match => `\\${match}` + ], + + [ + // > a question mark (?) matches a single character + /(?!\\)\?/g, + () => '[^/]' + ], + + // leading slash + [ + + // > A leading slash matches the beginning of the pathname. + // > For example, "/*.c" matches "cat-file.c" but not "mozilla-sha1/sha1.c". + // A leading slash matches the beginning of the pathname + /^\//, + () => '^' + ], + + // replace special metacharacter slash after the leading slash + [ + /\//g, + () => '\\/' + ], + + [ + // > A leading "**" followed by a slash means match in all directories. + // > For example, "**/foo" matches file or directory "foo" anywhere, + // > the same as pattern "foo". + // > "**/foo/bar" matches file or directory "bar" anywhere that is directly + // > under directory "foo". + // Notice that the '*'s have been replaced as '\\*' + /^\^*\\\*\\\*\\\//, + + // '**/foo' <-> 'foo' + () => '^(?:.*\\/)?' + ], + + // starting + [ + // there will be no leading '/' + // (which has been replaced by section "leading slash") + // If starts with '**', adding a '^' to the regular expression also works + /^(?=[^^])/, + function startingReplacer () { + // If has a slash `/` at the beginning or middle + return !/\/(?!$)/.test(this) + // > Prior to 2.22.1 + // > If the pattern does not contain a slash /, + // > Git treats it as a shell glob pattern + // Actually, if there is only a trailing slash, + // git also treats it as a shell glob pattern + + // After 2.22.1 (compatible but clearer) + // > If there is a separator at the beginning or middle (or both) + // > of the pattern, then the pattern is relative to the directory + // > level of the particular .gitignore file itself. + // > Otherwise the pattern may also match at any level below + // > the .gitignore level. + ? '(?:^|\\/)' + + // > Otherwise, Git treats the pattern as a shell glob suitable for + // > consumption by fnmatch(3) + : '^' + } + ], + + // two globstars + [ + // Use lookahead assertions so that we could match more than one `'/**'` + /\\\/\\\*\\\*(?=\\\/|$)/g, + + // Zero, one or several directories + // should not use '*', or it will be replaced by the next replacer + + // Check if it is not the last `'/**'` + (_, index, str) => index + 6 < str.length + + // case: /**/ + // > A slash followed by two consecutive asterisks then a slash matches + // > zero or more directories. + // > For example, "a/**/b" matches "a/b", "a/x/b", "a/x/y/b" and so on. + // '/**/' + ? '(?:\\/[^\\/]+)*' + + // case: /** + // > A trailing `"/**"` matches everything inside. + + // #21: everything inside but it should not include the current folder + : '\\/.+' + ], + + // normal intermediate wildcards + [ + // Never replace escaped '*' + // ignore rule '\*' will match the path '*' + + // 'abc.*/' -> go + // 'abc.*' -> skip this rule, + // coz trailing single wildcard will be handed by [trailing wildcard] + /(^|[^\\]+)(\\\*)+(?=.+)/g, + + // '*.js' matches '.js' + // '*.js' doesn't match 'abc' + (_, p1, p2) => { + // 1. + // > An asterisk "*" matches anything except a slash. + // 2. + // > Other consecutive asterisks are considered regular asterisks + // > and will match according to the previous rules. + const unescaped = p2.replace(/\\\*/g, '[^\\/]*'); + return p1 + unescaped + } + ], + + [ + // unescape, revert step 3 except for back slash + // For example, if a user escape a '\\*', + // after step 3, the result will be '\\\\\\*' + /\\\\\\(?=[$.|*+(){^])/g, + () => ESCAPE + ], + + [ + // '\\\\' -> '\\' + /\\\\/g, + () => ESCAPE + ], + + [ + // > The range notation, e.g. [a-zA-Z], + // > can be used to match one of the characters in a range. + + // `\` is escaped by step 3 + /(\\)?\[([^\]/]*?)(\\*)($|\])/g, + (match, leadEscape, range, endEscape, close) => leadEscape === ESCAPE + // '\\[bar]' -> '\\\\[bar\\]' + ? `\\[${range}${cleanRangeBackSlash(endEscape)}${close}` + : close === ']' + ? endEscape.length % 2 === 0 + // A normal case, and it is a range notation + // '[bar]' + // '[bar\\\\]' + ? `[${sanitizeRange(range)}${endEscape}]` + // Invalid range notaton + // '[bar\\]' -> '[bar\\\\]' + : '[]' + : '[]' + ], + + // ending + [ + // 'js' will not match 'js.' + // 'ab' will not match 'abc' + /(?:[^*])$/, + + // WTF! + // https://git-scm.com/docs/gitignore + // changes in [2.22.1](https://git-scm.com/docs/gitignore/2.22.1) + // which re-fixes #24, #38 + + // > If there is a separator at the end of the pattern then the pattern + // > will only match directories, otherwise the pattern can match both + // > files and directories. + + // 'js*' will not match 'a.js' + // 'js/' will not match 'a.js' + // 'js' will match 'a.js' and 'a.js/' + match => /\/$/.test(match) + // foo/ will not match 'foo' + ? `${match}$` + // foo matches 'foo' and 'foo/' + : `${match}(?=$|\\/$)` + ], + + // trailing wildcard + [ + /(\^|\\\/)?\\\*$/, + (_, p1) => { + const prefix = p1 + // '\^': + // '/*' does not match EMPTY + // '/*' does not match everything + + // '\\\/': + // 'abc/*' does not match 'abc/' + ? `${p1}[^/]+` + + // 'a*' matches 'a' + // 'a*' matches 'aa' + : '[^/]*'; + + return `${prefix}(?=$|\\/$)` + } + ], +]; + +// A simple cache, because an ignore rule only has only one certain meaning +const regexCache = Object.create(null); + +// @param {pattern} +const makeRegex = (pattern, ignoreCase) => { + let source = regexCache[pattern]; + + if (!source) { + source = REPLACERS.reduce( + (prev, current) => prev.replace(current[0], current[1].bind(pattern)), + pattern + ); + regexCache[pattern] = source; + } + + return ignoreCase + ? new RegExp(source, 'i') + : new RegExp(source) +}; + +const isString = subject => typeof subject === 'string'; + +// > A blank line matches no files, so it can serve as a separator for readability. +const checkPattern = pattern => pattern + && isString(pattern) + && !REGEX_TEST_BLANK_LINE.test(pattern) + && !REGEX_INVALID_TRAILING_BACKSLASH.test(pattern) + + // > A line starting with # serves as a comment. + && pattern.indexOf('#') !== 0; + +const splitPattern = pattern => pattern.split(REGEX_SPLITALL_CRLF); + +class IgnoreRule { + constructor ( + origin, + pattern, + negative, + regex + ) { + this.origin = origin; + this.pattern = pattern; + this.negative = negative; + this.regex = regex; + } +} + +const createRule = (pattern, ignoreCase) => { + const origin = pattern; + let negative = false; + + // > An optional prefix "!" which negates the pattern; + if (pattern.indexOf('!') === 0) { + negative = true; + pattern = pattern.substr(1); + } + + pattern = pattern + // > Put a backslash ("\") in front of the first "!" for patterns that + // > begin with a literal "!", for example, `"\!important!.txt"`. + .replace(REGEX_REPLACE_LEADING_EXCAPED_EXCLAMATION, '!') + // > Put a backslash ("\") in front of the first hash for patterns that + // > begin with a hash. + .replace(REGEX_REPLACE_LEADING_EXCAPED_HASH, '#'); + + const regex = makeRegex(pattern, ignoreCase); + + return new IgnoreRule( + origin, + pattern, + negative, + regex + ) +}; + +const throwError = (message, Ctor) => { + throw new Ctor(message) +}; + +const checkPath = (path, originalPath, doThrow) => { + if (!isString(path)) { + return doThrow( + `path must be a string, but got \`${originalPath}\``, + TypeError + ) + } + + // We don't know if we should ignore EMPTY, so throw + if (!path) { + return doThrow(`path must not be empty`, TypeError) + } + + // Check if it is a relative path + if (checkPath.isNotRelative(path)) { + const r = '`path.relative()`d'; + return doThrow( + `path should be a ${r} string, but got "${originalPath}"`, + RangeError + ) + } + + return true +}; + +const isNotRelative = path => REGEX_TEST_INVALID_PATH.test(path); + +checkPath.isNotRelative = isNotRelative; +checkPath.convert = p => p; + +class Ignore { + constructor ({ + ignorecase = true, + ignoreCase = ignorecase, + allowRelativePaths = false + } = {}) { + define(this, KEY_IGNORE, true); + + this._rules = []; + this._ignoreCase = ignoreCase; + this._allowRelativePaths = allowRelativePaths; + this._initCache(); + } + + _initCache () { + this._ignoreCache = Object.create(null); + this._testCache = Object.create(null); + } + + _addPattern (pattern) { + // #32 + if (pattern && pattern[KEY_IGNORE]) { + this._rules = this._rules.concat(pattern._rules); + this._added = true; + return + } + + if (checkPattern(pattern)) { + const rule = createRule(pattern, this._ignoreCase); + this._added = true; + this._rules.push(rule); + } + } + + // @param {Array | string | Ignore} pattern + add (pattern) { + this._added = false; + + makeArray( + isString(pattern) + ? splitPattern(pattern) + : pattern + ).forEach(this._addPattern, this); + + // Some rules have just added to the ignore, + // making the behavior changed. + if (this._added) { + this._initCache(); + } + + return this + } + + // legacy + addPattern (pattern) { + return this.add(pattern) + } + + // | ignored : unignored + // negative | 0:0 | 0:1 | 1:0 | 1:1 + // -------- | ------- | ------- | ------- | -------- + // 0 | TEST | TEST | SKIP | X + // 1 | TESTIF | SKIP | TEST | X + + // - SKIP: always skip + // - TEST: always test + // - TESTIF: only test if checkUnignored + // - X: that never happen + + // @param {boolean} whether should check if the path is unignored, + // setting `checkUnignored` to `false` could reduce additional + // path matching. + + // @returns {TestResult} true if a file is ignored + _testOne (path, checkUnignored) { + let ignored = false; + let unignored = false; + + this._rules.forEach(rule => { + const {negative} = rule; + if ( + unignored === negative && ignored !== unignored + || negative && !ignored && !unignored && !checkUnignored + ) { + return + } + + const matched = rule.regex.test(path); + + if (matched) { + ignored = !negative; + unignored = negative; + } + }); + + return { + ignored, + unignored + } + } + + // @returns {TestResult} + _test (originalPath, cache, checkUnignored, slices) { + const path = originalPath + // Supports nullable path + && checkPath.convert(originalPath); + + checkPath( + path, + originalPath, + this._allowRelativePaths + ? RETURN_FALSE + : throwError + ); + + return this._t(path, cache, checkUnignored, slices) + } + + _t (path, cache, checkUnignored, slices) { + if (path in cache) { + return cache[path] + } + + if (!slices) { + // path/to/a.js + // ['path', 'to', 'a.js'] + slices = path.split(SLASH); + } + + slices.pop(); + + // If the path has no parent directory, just test it + if (!slices.length) { + return cache[path] = this._testOne(path, checkUnignored) + } + + const parent = this._t( + slices.join(SLASH) + SLASH, + cache, + checkUnignored, + slices + ); + + // If the path contains a parent directory, check the parent first + return cache[path] = parent.ignored + // > It is not possible to re-include a file if a parent directory of + // > that file is excluded. + ? parent + : this._testOne(path, checkUnignored) + } + + ignores (path) { + return this._test(path, this._ignoreCache, false).ignored + } + + createFilter () { + return path => !this.ignores(path) + } + + filter (paths) { + return makeArray(paths).filter(this.createFilter()) + } + + // @returns {TestResult} + test (path) { + return this._test(path, this._testCache, true) + } +} + +const factory = options => new Ignore(options); + +const isPathValid = path => + checkPath(path && checkPath.convert(path), path, RETURN_FALSE); + +factory.isPathValid = isPathValid; + +// Fixes typescript +factory.default = factory; + +// Windows +// -------------------------------------------------------------- +/* istanbul ignore if */ +if ( + // Detect `process` so that it can run in browsers. + typeof process !== 'undefined' + && ( + process.env && process.env.IGNORE_TEST_WIN32 + || process.platform === 'win32' + ) +) { + /* eslint no-control-regex: "off" */ + const makePosix = str => /^\\\\\?\\/.test(str) + || /["<>|\u0000-\u001F]+/u.test(str) + ? str + : str.replace(/\\/g, '/'); + + checkPath.convert = makePosix; + + // 'C:\\foo' <- 'C:\\foo' has been converted to 'C:/' + // 'd:\\foo' + const REGIX_IS_WINDOWS_PATH_ABSOLUTE = /^[a-z]:\//i; + checkPath.isNotRelative = path => + REGIX_IS_WINDOWS_PATH_ABSOLUTE.test(path) + || isNotRelative(path); +} + +const pathSeparators = /* @__PURE__ */ new Set(["/", "\\", void 0]); +const normalizedAliasSymbol = Symbol.for("pathe:normalizedAlias"); +function normalizeAliases(_aliases) { + if (_aliases[normalizedAliasSymbol]) { + return _aliases; + } + const aliases = Object.fromEntries( + Object.entries(_aliases).sort(([a], [b]) => _compareAliases(a, b)) + ); + for (const key in aliases) { + for (const alias in aliases) { + if (alias === key || key.startsWith(alias)) { + continue; + } + if (aliases[key].startsWith(alias) && pathSeparators.has(aliases[key][alias.length])) { + aliases[key] = aliases[alias] + aliases[key].slice(alias.length); + } + } + } + Object.defineProperty(aliases, normalizedAliasSymbol, { + value: true, + enumerable: false + }); + return aliases; +} +function resolveAlias$1(path, aliases) { + const _path = normalizeWindowsPath(path); + aliases = normalizeAliases(aliases); + for (const [alias, to] of Object.entries(aliases)) { + if (!_path.startsWith(alias)) { + continue; + } + const _alias = hasTrailingSlash(alias) ? alias.slice(0, -1) : alias; + if (hasTrailingSlash(_path[_alias.length])) { + return join(to, _path.slice(alias.length)); + } + } + return _path; +} +function _compareAliases(a, b) { + return b.split("/").length - a.split("/").length; +} +function hasTrailingSlash(path = "/") { + const lastChar = path[path.length - 1]; + return lastChar === "/" || lastChar === "\\"; +} + +const nuxtCtx = getContext("nuxt"); +function tryUseNuxt() { + return nuxtCtx.tryUse(); +} + +/** Detect free variable `global` from Node.js. */ +var freeGlobal = typeof global == 'object' && global && global.Object === Object && global; + +/** Detect free variable `self`. */ +var freeSelf = typeof self == 'object' && self && self.Object === Object && self; + +/** Used as a reference to the global object. */ +var root = freeGlobal || freeSelf || Function('return this')(); + +/** Built-in value references. */ +var Symbol$1 = root.Symbol; + +/** Used for built-in method references. */ +var objectProto$b = Object.prototype; + +/** Used to check objects for own properties. */ +var hasOwnProperty$9 = objectProto$b.hasOwnProperty; + +/** + * Used to resolve the + * [`toStringTag`](http://ecma-international.org/ecma-262/7.0/#sec-object.prototype.tostring) + * of values. + */ +var nativeObjectToString$1 = objectProto$b.toString; + +/** Built-in value references. */ +var symToStringTag$1 = Symbol$1 ? Symbol$1.toStringTag : undefined; + +/** + * A specialized version of `baseGetTag` which ignores `Symbol.toStringTag` values. + * + * @private + * @param {*} value The value to query. + * @returns {string} Returns the raw `toStringTag`. + */ +function getRawTag(value) { + var isOwn = hasOwnProperty$9.call(value, symToStringTag$1), + tag = value[symToStringTag$1]; + + try { + value[symToStringTag$1] = undefined; + var unmasked = true; + } catch (e) {} + + var result = nativeObjectToString$1.call(value); + if (unmasked) { + if (isOwn) { + value[symToStringTag$1] = tag; + } else { + delete value[symToStringTag$1]; + } + } + return result; +} + +/** Used for built-in method references. */ +var objectProto$a = Object.prototype; + +/** + * Used to resolve the + * [`toStringTag`](http://ecma-international.org/ecma-262/7.0/#sec-object.prototype.tostring) + * of values. + */ +var nativeObjectToString = objectProto$a.toString; + +/** + * Converts `value` to a string using `Object.prototype.toString`. + * + * @private + * @param {*} value The value to convert. + * @returns {string} Returns the converted string. + */ +function objectToString(value) { + return nativeObjectToString.call(value); +} + +/** `Object#toString` result references. */ +var nullTag = '[object Null]', + undefinedTag = '[object Undefined]'; + +/** Built-in value references. */ +var symToStringTag = Symbol$1 ? Symbol$1.toStringTag : undefined; + +/** + * The base implementation of `getTag` without fallbacks for buggy environments. + * + * @private + * @param {*} value The value to query. + * @returns {string} Returns the `toStringTag`. + */ +function baseGetTag(value) { + if (value == null) { + return value === undefined ? undefinedTag : nullTag; + } + return (symToStringTag && symToStringTag in Object(value)) + ? getRawTag(value) + : objectToString(value); +} + +/** + * Checks if `value` is object-like. A value is object-like if it's not `null` + * and has a `typeof` result of "object". + * + * @static + * @memberOf _ + * @since 4.0.0 + * @category Lang + * @param {*} value The value to check. + * @returns {boolean} Returns `true` if `value` is object-like, else `false`. + * @example + * + * _.isObjectLike({}); + * // => true + * + * _.isObjectLike([1, 2, 3]); + * // => true + * + * _.isObjectLike(_.noop); + * // => false + * + * _.isObjectLike(null); + * // => false + */ +function isObjectLike(value) { + return value != null && typeof value == 'object'; +} + +/** + * Checks if `value` is classified as an `Array` object. + * + * @static + * @memberOf _ + * @since 0.1.0 + * @category Lang + * @param {*} value The value to check. + * @returns {boolean} Returns `true` if `value` is an array, else `false`. + * @example + * + * _.isArray([1, 2, 3]); + * // => true + * + * _.isArray(document.body.children); + * // => false + * + * _.isArray('abc'); + * // => false + * + * _.isArray(_.noop); + * // => false + */ +var isArray = Array.isArray; + +/** Used to convert symbols to primitives and strings. */ +var symbolProto = Symbol$1 ? Symbol$1.prototype : undefined; + symbolProto ? symbolProto.toString : undefined; + +/** + * Checks if `value` is the + * [language type](http://www.ecma-international.org/ecma-262/7.0/#sec-ecmascript-language-types) + * of `Object`. (e.g. arrays, functions, objects, regexes, `new Number(0)`, and `new String('')`) + * + * @static + * @memberOf _ + * @since 0.1.0 + * @category Lang + * @param {*} value The value to check. + * @returns {boolean} Returns `true` if `value` is an object, else `false`. + * @example + * + * _.isObject({}); + * // => true + * + * _.isObject([1, 2, 3]); + * // => true + * + * _.isObject(_.noop); + * // => true + * + * _.isObject(null); + * // => false + */ +function isObject(value) { + var type = typeof value; + return value != null && (type == 'object' || type == 'function'); +} + +/** + * This method returns the first argument it receives. + * + * @static + * @since 0.1.0 + * @memberOf _ + * @category Util + * @param {*} value Any value. + * @returns {*} Returns `value`. + * @example + * + * var object = { 'a': 1 }; + * + * console.log(_.identity(object) === object); + * // => true + */ +function identity(value) { + return value; +} + +/** `Object#toString` result references. */ +var asyncTag = '[object AsyncFunction]', + funcTag$1 = '[object Function]', + genTag = '[object GeneratorFunction]', + proxyTag = '[object Proxy]'; + +/** + * Checks if `value` is classified as a `Function` object. + * + * @static + * @memberOf _ + * @since 0.1.0 + * @category Lang + * @param {*} value The value to check. + * @returns {boolean} Returns `true` if `value` is a function, else `false`. + * @example + * + * _.isFunction(_); + * // => true + * + * _.isFunction(/abc/); + * // => false + */ +function isFunction(value) { + if (!isObject(value)) { + return false; + } + // The use of `Object#toString` avoids issues with the `typeof` operator + // in Safari 9 which returns 'object' for typed arrays and other constructors. + var tag = baseGetTag(value); + return tag == funcTag$1 || tag == genTag || tag == asyncTag || tag == proxyTag; +} + +/** Used to detect overreaching core-js shims. */ +var coreJsData = root['__core-js_shared__']; + +/** Used to detect methods masquerading as native. */ +var maskSrcKey = (function() { + var uid = /[^.]+$/.exec(coreJsData && coreJsData.keys && coreJsData.keys.IE_PROTO || ''); + return uid ? ('Symbol(src)_1.' + uid) : ''; +}()); + +/** + * Checks if `func` has its source masked. + * + * @private + * @param {Function} func The function to check. + * @returns {boolean} Returns `true` if `func` is masked, else `false`. + */ +function isMasked(func) { + return !!maskSrcKey && (maskSrcKey in func); +} + +/** Used for built-in method references. */ +var funcProto$2 = Function.prototype; + +/** Used to resolve the decompiled source of functions. */ +var funcToString$2 = funcProto$2.toString; + +/** + * Converts `func` to its source code. + * + * @private + * @param {Function} func The function to convert. + * @returns {string} Returns the source code. + */ +function toSource(func) { + if (func != null) { + try { + return funcToString$2.call(func); + } catch (e) {} + try { + return (func + ''); + } catch (e) {} + } + return ''; +} + +/** + * Used to match `RegExp` + * [syntax characters](http://ecma-international.org/ecma-262/7.0/#sec-patterns). + */ +var reRegExpChar = /[\\^$.*+?()[\]{}|]/g; + +/** Used to detect host constructors (Safari). */ +var reIsHostCtor = /^\[object .+?Constructor\]$/; + +/** Used for built-in method references. */ +var funcProto$1 = Function.prototype, + objectProto$9 = Object.prototype; + +/** Used to resolve the decompiled source of functions. */ +var funcToString$1 = funcProto$1.toString; + +/** Used to check objects for own properties. */ +var hasOwnProperty$8 = objectProto$9.hasOwnProperty; + +/** Used to detect if a method is native. */ +var reIsNative = RegExp('^' + + funcToString$1.call(hasOwnProperty$8).replace(reRegExpChar, '\\$&') + .replace(/hasOwnProperty|(function).*?(?=\\\()| for .+?(?=\\\])/g, '$1.*?') + '$' +); + +/** + * The base implementation of `_.isNative` without bad shim checks. + * + * @private + * @param {*} value The value to check. + * @returns {boolean} Returns `true` if `value` is a native function, + * else `false`. + */ +function baseIsNative(value) { + if (!isObject(value) || isMasked(value)) { + return false; + } + var pattern = isFunction(value) ? reIsNative : reIsHostCtor; + return pattern.test(toSource(value)); +} + +/** + * Gets the value at `key` of `object`. + * + * @private + * @param {Object} [object] The object to query. + * @param {string} key The key of the property to get. + * @returns {*} Returns the property value. + */ +function getValue(object, key) { + return object == null ? undefined : object[key]; +} + +/** + * Gets the native function at `key` of `object`. + * + * @private + * @param {Object} object The object to query. + * @param {string} key The key of the method to get. + * @returns {*} Returns the function if it's native, else `undefined`. + */ +function getNative(object, key) { + var value = getValue(object, key); + return baseIsNative(value) ? value : undefined; +} + +/** + * A faster alternative to `Function#apply`, this function invokes `func` + * with the `this` binding of `thisArg` and the arguments of `args`. + * + * @private + * @param {Function} func The function to invoke. + * @param {*} thisArg The `this` binding of `func`. + * @param {Array} args The arguments to invoke `func` with. + * @returns {*} Returns the result of `func`. + */ +function apply(func, thisArg, args) { + switch (args.length) { + case 0: return func.call(thisArg); + case 1: return func.call(thisArg, args[0]); + case 2: return func.call(thisArg, args[0], args[1]); + case 3: return func.call(thisArg, args[0], args[1], args[2]); + } + return func.apply(thisArg, args); +} + +/** Used to detect hot functions by number of calls within a span of milliseconds. */ +var HOT_COUNT = 800, + HOT_SPAN = 16; + +/* Built-in method references for those with the same name as other `lodash` methods. */ +var nativeNow = Date.now; + +/** + * Creates a function that'll short out and invoke `identity` instead + * of `func` when it's called `HOT_COUNT` or more times in `HOT_SPAN` + * milliseconds. + * + * @private + * @param {Function} func The function to restrict. + * @returns {Function} Returns the new shortable function. + */ +function shortOut(func) { + var count = 0, + lastCalled = 0; + + return function() { + var stamp = nativeNow(), + remaining = HOT_SPAN - (stamp - lastCalled); + + lastCalled = stamp; + if (remaining > 0) { + if (++count >= HOT_COUNT) { + return arguments[0]; + } + } else { + count = 0; + } + return func.apply(undefined, arguments); + }; +} + +/** + * Creates a function that returns `value`. + * + * @static + * @memberOf _ + * @since 2.4.0 + * @category Util + * @param {*} value The value to return from the new function. + * @returns {Function} Returns the new constant function. + * @example + * + * var objects = _.times(2, _.constant({ 'a': 1 })); + * + * console.log(objects); + * // => [{ 'a': 1 }, { 'a': 1 }] + * + * console.log(objects[0] === objects[1]); + * // => true + */ +function constant(value) { + return function() { + return value; + }; +} + +var defineProperty = (function() { + try { + var func = getNative(Object, 'defineProperty'); + func({}, '', {}); + return func; + } catch (e) {} +}()); + +/** + * The base implementation of `setToString` without support for hot loop shorting. + * + * @private + * @param {Function} func The function to modify. + * @param {Function} string The `toString` result. + * @returns {Function} Returns `func`. + */ +var baseSetToString = !defineProperty ? identity : function(func, string) { + return defineProperty(func, 'toString', { + 'configurable': true, + 'enumerable': false, + 'value': constant(string), + 'writable': true + }); +}; + +const baseSetToString$1 = baseSetToString; + +/** + * Sets the `toString` method of `func` to return `string`. + * + * @private + * @param {Function} func The function to modify. + * @param {Function} string The `toString` result. + * @returns {Function} Returns `func`. + */ +var setToString = shortOut(baseSetToString$1); + +/** Used as references for various `Number` constants. */ +var MAX_SAFE_INTEGER$1 = 9007199254740991; + +/** Used to detect unsigned integer values. */ +var reIsUint = /^(?:0|[1-9]\d*)$/; + +/** + * Checks if `value` is a valid array-like index. + * + * @private + * @param {*} value The value to check. + * @param {number} [length=MAX_SAFE_INTEGER] The upper bounds of a valid index. + * @returns {boolean} Returns `true` if `value` is a valid index, else `false`. + */ +function isIndex(value, length) { + var type = typeof value; + length = length == null ? MAX_SAFE_INTEGER$1 : length; + + return !!length && + (type == 'number' || + (type != 'symbol' && reIsUint.test(value))) && + (value > -1 && value % 1 == 0 && value < length); +} + +/** + * The base implementation of `assignValue` and `assignMergeValue` without + * value checks. + * + * @private + * @param {Object} object The object to modify. + * @param {string} key The key of the property to assign. + * @param {*} value The value to assign. + */ +function baseAssignValue(object, key, value) { + if (key == '__proto__' && defineProperty) { + defineProperty(object, key, { + 'configurable': true, + 'enumerable': true, + 'value': value, + 'writable': true + }); + } else { + object[key] = value; + } +} + +/** + * Performs a + * [`SameValueZero`](http://ecma-international.org/ecma-262/7.0/#sec-samevaluezero) + * comparison between two values to determine if they are equivalent. + * + * @static + * @memberOf _ + * @since 4.0.0 + * @category Lang + * @param {*} value The value to compare. + * @param {*} other The other value to compare. + * @returns {boolean} Returns `true` if the values are equivalent, else `false`. + * @example + * + * var object = { 'a': 1 }; + * var other = { 'a': 1 }; + * + * _.eq(object, object); + * // => true + * + * _.eq(object, other); + * // => false + * + * _.eq('a', 'a'); + * // => true + * + * _.eq('a', Object('a')); + * // => false + * + * _.eq(NaN, NaN); + * // => true + */ +function eq(value, other) { + return value === other || (value !== value && other !== other); +} + +/** Used for built-in method references. */ +var objectProto$8 = Object.prototype; + +/** Used to check objects for own properties. */ +var hasOwnProperty$7 = objectProto$8.hasOwnProperty; + +/** + * Assigns `value` to `key` of `object` if the existing value is not equivalent + * using [`SameValueZero`](http://ecma-international.org/ecma-262/7.0/#sec-samevaluezero) + * for equality comparisons. + * + * @private + * @param {Object} object The object to modify. + * @param {string} key The key of the property to assign. + * @param {*} value The value to assign. + */ +function assignValue(object, key, value) { + var objValue = object[key]; + if (!(hasOwnProperty$7.call(object, key) && eq(objValue, value)) || + (value === undefined && !(key in object))) { + baseAssignValue(object, key, value); + } +} + +/** + * Copies properties of `source` to `object`. + * + * @private + * @param {Object} source The object to copy properties from. + * @param {Array} props The property identifiers to copy. + * @param {Object} [object={}] The object to copy properties to. + * @param {Function} [customizer] The function to customize copied values. + * @returns {Object} Returns `object`. + */ +function copyObject(source, props, object, customizer) { + var isNew = !object; + object || (object = {}); + + var index = -1, + length = props.length; + + while (++index < length) { + var key = props[index]; + + var newValue = customizer + ? customizer(object[key], source[key], key, object, source) + : undefined; + + if (newValue === undefined) { + newValue = source[key]; + } + if (isNew) { + baseAssignValue(object, key, newValue); + } else { + assignValue(object, key, newValue); + } + } + return object; +} + +/* Built-in method references for those with the same name as other `lodash` methods. */ +var nativeMax = Math.max; + +/** + * A specialized version of `baseRest` which transforms the rest array. + * + * @private + * @param {Function} func The function to apply a rest parameter to. + * @param {number} [start=func.length-1] The start position of the rest parameter. + * @param {Function} transform The rest array transform. + * @returns {Function} Returns the new function. + */ +function overRest(func, start, transform) { + start = nativeMax(start === undefined ? (func.length - 1) : start, 0); + return function() { + var args = arguments, + index = -1, + length = nativeMax(args.length - start, 0), + array = Array(length); + + while (++index < length) { + array[index] = args[start + index]; + } + index = -1; + var otherArgs = Array(start + 1); + while (++index < start) { + otherArgs[index] = args[index]; + } + otherArgs[start] = transform(array); + return apply(func, this, otherArgs); + }; +} + +/** + * The base implementation of `_.rest` which doesn't validate or coerce arguments. + * + * @private + * @param {Function} func The function to apply a rest parameter to. + * @param {number} [start=func.length-1] The start position of the rest parameter. + * @returns {Function} Returns the new function. + */ +function baseRest(func, start) { + return setToString(overRest(func, start, identity), func + ''); +} + +/** Used as references for various `Number` constants. */ +var MAX_SAFE_INTEGER = 9007199254740991; + +/** + * Checks if `value` is a valid array-like length. + * + * **Note:** This method is loosely based on + * [`ToLength`](http://ecma-international.org/ecma-262/7.0/#sec-tolength). + * + * @static + * @memberOf _ + * @since 4.0.0 + * @category Lang + * @param {*} value The value to check. + * @returns {boolean} Returns `true` if `value` is a valid length, else `false`. + * @example + * + * _.isLength(3); + * // => true + * + * _.isLength(Number.MIN_VALUE); + * // => false + * + * _.isLength(Infinity); + * // => false + * + * _.isLength('3'); + * // => false + */ +function isLength(value) { + return typeof value == 'number' && + value > -1 && value % 1 == 0 && value <= MAX_SAFE_INTEGER; +} + +/** + * Checks if `value` is array-like. A value is considered array-like if it's + * not a function and has a `value.length` that's an integer greater than or + * equal to `0` and less than or equal to `Number.MAX_SAFE_INTEGER`. + * + * @static + * @memberOf _ + * @since 4.0.0 + * @category Lang + * @param {*} value The value to check. + * @returns {boolean} Returns `true` if `value` is array-like, else `false`. + * @example + * + * _.isArrayLike([1, 2, 3]); + * // => true + * + * _.isArrayLike(document.body.children); + * // => true + * + * _.isArrayLike('abc'); + * // => true + * + * _.isArrayLike(_.noop); + * // => false + */ +function isArrayLike(value) { + return value != null && isLength(value.length) && !isFunction(value); +} + +/** + * Checks if the given arguments are from an iteratee call. + * + * @private + * @param {*} value The potential iteratee value argument. + * @param {*} index The potential iteratee index or key argument. + * @param {*} object The potential iteratee object argument. + * @returns {boolean} Returns `true` if the arguments are from an iteratee call, + * else `false`. + */ +function isIterateeCall(value, index, object) { + if (!isObject(object)) { + return false; + } + var type = typeof index; + if (type == 'number' + ? (isArrayLike(object) && isIndex(index, object.length)) + : (type == 'string' && index in object) + ) { + return eq(object[index], value); + } + return false; +} + +/** + * Creates a function like `_.assign`. + * + * @private + * @param {Function} assigner The function to assign values. + * @returns {Function} Returns the new assigner function. + */ +function createAssigner(assigner) { + return baseRest(function(object, sources) { + var index = -1, + length = sources.length, + customizer = length > 1 ? sources[length - 1] : undefined, + guard = length > 2 ? sources[2] : undefined; + + customizer = (assigner.length > 3 && typeof customizer == 'function') + ? (length--, customizer) + : undefined; + + if (guard && isIterateeCall(sources[0], sources[1], guard)) { + customizer = length < 3 ? undefined : customizer; + length = 1; + } + object = Object(object); + while (++index < length) { + var source = sources[index]; + if (source) { + assigner(object, source, index, customizer); + } + } + return object; + }); +} + +/** Used for built-in method references. */ +var objectProto$7 = Object.prototype; + +/** + * Checks if `value` is likely a prototype object. + * + * @private + * @param {*} value The value to check. + * @returns {boolean} Returns `true` if `value` is a prototype, else `false`. + */ +function isPrototype(value) { + var Ctor = value && value.constructor, + proto = (typeof Ctor == 'function' && Ctor.prototype) || objectProto$7; + + return value === proto; +} + +/** + * The base implementation of `_.times` without support for iteratee shorthands + * or max array length checks. + * + * @private + * @param {number} n The number of times to invoke `iteratee`. + * @param {Function} iteratee The function invoked per iteration. + * @returns {Array} Returns the array of results. + */ +function baseTimes(n, iteratee) { + var index = -1, + result = Array(n); + + while (++index < n) { + result[index] = iteratee(index); + } + return result; +} + +/** `Object#toString` result references. */ +var argsTag$1 = '[object Arguments]'; + +/** + * The base implementation of `_.isArguments`. + * + * @private + * @param {*} value The value to check. + * @returns {boolean} Returns `true` if `value` is an `arguments` object, + */ +function baseIsArguments(value) { + return isObjectLike(value) && baseGetTag(value) == argsTag$1; +} + +/** Used for built-in method references. */ +var objectProto$6 = Object.prototype; + +/** Used to check objects for own properties. */ +var hasOwnProperty$6 = objectProto$6.hasOwnProperty; + +/** Built-in value references. */ +var propertyIsEnumerable = objectProto$6.propertyIsEnumerable; + +/** + * Checks if `value` is likely an `arguments` object. + * + * @static + * @memberOf _ + * @since 0.1.0 + * @category Lang + * @param {*} value The value to check. + * @returns {boolean} Returns `true` if `value` is an `arguments` object, + * else `false`. + * @example + * + * _.isArguments(function() { return arguments; }()); + * // => true + * + * _.isArguments([1, 2, 3]); + * // => false + */ +var isArguments = baseIsArguments(function() { return arguments; }()) ? baseIsArguments : function(value) { + return isObjectLike(value) && hasOwnProperty$6.call(value, 'callee') && + !propertyIsEnumerable.call(value, 'callee'); +}; + +/** + * This method returns `false`. + * + * @static + * @memberOf _ + * @since 4.13.0 + * @category Util + * @returns {boolean} Returns `false`. + * @example + * + * _.times(2, _.stubFalse); + * // => [false, false] + */ +function stubFalse() { + return false; +} + +/** Detect free variable `exports`. */ +var freeExports$1 = typeof exports == 'object' && exports && !exports.nodeType && exports; + +/** Detect free variable `module`. */ +var freeModule$1 = freeExports$1 && typeof module == 'object' && module && !module.nodeType && module; + +/** Detect the popular CommonJS extension `module.exports`. */ +var moduleExports$1 = freeModule$1 && freeModule$1.exports === freeExports$1; + +/** Built-in value references. */ +var Buffer = moduleExports$1 ? root.Buffer : undefined; + +/* Built-in method references for those with the same name as other `lodash` methods. */ +var nativeIsBuffer = Buffer ? Buffer.isBuffer : undefined; + +/** + * Checks if `value` is a buffer. + * + * @static + * @memberOf _ + * @since 4.3.0 + * @category Lang + * @param {*} value The value to check. + * @returns {boolean} Returns `true` if `value` is a buffer, else `false`. + * @example + * + * _.isBuffer(new Buffer(2)); + * // => true + * + * _.isBuffer(new Uint8Array(2)); + * // => false + */ +var isBuffer = nativeIsBuffer || stubFalse; + +/** `Object#toString` result references. */ +var argsTag = '[object Arguments]', + arrayTag = '[object Array]', + boolTag = '[object Boolean]', + dateTag = '[object Date]', + errorTag$1 = '[object Error]', + funcTag = '[object Function]', + mapTag = '[object Map]', + numberTag = '[object Number]', + objectTag$1 = '[object Object]', + regexpTag = '[object RegExp]', + setTag = '[object Set]', + stringTag = '[object String]', + weakMapTag = '[object WeakMap]'; + +var arrayBufferTag = '[object ArrayBuffer]', + dataViewTag = '[object DataView]', + float32Tag = '[object Float32Array]', + float64Tag = '[object Float64Array]', + int8Tag = '[object Int8Array]', + int16Tag = '[object Int16Array]', + int32Tag = '[object Int32Array]', + uint8Tag = '[object Uint8Array]', + uint8ClampedTag = '[object Uint8ClampedArray]', + uint16Tag = '[object Uint16Array]', + uint32Tag = '[object Uint32Array]'; + +/** Used to identify `toStringTag` values of typed arrays. */ +var typedArrayTags = {}; +typedArrayTags[float32Tag] = typedArrayTags[float64Tag] = +typedArrayTags[int8Tag] = typedArrayTags[int16Tag] = +typedArrayTags[int32Tag] = typedArrayTags[uint8Tag] = +typedArrayTags[uint8ClampedTag] = typedArrayTags[uint16Tag] = +typedArrayTags[uint32Tag] = true; +typedArrayTags[argsTag] = typedArrayTags[arrayTag] = +typedArrayTags[arrayBufferTag] = typedArrayTags[boolTag] = +typedArrayTags[dataViewTag] = typedArrayTags[dateTag] = +typedArrayTags[errorTag$1] = typedArrayTags[funcTag] = +typedArrayTags[mapTag] = typedArrayTags[numberTag] = +typedArrayTags[objectTag$1] = typedArrayTags[regexpTag] = +typedArrayTags[setTag] = typedArrayTags[stringTag] = +typedArrayTags[weakMapTag] = false; + +/** + * The base implementation of `_.isTypedArray` without Node.js optimizations. + * + * @private + * @param {*} value The value to check. + * @returns {boolean} Returns `true` if `value` is a typed array, else `false`. + */ +function baseIsTypedArray(value) { + return isObjectLike(value) && + isLength(value.length) && !!typedArrayTags[baseGetTag(value)]; +} + +/** + * The base implementation of `_.unary` without support for storing metadata. + * + * @private + * @param {Function} func The function to cap arguments for. + * @returns {Function} Returns the new capped function. + */ +function baseUnary(func) { + return function(value) { + return func(value); + }; +} + +/** Detect free variable `exports`. */ +var freeExports = typeof exports == 'object' && exports && !exports.nodeType && exports; + +/** Detect free variable `module`. */ +var freeModule = freeExports && typeof module == 'object' && module && !module.nodeType && module; + +/** Detect the popular CommonJS extension `module.exports`. */ +var moduleExports = freeModule && freeModule.exports === freeExports; + +/** Detect free variable `process` from Node.js. */ +var freeProcess = moduleExports && freeGlobal.process; + +/** Used to access faster Node.js helpers. */ +var nodeUtil = (function() { + try { + // Use `util.types` for Node.js 10+. + var types = freeModule && freeModule.require && freeModule.require('util').types; + + if (types) { + return types; + } + + // Legacy `process.binding('util')` for Node.js < 10. + return freeProcess && freeProcess.binding && freeProcess.binding('util'); + } catch (e) {} +}()); + +/* Node.js helper references. */ +var nodeIsTypedArray = nodeUtil && nodeUtil.isTypedArray; + +/** + * Checks if `value` is classified as a typed array. + * + * @static + * @memberOf _ + * @since 3.0.0 + * @category Lang + * @param {*} value The value to check. + * @returns {boolean} Returns `true` if `value` is a typed array, else `false`. + * @example + * + * _.isTypedArray(new Uint8Array); + * // => true + * + * _.isTypedArray([]); + * // => false + */ +var isTypedArray = nodeIsTypedArray ? baseUnary(nodeIsTypedArray) : baseIsTypedArray; + +/** Used for built-in method references. */ +var objectProto$5 = Object.prototype; + +/** Used to check objects for own properties. */ +var hasOwnProperty$5 = objectProto$5.hasOwnProperty; + +/** + * Creates an array of the enumerable property names of the array-like `value`. + * + * @private + * @param {*} value The value to query. + * @param {boolean} inherited Specify returning inherited property names. + * @returns {Array} Returns the array of property names. + */ +function arrayLikeKeys(value, inherited) { + var isArr = isArray(value), + isArg = !isArr && isArguments(value), + isBuff = !isArr && !isArg && isBuffer(value), + isType = !isArr && !isArg && !isBuff && isTypedArray(value), + skipIndexes = isArr || isArg || isBuff || isType, + result = skipIndexes ? baseTimes(value.length, String) : [], + length = result.length; + + for (var key in value) { + if ((inherited || hasOwnProperty$5.call(value, key)) && + !(skipIndexes && ( + // Safari 9 has enumerable `arguments.length` in strict mode. + key == 'length' || + // Node.js 0.10 has enumerable non-index properties on buffers. + (isBuff && (key == 'offset' || key == 'parent')) || + // PhantomJS 2 has enumerable non-index properties on typed arrays. + (isType && (key == 'buffer' || key == 'byteLength' || key == 'byteOffset')) || + // Skip index properties. + isIndex(key, length) + ))) { + result.push(key); + } + } + return result; +} + +/** + * Creates a unary function that invokes `func` with its argument transformed. + * + * @private + * @param {Function} func The function to wrap. + * @param {Function} transform The argument transform. + * @returns {Function} Returns the new function. + */ +function overArg(func, transform) { + return function(arg) { + return func(transform(arg)); + }; +} + +/** + * This function is like + * [`Object.keys`](http://ecma-international.org/ecma-262/7.0/#sec-object.keys) + * except that it includes inherited enumerable properties. + * + * @private + * @param {Object} object The object to query. + * @returns {Array} Returns the array of property names. + */ +function nativeKeysIn(object) { + var result = []; + if (object != null) { + for (var key in Object(object)) { + result.push(key); + } + } + return result; +} + +/** Used for built-in method references. */ +var objectProto$3 = Object.prototype; + +/** Used to check objects for own properties. */ +var hasOwnProperty$3 = objectProto$3.hasOwnProperty; + +/** + * The base implementation of `_.keysIn` which doesn't treat sparse arrays as dense. + * + * @private + * @param {Object} object The object to query. + * @returns {Array} Returns the array of property names. + */ +function baseKeysIn(object) { + if (!isObject(object)) { + return nativeKeysIn(object); + } + var isProto = isPrototype(object), + result = []; + + for (var key in object) { + if (!(key == 'constructor' && (isProto || !hasOwnProperty$3.call(object, key)))) { + result.push(key); + } + } + return result; +} + +/** + * Creates an array of the own and inherited enumerable property names of `object`. + * + * **Note:** Non-object values are coerced to objects. + * + * @static + * @memberOf _ + * @since 3.0.0 + * @category Object + * @param {Object} object The object to query. + * @returns {Array} Returns the array of property names. + * @example + * + * function Foo() { + * this.a = 1; + * this.b = 2; + * } + * + * Foo.prototype.c = 3; + * + * _.keysIn(new Foo); + * // => ['a', 'b', 'c'] (iteration order is not guaranteed) + */ +function keysIn(object) { + return isArrayLike(object) ? arrayLikeKeys(object, true) : baseKeysIn(object); +} + +/** + * This method is like `_.assignIn` except that it accepts `customizer` + * which is invoked to produce the assigned values. If `customizer` returns + * `undefined`, assignment is handled by the method instead. The `customizer` + * is invoked with five arguments: (objValue, srcValue, key, object, source). + * + * **Note:** This method mutates `object`. + * + * @static + * @memberOf _ + * @since 4.0.0 + * @alias extendWith + * @category Object + * @param {Object} object The destination object. + * @param {...Object} sources The source objects. + * @param {Function} [customizer] The function to customize assigned values. + * @returns {Object} Returns `object`. + * @see _.assignWith + * @example + * + * function customizer(objValue, srcValue) { + * return _.isUndefined(objValue) ? srcValue : objValue; + * } + * + * var defaults = _.partialRight(_.assignInWith, customizer); + * + * defaults({ 'a': 1 }, { 'b': 2 }, { 'a': 3 }); + * // => { 'a': 1, 'b': 2 } + */ +createAssigner(function(object, source, srcIndex, customizer) { + copyObject(source, keysIn(source), object, customizer); +}); + +/** Built-in value references. */ +var getPrototype = overArg(Object.getPrototypeOf, Object); + +/** `Object#toString` result references. */ +var objectTag = '[object Object]'; + +/** Used for built-in method references. */ +var funcProto = Function.prototype, + objectProto$2 = Object.prototype; + +/** Used to resolve the decompiled source of functions. */ +var funcToString = funcProto.toString; + +/** Used to check objects for own properties. */ +var hasOwnProperty$2 = objectProto$2.hasOwnProperty; + +/** Used to infer the `Object` constructor. */ +var objectCtorString = funcToString.call(Object); + +/** + * Checks if `value` is a plain object, that is, an object created by the + * `Object` constructor or one with a `[[Prototype]]` of `null`. + * + * @static + * @memberOf _ + * @since 0.8.0 + * @category Lang + * @param {*} value The value to check. + * @returns {boolean} Returns `true` if `value` is a plain object, else `false`. + * @example + * + * function Foo() { + * this.a = 1; + * } + * + * _.isPlainObject(new Foo); + * // => false + * + * _.isPlainObject([1, 2, 3]); + * // => false + * + * _.isPlainObject({ 'x': 0, 'y': 0 }); + * // => true + * + * _.isPlainObject(Object.create(null)); + * // => true + */ +function isPlainObject(value) { + if (!isObjectLike(value) || baseGetTag(value) != objectTag) { + return false; + } + var proto = getPrototype(value); + if (proto === null) { + return true; + } + var Ctor = hasOwnProperty$2.call(proto, 'constructor') && proto.constructor; + return typeof Ctor == 'function' && Ctor instanceof Ctor && + funcToString.call(Ctor) == objectCtorString; +} + +/** `Object#toString` result references. */ +var domExcTag = '[object DOMException]', + errorTag = '[object Error]'; + +/** + * Checks if `value` is an `Error`, `EvalError`, `RangeError`, `ReferenceError`, + * `SyntaxError`, `TypeError`, or `URIError` object. + * + * @static + * @memberOf _ + * @since 3.0.0 + * @category Lang + * @param {*} value The value to check. + * @returns {boolean} Returns `true` if `value` is an error object, else `false`. + * @example + * + * _.isError(new Error); + * // => true + * + * _.isError(Error); + * // => false + */ +function isError(value) { + if (!isObjectLike(value)) { + return false; + } + var tag = baseGetTag(value); + return tag == errorTag || tag == domExcTag || + (typeof value.message == 'string' && typeof value.name == 'string' && !isPlainObject(value)); +} + +/** + * Attempts to invoke `func`, returning either the result or the caught error + * object. Any additional arguments are provided to `func` when it's invoked. + * + * @static + * @memberOf _ + * @since 3.0.0 + * @category Util + * @param {Function} func The function to attempt. + * @param {...*} [args] The arguments to invoke `func` with. + * @returns {*} Returns the `func` result or error object. + * @example + * + * // Avoid throwing errors for invalid selectors. + * var elements = _.attempt(function(selector) { + * return document.querySelectorAll(selector); + * }, '>_>'); + * + * if (_.isError(elements)) { + * elements = []; + * } + */ +baseRest(function(func, args) { + try { + return apply(func, undefined, args); + } catch (e) { + return isError(e) ? e : new Error(e); + } +}); + +jiti(process.cwd(), { interopDefault: true, esmResolve: true }); +function getModulePaths(paths) { + return [].concat( + global.__NUXT_PREPATHS__, + paths || [], + process.cwd(), + global.__NUXT_PATHS__ + ).filter(Boolean); +} + +async function tryResolveModule(id, url = import.meta.url) { + try { + return await resolvePath$1(id, { url }); + } catch { + } +} + +async function resolvePath(path, opts = {}) { + const _path = path; + path = normalize(path); + if (isAbsolute(path) && existsSync(path) && !await isDirectory(path)) { + return path; + } + const nuxt = tryUseNuxt(); + const cwd = opts.cwd || (nuxt ? nuxt.options.rootDir : process.cwd()); + const extensions = opts.extensions || (nuxt ? nuxt.options.extensions : [".ts", ".mjs", ".cjs", ".json"]); + const modulesDir = nuxt ? nuxt.options.modulesDir : []; + path = resolveAlias(path); + if (!isAbsolute(path)) { + path = resolve(cwd, path); + } + let _isDir = false; + if (existsSync(path)) { + _isDir = await isDirectory(path); + if (!_isDir) { + return path; + } + } + for (const ext of extensions) { + const pathWithExt = path + ext; + if (existsSync(pathWithExt)) { + return pathWithExt; + } + const pathWithIndex = join(path, "index" + ext); + if (_isDir && existsSync(pathWithIndex)) { + return pathWithIndex; + } + } + const resolveModulePath = await resolvePath$1(_path, { url: [cwd, ...modulesDir] }).catch(() => null); + if (resolveModulePath) { + return resolveModulePath; + } + return path; +} +function resolveAlias(path, alias) { + if (!alias) { + alias = tryUseNuxt()?.options.alias || {}; + } + return resolveAlias$1(path, alias); +} +function createResolver(base) { + if (!base) { + throw new Error("`base` argument is missing for createResolver(base)!"); + } + base = base.toString(); + if (base.startsWith("file://")) { + base = dirname(fileURLToPath(base)); + } + return { + resolve: (...path) => resolve(base, ...path), + resolvePath: (path, opts) => resolvePath(path, { cwd: base, ...opts }) + }; +} +async function resolveNuxtModule(base, paths) { + const resolved = []; + const resolver = createResolver(base); + for (const path of paths) { + if (path.startsWith(base)) { + resolved.push(path.split("/index.ts")[0]); + } else { + const resolvedPath = await resolver.resolvePath(path); + resolved.push(resolvedPath.slice(0, resolvedPath.lastIndexOf(path) + path.length)); + } + } + return resolved; +} +async function isDirectory(path) { + return (await promises.lstat(path)).isDirectory(); +} +function getDirectory(p) { + try { + return isAbsolute(p) && lstatSync(p).isFile() ? dirname(p) : p; + } catch (e) { + } + return p; +} +async function _generateTypes(nuxt) { + const nodeModulePaths = getModulePaths(nuxt.options.modulesDir); + const rootDirWithSlash = withTrailingSlash(nuxt.options.rootDir); + const modulePaths = await resolveNuxtModule( + rootDirWithSlash, + nuxt.options._installedModules.filter((m) => m.entryPath).map((m) => getDirectory(m.entryPath)) + ); + const tsConfig = defu(nuxt.options.typescript?.tsConfig, { + compilerOptions: { + forceConsistentCasingInFileNames: true, + jsx: "preserve", + jsxImportSource: "vue", + target: "ESNext", + module: "ESNext", + moduleResolution: nuxt.options.future?.typescriptBundlerResolution || nuxt.options.experimental?.typescriptBundlerResolution ? "Bundler" : "Node", + skipLibCheck: true, + isolatedModules: true, + useDefineForClassFields: true, + strict: nuxt.options.typescript?.strict ?? true, + noImplicitThis: true, + esModuleInterop: true, + types: [], + verbatimModuleSyntax: true, + allowJs: true, + noEmit: true, + resolveJsonModule: true, + allowSyntheticDefaultImports: true, + paths: {} + }, + include: [ + "./nuxt.d.ts", + join(relativeWithDot(nuxt.options.buildDir, nuxt.options.rootDir), ".config/nuxt.*"), + join(relativeWithDot(nuxt.options.buildDir, nuxt.options.rootDir), "**/*"), + ...nuxt.options.srcDir !== nuxt.options.rootDir ? [join(relative(nuxt.options.buildDir, nuxt.options.srcDir), "**/*")] : [], + ...nuxt.options._layers.map((layer) => layer.config.srcDir ?? layer.cwd).filter((srcOrCwd) => !srcOrCwd.startsWith(rootDirWithSlash) || srcOrCwd.includes("node_modules")).map((srcOrCwd) => join(relative(nuxt.options.buildDir, srcOrCwd), "**/*")), + ...nuxt.options.typescript.includeWorkspace && nuxt.options.workspaceDir !== nuxt.options.rootDir ? [join(relative(nuxt.options.buildDir, nuxt.options.workspaceDir), "**/*")] : [], + ...modulePaths.map((m) => join(relativeWithDot(nuxt.options.buildDir, m), "runtime")) + ], + exclude: [ + ...nuxt.options.modulesDir.map((m) => relativeWithDot(nuxt.options.buildDir, m)), + ...modulePaths.map((m) => join(relativeWithDot(nuxt.options.buildDir, m), "runtime/server")), + // nitro generate output: https://github.com/nuxt/nuxt/blob/main/packages/nuxt/src/core/nitro.ts#L186 + relativeWithDot(nuxt.options.buildDir, resolve(nuxt.options.rootDir, "dist")) + ] + }); + const aliases = { + ...nuxt.options.alias, + "#build": nuxt.options.buildDir + }; + const excludedAlias = [/^@vue\/.*$/]; + const basePath = tsConfig.compilerOptions.baseUrl ? resolve(nuxt.options.buildDir, tsConfig.compilerOptions.baseUrl) : nuxt.options.buildDir; + tsConfig.compilerOptions = tsConfig.compilerOptions || {}; + tsConfig.include = tsConfig.include || []; + for (const alias in aliases) { + if (excludedAlias.some((re) => re.test(alias))) { + continue; + } + let absolutePath = resolve(basePath, aliases[alias]); + let stats = await promises.stat(absolutePath).catch( + () => null + /* file does not exist */ + ); + if (!stats) { + const resolvedModule = await tryResolveModule(aliases[alias], nuxt.options.modulesDir); + if (resolvedModule) { + absolutePath = resolvedModule; + stats = await promises.stat(resolvedModule).catch(() => null); + } + } + const relativePath = relativeWithDot(nuxt.options.buildDir, absolutePath); + if (stats?.isDirectory()) { + tsConfig.compilerOptions.paths[alias] = [relativePath]; + tsConfig.compilerOptions.paths[`${alias}/*`] = [`${relativePath}/*`]; + if (!absolutePath.startsWith(rootDirWithSlash)) { + tsConfig.include.push(relativePath); + } + } else { + const path = stats?.isFile() ? relativePath.replace(/(?<=\w)\.\w+$/g, "") : aliases[alias]; + tsConfig.compilerOptions.paths[alias] = [path]; + if (!absolutePath.startsWith(rootDirWithSlash)) { + tsConfig.include.push(path); + } + } + } + const references = await Promise.all([ + ...nuxt.options.modules, + ...nuxt.options._modules + ].filter((f) => typeof f === "string").map(async (id) => ({ types: (await readPackageJSON(id, { url: nodeModulePaths }).catch(() => null))?.name || id }))); + const declarations = []; + await nuxt.callHook("prepare:types", { references, declarations, tsConfig }); + for (const alias in tsConfig.compilerOptions.paths) { + const paths = tsConfig.compilerOptions.paths[alias]; + tsConfig.compilerOptions.paths[alias] = await Promise.all(paths.map(async (path) => { + if (!isAbsolute(path)) { + return path; + } + const stats = await promises.stat(path).catch( + () => null + /* file does not exist */ + ); + return relativeWithDot(nuxt.options.buildDir, stats?.isFile() ? path.replace(/(?<=\w)\.\w+$/g, "") : path); + })); + } + tsConfig.include = [...new Set(tsConfig.include.map((p) => isAbsolute(p) ? relativeWithDot(nuxt.options.buildDir, p) : p))]; + tsConfig.exclude = [...new Set(tsConfig.exclude.map((p) => isAbsolute(p) ? relativeWithDot(nuxt.options.buildDir, p) : p))]; + const declaration = [ + ...references.map((ref) => { + if ("path" in ref && isAbsolute(ref.path)) { + ref.path = relative(nuxt.options.buildDir, ref.path); + } + return `/// `; + }), + ...declarations, + "", + "export {}", + "" + ].join("\n"); + return { + declaration, + tsConfig + }; +} +async function writeTypes(nuxt) { + const { tsConfig, declaration } = await _generateTypes(nuxt); + async function writeFile() { + const GeneratedBy = "// Generated by nuxi"; + const tsConfigPath = resolve(nuxt.options.buildDir, "tsconfig.json"); + await promises.mkdir(nuxt.options.buildDir, { recursive: true }); + await promises.writeFile(tsConfigPath, GeneratedBy + "\n" + JSON.stringify(tsConfig, null, 2)); + const declarationPath = resolve(nuxt.options.buildDir, "nuxt.d.ts"); + await promises.writeFile(declarationPath, GeneratedBy + "\n" + declaration); + } + nuxt.hook("builder:prepared", writeFile); + await writeFile(); +} +function renderAttrs(obj) { + return Object.entries(obj).map((e) => renderAttr(e[0], e[1])).join(" "); +} +function renderAttr(key, value) { + return value ? `${key}="${value}"` : ""; +} +function relativeWithDot(from, to) { + return relative(from, to).replace(/^([^.])/, "./$1") || "."; +} + +const loadKit = async (rootDir) => { + try { + const localKit = await tryResolveModule$1("@nuxt/kit", rootDir); + const rootURL = localKit ? rootDir : await tryResolveNuxt() || rootDir; + let kit = await importModule( + "@nuxt/kit", + rootURL + ); + if (!kit.writeTypes) { + kit = { ...kit, writeTypes: writeTypes }; + } + return kit; + } catch (e) { + if (e.toString().includes("Cannot find module '@nuxt/kit'")) { + throw new Error( + "nuxi requires `@nuxt/kit` to be installed in your project. Try installing `nuxt` v3 or `@nuxt/bridge` first." + ); + } + throw e; + } +}; +async function tryResolveNuxt() { + for (const pkg of ["nuxt-nightly", "nuxt3", "nuxt", "nuxt-edge"]) { + const path = await tryResolveModule$1(pkg); + if (path) { + return path; + } + } + return null; +} + +export { loadKit as l, readPackageJSON as r, writeTypes as w }; diff --git a/.pnpm-store/v3/files/28/3d66f5f41e9e37c8e26dd7d5b7d487a79e2868e80b82aa44328865755329aa9ab2af8433f0e260ecefeb47ef134ff22bbbf72d377648b2789a994c724b2637 b/.pnpm-store/v3/files/28/3d66f5f41e9e37c8e26dd7d5b7d487a79e2868e80b82aa44328865755329aa9ab2af8433f0e260ecefeb47ef134ff22bbbf72d377648b2789a994c724b2637 new file mode 100644 index 0000000000000000000000000000000000000000..395d9548ff44826dec92d6fa5d632baebd170ee4 --- /dev/null +++ b/.pnpm-store/v3/files/28/3d66f5f41e9e37c8e26dd7d5b7d487a79e2868e80b82aa44328865755329aa9ab2af8433f0e260ecefeb47ef134ff22bbbf72d377648b2789a994c724b2637 @@ -0,0 +1,1898 @@ +import { d as defineCommand, c as consola } from '../shared/nuxi.9edf0930.mjs'; +import { s as sharedArgs } from '../shared/nuxi.610c92ff.mjs'; +import 'node:util'; +import 'node:path'; +import 'node:process'; +import 'node:tty'; +import { a as getNuxtVersion, f as fetchModules, c as checkNuxtCompatibility } from '../shared/nuxi.34ba5283.mjs'; +import { u as upperFirst, k as kebabCase } from '../shared/nuxi.349af404.mjs'; +import { b as bold, c as cyan, g as gray, y as yellow, m as magenta, a as green } from '../shared/nuxi.d3241ca4.mjs'; +import 'node:url'; +import 'node:http'; +import 'node:https'; +import 'node:zlib'; +import 'node:stream'; +import 'node:buffer'; +import 'node:net'; +import 'node:fs'; +import '../shared/nuxi.4ac76f59.mjs'; +import '../shared/nuxi.53f5921c.mjs'; +import './satisfies.mjs'; +import '../shared/nuxi.2155838d.mjs'; +import '../shared/nuxi.cc8dd4a9.mjs'; +import '../shared/nuxi.5aaa4630.mjs'; +import 'node:module'; +import 'tty'; + +/** + * Fuse.js v7.0.0 - Lightweight fuzzy-search (http://fusejs.io) + * + * Copyright (c) 2023 Kiro Risk (http://kiro.me) + * All Rights Reserved. Apache Software License 2.0 + * + * http://www.apache.org/licenses/LICENSE-2.0 + */ + +function isArray(value) { + return !Array.isArray + ? getTag(value) === '[object Array]' + : Array.isArray(value) +} + +// Adapted from: https://github.com/lodash/lodash/blob/master/.internal/baseToString.js +const INFINITY = 1 / 0; +function baseToString(value) { + // Exit early for strings to avoid a performance hit in some environments. + if (typeof value == 'string') { + return value + } + let result = value + ''; + return result == '0' && 1 / value == -INFINITY ? '-0' : result +} + +function toString(value) { + return value == null ? '' : baseToString(value) +} + +function isString(value) { + return typeof value === 'string' +} + +function isNumber(value) { + return typeof value === 'number' +} + +// Adapted from: https://github.com/lodash/lodash/blob/master/isBoolean.js +function isBoolean(value) { + return ( + value === true || + value === false || + (isObjectLike(value) && getTag(value) == '[object Boolean]') + ) +} + +function isObject(value) { + return typeof value === 'object' +} + +// Checks if `value` is object-like. +function isObjectLike(value) { + return isObject(value) && value !== null +} + +function isDefined(value) { + return value !== undefined && value !== null +} + +function isBlank(value) { + return !value.trim().length +} + +// Gets the `toStringTag` of `value`. +// Adapted from: https://github.com/lodash/lodash/blob/master/.internal/getTag.js +function getTag(value) { + return value == null + ? value === undefined + ? '[object Undefined]' + : '[object Null]' + : Object.prototype.toString.call(value) +} + +const EXTENDED_SEARCH_UNAVAILABLE = 'Extended search is not available'; + +const INCORRECT_INDEX_TYPE = "Incorrect 'index' type"; + +const LOGICAL_SEARCH_INVALID_QUERY_FOR_KEY = (key) => + `Invalid value for key ${key}`; + +const PATTERN_LENGTH_TOO_LARGE = (max) => + `Pattern length exceeds max of ${max}.`; + +const MISSING_KEY_PROPERTY = (name) => `Missing ${name} property in key`; + +const INVALID_KEY_WEIGHT_VALUE = (key) => + `Property 'weight' in key '${key}' must be a positive integer`; + +const hasOwn = Object.prototype.hasOwnProperty; + +class KeyStore { + constructor(keys) { + this._keys = []; + this._keyMap = {}; + + let totalWeight = 0; + + keys.forEach((key) => { + let obj = createKey(key); + + this._keys.push(obj); + this._keyMap[obj.id] = obj; + + totalWeight += obj.weight; + }); + + // Normalize weights so that their sum is equal to 1 + this._keys.forEach((key) => { + key.weight /= totalWeight; + }); + } + get(keyId) { + return this._keyMap[keyId] + } + keys() { + return this._keys + } + toJSON() { + return JSON.stringify(this._keys) + } +} + +function createKey(key) { + let path = null; + let id = null; + let src = null; + let weight = 1; + let getFn = null; + + if (isString(key) || isArray(key)) { + src = key; + path = createKeyPath(key); + id = createKeyId(key); + } else { + if (!hasOwn.call(key, 'name')) { + throw new Error(MISSING_KEY_PROPERTY('name')) + } + + const name = key.name; + src = name; + + if (hasOwn.call(key, 'weight')) { + weight = key.weight; + + if (weight <= 0) { + throw new Error(INVALID_KEY_WEIGHT_VALUE(name)) + } + } + + path = createKeyPath(name); + id = createKeyId(name); + getFn = key.getFn; + } + + return { path, id, weight, src, getFn } +} + +function createKeyPath(key) { + return isArray(key) ? key : key.split('.') +} + +function createKeyId(key) { + return isArray(key) ? key.join('.') : key +} + +function get(obj, path) { + let list = []; + let arr = false; + + const deepGet = (obj, path, index) => { + if (!isDefined(obj)) { + return + } + if (!path[index]) { + // If there's no path left, we've arrived at the object we care about. + list.push(obj); + } else { + let key = path[index]; + + const value = obj[key]; + + if (!isDefined(value)) { + return + } + + // If we're at the last value in the path, and if it's a string/number/bool, + // add it to the list + if ( + index === path.length - 1 && + (isString(value) || isNumber(value) || isBoolean(value)) + ) { + list.push(toString(value)); + } else if (isArray(value)) { + arr = true; + // Search each item in the array. + for (let i = 0, len = value.length; i < len; i += 1) { + deepGet(value[i], path, index + 1); + } + } else if (path.length) { + // An object. Recurse further. + deepGet(value, path, index + 1); + } + } + }; + + // Backwards compatibility (since path used to be a string) + deepGet(obj, isString(path) ? path.split('.') : path, 0); + + return arr ? list : list[0] +} + +const MatchOptions = { + // Whether the matches should be included in the result set. When `true`, each record in the result + // set will include the indices of the matched characters. + // These can consequently be used for highlighting purposes. + includeMatches: false, + // When `true`, the matching function will continue to the end of a search pattern even if + // a perfect match has already been located in the string. + findAllMatches: false, + // Minimum number of characters that must be matched before a result is considered a match + minMatchCharLength: 1 +}; + +const BasicOptions = { + // When `true`, the algorithm continues searching to the end of the input even if a perfect + // match is found before the end of the same input. + isCaseSensitive: false, + // When true, the matching function will continue to the end of a search pattern even if + includeScore: false, + // List of properties that will be searched. This also supports nested properties. + keys: [], + // Whether to sort the result list, by score + shouldSort: true, + // Default sort function: sort by ascending score, ascending index + sortFn: (a, b) => + a.score === b.score ? (a.idx < b.idx ? -1 : 1) : a.score < b.score ? -1 : 1 +}; + +const FuzzyOptions = { + // Approximately where in the text is the pattern expected to be found? + location: 0, + // At what point does the match algorithm give up. A threshold of '0.0' requires a perfect match + // (of both letters and location), a threshold of '1.0' would match anything. + threshold: 0.6, + // Determines how close the match must be to the fuzzy location (specified above). + // An exact letter match which is 'distance' characters away from the fuzzy location + // would score as a complete mismatch. A distance of '0' requires the match be at + // the exact location specified, a threshold of '1000' would require a perfect match + // to be within 800 characters of the fuzzy location to be found using a 0.8 threshold. + distance: 100 +}; + +const AdvancedOptions = { + // When `true`, it enables the use of unix-like search commands + useExtendedSearch: false, + // The get function to use when fetching an object's properties. + // The default will search nested paths *ie foo.bar.baz* + getFn: get, + // When `true`, search will ignore `location` and `distance`, so it won't matter + // where in the string the pattern appears. + // More info: https://fusejs.io/concepts/scoring-theory.html#fuzziness-score + ignoreLocation: false, + // When `true`, the calculation for the relevance score (used for sorting) will + // ignore the field-length norm. + // More info: https://fusejs.io/concepts/scoring-theory.html#field-length-norm + ignoreFieldNorm: false, + // The weight to determine how much field length norm effects scoring. + fieldNormWeight: 1 +}; + +var Config = { + ...BasicOptions, + ...MatchOptions, + ...FuzzyOptions, + ...AdvancedOptions +}; + +const SPACE = /[^ ]+/g; + +// Field-length norm: the shorter the field, the higher the weight. +// Set to 3 decimals to reduce index size. +function norm(weight = 1, mantissa = 3) { + const cache = new Map(); + const m = Math.pow(10, mantissa); + + return { + get(value) { + const numTokens = value.match(SPACE).length; + + if (cache.has(numTokens)) { + return cache.get(numTokens) + } + + // Default function is 1/sqrt(x), weight makes that variable + const norm = 1 / Math.pow(numTokens, 0.5 * weight); + + // In place of `toFixed(mantissa)`, for faster computation + const n = parseFloat(Math.round(norm * m) / m); + + cache.set(numTokens, n); + + return n + }, + clear() { + cache.clear(); + } + } +} + +class FuseIndex { + constructor({ + getFn = Config.getFn, + fieldNormWeight = Config.fieldNormWeight + } = {}) { + this.norm = norm(fieldNormWeight, 3); + this.getFn = getFn; + this.isCreated = false; + + this.setIndexRecords(); + } + setSources(docs = []) { + this.docs = docs; + } + setIndexRecords(records = []) { + this.records = records; + } + setKeys(keys = []) { + this.keys = keys; + this._keysMap = {}; + keys.forEach((key, idx) => { + this._keysMap[key.id] = idx; + }); + } + create() { + if (this.isCreated || !this.docs.length) { + return + } + + this.isCreated = true; + + // List is Array + if (isString(this.docs[0])) { + this.docs.forEach((doc, docIndex) => { + this._addString(doc, docIndex); + }); + } else { + // List is Array + this.docs.forEach((doc, docIndex) => { + this._addObject(doc, docIndex); + }); + } + + this.norm.clear(); + } + // Adds a doc to the end of the index + add(doc) { + const idx = this.size(); + + if (isString(doc)) { + this._addString(doc, idx); + } else { + this._addObject(doc, idx); + } + } + // Removes the doc at the specified index of the index + removeAt(idx) { + this.records.splice(idx, 1); + + // Change ref index of every subsquent doc + for (let i = idx, len = this.size(); i < len; i += 1) { + this.records[i].i -= 1; + } + } + getValueForItemAtKeyId(item, keyId) { + return item[this._keysMap[keyId]] + } + size() { + return this.records.length + } + _addString(doc, docIndex) { + if (!isDefined(doc) || isBlank(doc)) { + return + } + + let record = { + v: doc, + i: docIndex, + n: this.norm.get(doc) + }; + + this.records.push(record); + } + _addObject(doc, docIndex) { + let record = { i: docIndex, $: {} }; + + // Iterate over every key (i.e, path), and fetch the value at that key + this.keys.forEach((key, keyIndex) => { + let value = key.getFn ? key.getFn(doc) : this.getFn(doc, key.path); + + if (!isDefined(value)) { + return + } + + if (isArray(value)) { + let subRecords = []; + const stack = [{ nestedArrIndex: -1, value }]; + + while (stack.length) { + const { nestedArrIndex, value } = stack.pop(); + + if (!isDefined(value)) { + continue + } + + if (isString(value) && !isBlank(value)) { + let subRecord = { + v: value, + i: nestedArrIndex, + n: this.norm.get(value) + }; + + subRecords.push(subRecord); + } else if (isArray(value)) { + value.forEach((item, k) => { + stack.push({ + nestedArrIndex: k, + value: item + }); + }); + } else ; + } + record.$[keyIndex] = subRecords; + } else if (isString(value) && !isBlank(value)) { + let subRecord = { + v: value, + n: this.norm.get(value) + }; + + record.$[keyIndex] = subRecord; + } + }); + + this.records.push(record); + } + toJSON() { + return { + keys: this.keys, + records: this.records + } + } +} + +function createIndex( + keys, + docs, + { getFn = Config.getFn, fieldNormWeight = Config.fieldNormWeight } = {} +) { + const myIndex = new FuseIndex({ getFn, fieldNormWeight }); + myIndex.setKeys(keys.map(createKey)); + myIndex.setSources(docs); + myIndex.create(); + return myIndex +} + +function parseIndex( + data, + { getFn = Config.getFn, fieldNormWeight = Config.fieldNormWeight } = {} +) { + const { keys, records } = data; + const myIndex = new FuseIndex({ getFn, fieldNormWeight }); + myIndex.setKeys(keys); + myIndex.setIndexRecords(records); + return myIndex +} + +function computeScore$1( + pattern, + { + errors = 0, + currentLocation = 0, + expectedLocation = 0, + distance = Config.distance, + ignoreLocation = Config.ignoreLocation + } = {} +) { + const accuracy = errors / pattern.length; + + if (ignoreLocation) { + return accuracy + } + + const proximity = Math.abs(expectedLocation - currentLocation); + + if (!distance) { + // Dodge divide by zero error. + return proximity ? 1.0 : accuracy + } + + return accuracy + proximity / distance +} + +function convertMaskToIndices( + matchmask = [], + minMatchCharLength = Config.minMatchCharLength +) { + let indices = []; + let start = -1; + let end = -1; + let i = 0; + + for (let len = matchmask.length; i < len; i += 1) { + let match = matchmask[i]; + if (match && start === -1) { + start = i; + } else if (!match && start !== -1) { + end = i - 1; + if (end - start + 1 >= minMatchCharLength) { + indices.push([start, end]); + } + start = -1; + } + } + + // (i-1 - start) + 1 => i - start + if (matchmask[i - 1] && i - start >= minMatchCharLength) { + indices.push([start, i - 1]); + } + + return indices +} + +// Machine word size +const MAX_BITS = 32; + +function search$1( + text, + pattern, + patternAlphabet, + { + location = Config.location, + distance = Config.distance, + threshold = Config.threshold, + findAllMatches = Config.findAllMatches, + minMatchCharLength = Config.minMatchCharLength, + includeMatches = Config.includeMatches, + ignoreLocation = Config.ignoreLocation + } = {} +) { + if (pattern.length > MAX_BITS) { + throw new Error(PATTERN_LENGTH_TOO_LARGE(MAX_BITS)) + } + + const patternLen = pattern.length; + // Set starting location at beginning text and initialize the alphabet. + const textLen = text.length; + // Handle the case when location > text.length + const expectedLocation = Math.max(0, Math.min(location, textLen)); + // Highest score beyond which we give up. + let currentThreshold = threshold; + // Is there a nearby exact match? (speedup) + let bestLocation = expectedLocation; + + // Performance: only computer matches when the minMatchCharLength > 1 + // OR if `includeMatches` is true. + const computeMatches = minMatchCharLength > 1 || includeMatches; + // A mask of the matches, used for building the indices + const matchMask = computeMatches ? Array(textLen) : []; + + let index; + + // Get all exact matches, here for speed up + while ((index = text.indexOf(pattern, bestLocation)) > -1) { + let score = computeScore$1(pattern, { + currentLocation: index, + expectedLocation, + distance, + ignoreLocation + }); + + currentThreshold = Math.min(score, currentThreshold); + bestLocation = index + patternLen; + + if (computeMatches) { + let i = 0; + while (i < patternLen) { + matchMask[index + i] = 1; + i += 1; + } + } + } + + // Reset the best location + bestLocation = -1; + + let lastBitArr = []; + let finalScore = 1; + let binMax = patternLen + textLen; + + const mask = 1 << (patternLen - 1); + + for (let i = 0; i < patternLen; i += 1) { + // Scan for the best match; each iteration allows for one more error. + // Run a binary search to determine how far from the match location we can stray + // at this error level. + let binMin = 0; + let binMid = binMax; + + while (binMin < binMid) { + const score = computeScore$1(pattern, { + errors: i, + currentLocation: expectedLocation + binMid, + expectedLocation, + distance, + ignoreLocation + }); + + if (score <= currentThreshold) { + binMin = binMid; + } else { + binMax = binMid; + } + + binMid = Math.floor((binMax - binMin) / 2 + binMin); + } + + // Use the result from this iteration as the maximum for the next. + binMax = binMid; + + let start = Math.max(1, expectedLocation - binMid + 1); + let finish = findAllMatches + ? textLen + : Math.min(expectedLocation + binMid, textLen) + patternLen; + + // Initialize the bit array + let bitArr = Array(finish + 2); + + bitArr[finish + 1] = (1 << i) - 1; + + for (let j = finish; j >= start; j -= 1) { + let currentLocation = j - 1; + let charMatch = patternAlphabet[text.charAt(currentLocation)]; + + if (computeMatches) { + // Speed up: quick bool to int conversion (i.e, `charMatch ? 1 : 0`) + matchMask[currentLocation] = +!!charMatch; + } + + // First pass: exact match + bitArr[j] = ((bitArr[j + 1] << 1) | 1) & charMatch; + + // Subsequent passes: fuzzy match + if (i) { + bitArr[j] |= + ((lastBitArr[j + 1] | lastBitArr[j]) << 1) | 1 | lastBitArr[j + 1]; + } + + if (bitArr[j] & mask) { + finalScore = computeScore$1(pattern, { + errors: i, + currentLocation, + expectedLocation, + distance, + ignoreLocation + }); + + // This match will almost certainly be better than any existing match. + // But check anyway. + if (finalScore <= currentThreshold) { + // Indeed it is + currentThreshold = finalScore; + bestLocation = currentLocation; + + // Already passed `loc`, downhill from here on in. + if (bestLocation <= expectedLocation) { + break + } + + // When passing `bestLocation`, don't exceed our current distance from `expectedLocation`. + start = Math.max(1, 2 * expectedLocation - bestLocation); + } + } + } + + // No hope for a (better) match at greater error levels. + const score = computeScore$1(pattern, { + errors: i + 1, + currentLocation: expectedLocation, + expectedLocation, + distance, + ignoreLocation + }); + + if (score > currentThreshold) { + break + } + + lastBitArr = bitArr; + } + + const result = { + isMatch: bestLocation >= 0, + // Count exact matches (those with a score of 0) to be "almost" exact + score: Math.max(0.001, finalScore) + }; + + if (computeMatches) { + const indices = convertMaskToIndices(matchMask, minMatchCharLength); + if (!indices.length) { + result.isMatch = false; + } else if (includeMatches) { + result.indices = indices; + } + } + + return result +} + +function createPatternAlphabet(pattern) { + let mask = {}; + + for (let i = 0, len = pattern.length; i < len; i += 1) { + const char = pattern.charAt(i); + mask[char] = (mask[char] || 0) | (1 << (len - i - 1)); + } + + return mask +} + +class BitapSearch { + constructor( + pattern, + { + location = Config.location, + threshold = Config.threshold, + distance = Config.distance, + includeMatches = Config.includeMatches, + findAllMatches = Config.findAllMatches, + minMatchCharLength = Config.minMatchCharLength, + isCaseSensitive = Config.isCaseSensitive, + ignoreLocation = Config.ignoreLocation + } = {} + ) { + this.options = { + location, + threshold, + distance, + includeMatches, + findAllMatches, + minMatchCharLength, + isCaseSensitive, + ignoreLocation + }; + + this.pattern = isCaseSensitive ? pattern : pattern.toLowerCase(); + + this.chunks = []; + + if (!this.pattern.length) { + return + } + + const addChunk = (pattern, startIndex) => { + this.chunks.push({ + pattern, + alphabet: createPatternAlphabet(pattern), + startIndex + }); + }; + + const len = this.pattern.length; + + if (len > MAX_BITS) { + let i = 0; + const remainder = len % MAX_BITS; + const end = len - remainder; + + while (i < end) { + addChunk(this.pattern.substr(i, MAX_BITS), i); + i += MAX_BITS; + } + + if (remainder) { + const startIndex = len - MAX_BITS; + addChunk(this.pattern.substr(startIndex), startIndex); + } + } else { + addChunk(this.pattern, 0); + } + } + + searchIn(text) { + const { isCaseSensitive, includeMatches } = this.options; + + if (!isCaseSensitive) { + text = text.toLowerCase(); + } + + // Exact match + if (this.pattern === text) { + let result = { + isMatch: true, + score: 0 + }; + + if (includeMatches) { + result.indices = [[0, text.length - 1]]; + } + + return result + } + + // Otherwise, use Bitap algorithm + const { + location, + distance, + threshold, + findAllMatches, + minMatchCharLength, + ignoreLocation + } = this.options; + + let allIndices = []; + let totalScore = 0; + let hasMatches = false; + + this.chunks.forEach(({ pattern, alphabet, startIndex }) => { + const { isMatch, score, indices } = search$1(text, pattern, alphabet, { + location: location + startIndex, + distance, + threshold, + findAllMatches, + minMatchCharLength, + includeMatches, + ignoreLocation + }); + + if (isMatch) { + hasMatches = true; + } + + totalScore += score; + + if (isMatch && indices) { + allIndices = [...allIndices, ...indices]; + } + }); + + let result = { + isMatch: hasMatches, + score: hasMatches ? totalScore / this.chunks.length : 1 + }; + + if (hasMatches && includeMatches) { + result.indices = allIndices; + } + + return result + } +} + +class BaseMatch { + constructor(pattern) { + this.pattern = pattern; + } + static isMultiMatch(pattern) { + return getMatch(pattern, this.multiRegex) + } + static isSingleMatch(pattern) { + return getMatch(pattern, this.singleRegex) + } + search(/*text*/) {} +} + +function getMatch(pattern, exp) { + const matches = pattern.match(exp); + return matches ? matches[1] : null +} + +// Token: 'file + +class ExactMatch extends BaseMatch { + constructor(pattern) { + super(pattern); + } + static get type() { + return 'exact' + } + static get multiRegex() { + return /^="(.*)"$/ + } + static get singleRegex() { + return /^=(.*)$/ + } + search(text) { + const isMatch = text === this.pattern; + + return { + isMatch, + score: isMatch ? 0 : 1, + indices: [0, this.pattern.length - 1] + } + } +} + +// Token: !fire + +class InverseExactMatch extends BaseMatch { + constructor(pattern) { + super(pattern); + } + static get type() { + return 'inverse-exact' + } + static get multiRegex() { + return /^!"(.*)"$/ + } + static get singleRegex() { + return /^!(.*)$/ + } + search(text) { + const index = text.indexOf(this.pattern); + const isMatch = index === -1; + + return { + isMatch, + score: isMatch ? 0 : 1, + indices: [0, text.length - 1] + } + } +} + +// Token: ^file + +class PrefixExactMatch extends BaseMatch { + constructor(pattern) { + super(pattern); + } + static get type() { + return 'prefix-exact' + } + static get multiRegex() { + return /^\^"(.*)"$/ + } + static get singleRegex() { + return /^\^(.*)$/ + } + search(text) { + const isMatch = text.startsWith(this.pattern); + + return { + isMatch, + score: isMatch ? 0 : 1, + indices: [0, this.pattern.length - 1] + } + } +} + +// Token: !^fire + +class InversePrefixExactMatch extends BaseMatch { + constructor(pattern) { + super(pattern); + } + static get type() { + return 'inverse-prefix-exact' + } + static get multiRegex() { + return /^!\^"(.*)"$/ + } + static get singleRegex() { + return /^!\^(.*)$/ + } + search(text) { + const isMatch = !text.startsWith(this.pattern); + + return { + isMatch, + score: isMatch ? 0 : 1, + indices: [0, text.length - 1] + } + } +} + +// Token: .file$ + +class SuffixExactMatch extends BaseMatch { + constructor(pattern) { + super(pattern); + } + static get type() { + return 'suffix-exact' + } + static get multiRegex() { + return /^"(.*)"\$$/ + } + static get singleRegex() { + return /^(.*)\$$/ + } + search(text) { + const isMatch = text.endsWith(this.pattern); + + return { + isMatch, + score: isMatch ? 0 : 1, + indices: [text.length - this.pattern.length, text.length - 1] + } + } +} + +// Token: !.file$ + +class InverseSuffixExactMatch extends BaseMatch { + constructor(pattern) { + super(pattern); + } + static get type() { + return 'inverse-suffix-exact' + } + static get multiRegex() { + return /^!"(.*)"\$$/ + } + static get singleRegex() { + return /^!(.*)\$$/ + } + search(text) { + const isMatch = !text.endsWith(this.pattern); + return { + isMatch, + score: isMatch ? 0 : 1, + indices: [0, text.length - 1] + } + } +} + +class FuzzyMatch extends BaseMatch { + constructor( + pattern, + { + location = Config.location, + threshold = Config.threshold, + distance = Config.distance, + includeMatches = Config.includeMatches, + findAllMatches = Config.findAllMatches, + minMatchCharLength = Config.minMatchCharLength, + isCaseSensitive = Config.isCaseSensitive, + ignoreLocation = Config.ignoreLocation + } = {} + ) { + super(pattern); + this._bitapSearch = new BitapSearch(pattern, { + location, + threshold, + distance, + includeMatches, + findAllMatches, + minMatchCharLength, + isCaseSensitive, + ignoreLocation + }); + } + static get type() { + return 'fuzzy' + } + static get multiRegex() { + return /^"(.*)"$/ + } + static get singleRegex() { + return /^(.*)$/ + } + search(text) { + return this._bitapSearch.searchIn(text) + } +} + +// Token: 'file + +class IncludeMatch extends BaseMatch { + constructor(pattern) { + super(pattern); + } + static get type() { + return 'include' + } + static get multiRegex() { + return /^'"(.*)"$/ + } + static get singleRegex() { + return /^'(.*)$/ + } + search(text) { + let location = 0; + let index; + + const indices = []; + const patternLen = this.pattern.length; + + // Get all exact matches + while ((index = text.indexOf(this.pattern, location)) > -1) { + location = index + patternLen; + indices.push([index, location - 1]); + } + + const isMatch = !!indices.length; + + return { + isMatch, + score: isMatch ? 0 : 1, + indices + } + } +} + +// ❗Order is important. DO NOT CHANGE. +const searchers = [ + ExactMatch, + IncludeMatch, + PrefixExactMatch, + InversePrefixExactMatch, + InverseSuffixExactMatch, + SuffixExactMatch, + InverseExactMatch, + FuzzyMatch +]; + +const searchersLen = searchers.length; + +// Regex to split by spaces, but keep anything in quotes together +const SPACE_RE = / +(?=(?:[^\"]*\"[^\"]*\")*[^\"]*$)/; +const OR_TOKEN = '|'; + +// Return a 2D array representation of the query, for simpler parsing. +// Example: +// "^core go$ | rb$ | py$ xy$" => [["^core", "go$"], ["rb$"], ["py$", "xy$"]] +function parseQuery(pattern, options = {}) { + return pattern.split(OR_TOKEN).map((item) => { + let query = item + .trim() + .split(SPACE_RE) + .filter((item) => item && !!item.trim()); + + let results = []; + for (let i = 0, len = query.length; i < len; i += 1) { + const queryItem = query[i]; + + // 1. Handle multiple query match (i.e, once that are quoted, like `"hello world"`) + let found = false; + let idx = -1; + while (!found && ++idx < searchersLen) { + const searcher = searchers[idx]; + let token = searcher.isMultiMatch(queryItem); + if (token) { + results.push(new searcher(token, options)); + found = true; + } + } + + if (found) { + continue + } + + // 2. Handle single query matches (i.e, once that are *not* quoted) + idx = -1; + while (++idx < searchersLen) { + const searcher = searchers[idx]; + let token = searcher.isSingleMatch(queryItem); + if (token) { + results.push(new searcher(token, options)); + break + } + } + } + + return results + }) +} + +// These extended matchers can return an array of matches, as opposed +// to a singl match +const MultiMatchSet = new Set([FuzzyMatch.type, IncludeMatch.type]); + +/** + * Command-like searching + * ====================== + * + * Given multiple search terms delimited by spaces.e.g. `^jscript .python$ ruby !java`, + * search in a given text. + * + * Search syntax: + * + * | Token | Match type | Description | + * | ----------- | -------------------------- | -------------------------------------- | + * | `jscript` | fuzzy-match | Items that fuzzy match `jscript` | + * | `=scheme` | exact-match | Items that are `scheme` | + * | `'python` | include-match | Items that include `python` | + * | `!ruby` | inverse-exact-match | Items that do not include `ruby` | + * | `^java` | prefix-exact-match | Items that start with `java` | + * | `!^earlang` | inverse-prefix-exact-match | Items that do not start with `earlang` | + * | `.js$` | suffix-exact-match | Items that end with `.js` | + * | `!.go$` | inverse-suffix-exact-match | Items that do not end with `.go` | + * + * A single pipe character acts as an OR operator. For example, the following + * query matches entries that start with `core` and end with either`go`, `rb`, + * or`py`. + * + * ``` + * ^core go$ | rb$ | py$ + * ``` + */ +class ExtendedSearch { + constructor( + pattern, + { + isCaseSensitive = Config.isCaseSensitive, + includeMatches = Config.includeMatches, + minMatchCharLength = Config.minMatchCharLength, + ignoreLocation = Config.ignoreLocation, + findAllMatches = Config.findAllMatches, + location = Config.location, + threshold = Config.threshold, + distance = Config.distance + } = {} + ) { + this.query = null; + this.options = { + isCaseSensitive, + includeMatches, + minMatchCharLength, + findAllMatches, + ignoreLocation, + location, + threshold, + distance + }; + + this.pattern = isCaseSensitive ? pattern : pattern.toLowerCase(); + this.query = parseQuery(this.pattern, this.options); + } + + static condition(_, options) { + return options.useExtendedSearch + } + + searchIn(text) { + const query = this.query; + + if (!query) { + return { + isMatch: false, + score: 1 + } + } + + const { includeMatches, isCaseSensitive } = this.options; + + text = isCaseSensitive ? text : text.toLowerCase(); + + let numMatches = 0; + let allIndices = []; + let totalScore = 0; + + // ORs + for (let i = 0, qLen = query.length; i < qLen; i += 1) { + const searchers = query[i]; + + // Reset indices + allIndices.length = 0; + numMatches = 0; + + // ANDs + for (let j = 0, pLen = searchers.length; j < pLen; j += 1) { + const searcher = searchers[j]; + const { isMatch, indices, score } = searcher.search(text); + + if (isMatch) { + numMatches += 1; + totalScore += score; + if (includeMatches) { + const type = searcher.constructor.type; + if (MultiMatchSet.has(type)) { + allIndices = [...allIndices, ...indices]; + } else { + allIndices.push(indices); + } + } + } else { + totalScore = 0; + numMatches = 0; + allIndices.length = 0; + break + } + } + + // OR condition, so if TRUE, return + if (numMatches) { + let result = { + isMatch: true, + score: totalScore / numMatches + }; + + if (includeMatches) { + result.indices = allIndices; + } + + return result + } + } + + // Nothing was matched + return { + isMatch: false, + score: 1 + } + } +} + +const registeredSearchers = []; + +function register(...args) { + registeredSearchers.push(...args); +} + +function createSearcher(pattern, options) { + for (let i = 0, len = registeredSearchers.length; i < len; i += 1) { + let searcherClass = registeredSearchers[i]; + if (searcherClass.condition(pattern, options)) { + return new searcherClass(pattern, options) + } + } + + return new BitapSearch(pattern, options) +} + +const LogicalOperator = { + AND: '$and', + OR: '$or' +}; + +const KeyType = { + PATH: '$path', + PATTERN: '$val' +}; + +const isExpression = (query) => + !!(query[LogicalOperator.AND] || query[LogicalOperator.OR]); + +const isPath = (query) => !!query[KeyType.PATH]; + +const isLeaf = (query) => + !isArray(query) && isObject(query) && !isExpression(query); + +const convertToExplicit = (query) => ({ + [LogicalOperator.AND]: Object.keys(query).map((key) => ({ + [key]: query[key] + })) +}); + +// When `auto` is `true`, the parse function will infer and initialize and add +// the appropriate `Searcher` instance +function parse(query, options, { auto = true } = {}) { + const next = (query) => { + let keys = Object.keys(query); + + const isQueryPath = isPath(query); + + if (!isQueryPath && keys.length > 1 && !isExpression(query)) { + return next(convertToExplicit(query)) + } + + if (isLeaf(query)) { + const key = isQueryPath ? query[KeyType.PATH] : keys[0]; + + const pattern = isQueryPath ? query[KeyType.PATTERN] : query[key]; + + if (!isString(pattern)) { + throw new Error(LOGICAL_SEARCH_INVALID_QUERY_FOR_KEY(key)) + } + + const obj = { + keyId: createKeyId(key), + pattern + }; + + if (auto) { + obj.searcher = createSearcher(pattern, options); + } + + return obj + } + + let node = { + children: [], + operator: keys[0] + }; + + keys.forEach((key) => { + const value = query[key]; + + if (isArray(value)) { + value.forEach((item) => { + node.children.push(next(item)); + }); + } + }); + + return node + }; + + if (!isExpression(query)) { + query = convertToExplicit(query); + } + + return next(query) +} + +// Practical scoring function +function computeScore( + results, + { ignoreFieldNorm = Config.ignoreFieldNorm } +) { + results.forEach((result) => { + let totalScore = 1; + + result.matches.forEach(({ key, norm, score }) => { + const weight = key ? key.weight : null; + + totalScore *= Math.pow( + score === 0 && weight ? Number.EPSILON : score, + (weight || 1) * (ignoreFieldNorm ? 1 : norm) + ); + }); + + result.score = totalScore; + }); +} + +function transformMatches(result, data) { + const matches = result.matches; + data.matches = []; + + if (!isDefined(matches)) { + return + } + + matches.forEach((match) => { + if (!isDefined(match.indices) || !match.indices.length) { + return + } + + const { indices, value } = match; + + let obj = { + indices, + value + }; + + if (match.key) { + obj.key = match.key.src; + } + + if (match.idx > -1) { + obj.refIndex = match.idx; + } + + data.matches.push(obj); + }); +} + +function transformScore(result, data) { + data.score = result.score; +} + +function format( + results, + docs, + { + includeMatches = Config.includeMatches, + includeScore = Config.includeScore + } = {} +) { + const transformers = []; + + if (includeMatches) transformers.push(transformMatches); + if (includeScore) transformers.push(transformScore); + + return results.map((result) => { + const { idx } = result; + + const data = { + item: docs[idx], + refIndex: idx + }; + + if (transformers.length) { + transformers.forEach((transformer) => { + transformer(result, data); + }); + } + + return data + }) +} + +class Fuse { + constructor(docs, options = {}, index) { + this.options = { ...Config, ...options }; + + if ( + this.options.useExtendedSearch && + !true + ) { + throw new Error(EXTENDED_SEARCH_UNAVAILABLE) + } + + this._keyStore = new KeyStore(this.options.keys); + + this.setCollection(docs, index); + } + + setCollection(docs, index) { + this._docs = docs; + + if (index && !(index instanceof FuseIndex)) { + throw new Error(INCORRECT_INDEX_TYPE) + } + + this._myIndex = + index || + createIndex(this.options.keys, this._docs, { + getFn: this.options.getFn, + fieldNormWeight: this.options.fieldNormWeight + }); + } + + add(doc) { + if (!isDefined(doc)) { + return + } + + this._docs.push(doc); + this._myIndex.add(doc); + } + + remove(predicate = (/* doc, idx */) => false) { + const results = []; + + for (let i = 0, len = this._docs.length; i < len; i += 1) { + const doc = this._docs[i]; + if (predicate(doc, i)) { + this.removeAt(i); + i -= 1; + len -= 1; + + results.push(doc); + } + } + + return results + } + + removeAt(idx) { + this._docs.splice(idx, 1); + this._myIndex.removeAt(idx); + } + + getIndex() { + return this._myIndex + } + + search(query, { limit = -1 } = {}) { + const { + includeMatches, + includeScore, + shouldSort, + sortFn, + ignoreFieldNorm + } = this.options; + + let results = isString(query) + ? isString(this._docs[0]) + ? this._searchStringList(query) + : this._searchObjectList(query) + : this._searchLogical(query); + + computeScore(results, { ignoreFieldNorm }); + + if (shouldSort) { + results.sort(sortFn); + } + + if (isNumber(limit) && limit > -1) { + results = results.slice(0, limit); + } + + return format(results, this._docs, { + includeMatches, + includeScore + }) + } + + _searchStringList(query) { + const searcher = createSearcher(query, this.options); + const { records } = this._myIndex; + const results = []; + + // Iterate over every string in the index + records.forEach(({ v: text, i: idx, n: norm }) => { + if (!isDefined(text)) { + return + } + + const { isMatch, score, indices } = searcher.searchIn(text); + + if (isMatch) { + results.push({ + item: text, + idx, + matches: [{ score, value: text, norm, indices }] + }); + } + }); + + return results + } + + _searchLogical(query) { + + const expression = parse(query, this.options); + + const evaluate = (node, item, idx) => { + if (!node.children) { + const { keyId, searcher } = node; + + const matches = this._findMatches({ + key: this._keyStore.get(keyId), + value: this._myIndex.getValueForItemAtKeyId(item, keyId), + searcher + }); + + if (matches && matches.length) { + return [ + { + idx, + item, + matches + } + ] + } + + return [] + } + + const res = []; + for (let i = 0, len = node.children.length; i < len; i += 1) { + const child = node.children[i]; + const result = evaluate(child, item, idx); + if (result.length) { + res.push(...result); + } else if (node.operator === LogicalOperator.AND) { + return [] + } + } + return res + }; + + const records = this._myIndex.records; + const resultMap = {}; + const results = []; + + records.forEach(({ $: item, i: idx }) => { + if (isDefined(item)) { + let expResults = evaluate(expression, item, idx); + + if (expResults.length) { + // Dedupe when adding + if (!resultMap[idx]) { + resultMap[idx] = { idx, item, matches: [] }; + results.push(resultMap[idx]); + } + expResults.forEach(({ matches }) => { + resultMap[idx].matches.push(...matches); + }); + } + } + }); + + return results + } + + _searchObjectList(query) { + const searcher = createSearcher(query, this.options); + const { keys, records } = this._myIndex; + const results = []; + + // List is Array + records.forEach(({ $: item, i: idx }) => { + if (!isDefined(item)) { + return + } + + let matches = []; + + // Iterate over every key (i.e, path), and fetch the value at that key + keys.forEach((key, keyIndex) => { + matches.push( + ...this._findMatches({ + key, + value: item[keyIndex], + searcher + }) + ); + }); + + if (matches.length) { + results.push({ + idx, + item, + matches + }); + } + }); + + return results + } + _findMatches({ key, value, searcher }) { + if (!isDefined(value)) { + return [] + } + + let matches = []; + + if (isArray(value)) { + value.forEach(({ v: text, i: idx, n: norm }) => { + if (!isDefined(text)) { + return + } + + const { isMatch, score, indices } = searcher.searchIn(text); + + if (isMatch) { + matches.push({ + score, + key, + value: text, + idx, + norm, + indices + }); + } + }); + } else { + const { v: text, n: norm } = value; + + const { isMatch, score, indices } = searcher.searchIn(text); + + if (isMatch) { + matches.push({ score, key, value: text, norm, indices }); + } + } + + return matches + } +} + +Fuse.version = '7.0.0'; +Fuse.createIndex = createIndex; +Fuse.parseIndex = parseIndex; +Fuse.config = Config; + +{ + Fuse.parseQuery = parse; +} + +{ + register(ExtendedSearch); +} + +const { format: formatNumber } = Intl.NumberFormat("en-GB", { + notation: "compact", + maximumFractionDigits: 1 +}); +const search = defineCommand({ + meta: { + name: "search", + description: "Search in Nuxt modules" + }, + args: { + ...sharedArgs, + query: { + type: "positional", + description: "keywords to search for", + required: true + }, + nuxtVersion: { + type: "string", + description: "Filter by Nuxt version and list compatible moduless only (auto detected by default)", + required: false + } + }, + async setup(ctx) { + const nuxtVersion = await getNuxtVersion(ctx.args.cwd || "."); + return findModuleByKeywords(ctx.args._.join(" "), nuxtVersion); + } +}); +async function findModuleByKeywords(query, nuxtVersion) { + const allModules = await fetchModules(); + const compatibleModules = allModules.filter( + (m) => checkNuxtCompatibility(m, nuxtVersion) + ); + const fuse = new Fuse(compatibleModules, { + threshold: 0.1, + keys: [ + { name: "name", weight: 1 }, + { name: "npm", weight: 1 }, + { name: "repo", weight: 1 }, + { name: "tags", weight: 1 }, + { name: "category", weight: 1 }, + { name: "description", weight: 0.5 }, + { name: "maintainers.name", weight: 0.5 }, + { name: "maintainers.github", weight: 0.5 } + ] + }); + const results = fuse.search(query).map((result) => { + const res = { + name: bold(result.item.name), + homepage: cyan(result.item.website), + compatibility: `nuxt: ${result.item.compatibility?.nuxt || "*"}`, + repository: gray(result.item.github), + description: gray(result.item.description), + package: gray(result.item.npm), + install: cyan(`npx nuxi module add ${result.item.name}`), + stars: yellow(formatNumber(result.item.stats.stars)), + monthlyDownloads: yellow(formatNumber(result.item.stats.downloads)) + }; + if (result.item.github === result.item.website) { + delete res.homepage; + } + if (result.item.name === result.item.npm) { + delete res.packageName; + } + return res; + }); + if (!results.length) { + consola.info( + `No Nuxt modules found matching query ${magenta(query)} for Nuxt ${cyan( + nuxtVersion + )}` + ); + return; + } + consola.success( + `Found ${results.length} Nuxt ${results.length > 1 ? "modules" : "module"} matching ${cyan(query)} ${nuxtVersion ? `for Nuxt ${cyan(nuxtVersion)}` : ""}: +` + ); + for (const foundModule of results) { + let maxLength = 0; + const entries = Object.entries(foundModule).map(([key, val]) => { + const label = upperFirst(kebabCase(key)).replace(/-/g, " "); + if (label.length > maxLength) { + maxLength = label.length; + } + return [label, val || "-"]; + }); + let infoStr = ""; + for (const [label, value] of entries) { + infoStr += bold(label === "Install" ? "\u2192 " : "- ") + green(label.padEnd(maxLength + 2)) + value + "\n"; + } + console.log(infoStr); + } +} + +export { search as default }; diff --git a/.pnpm-store/v3/files/2c/3697f9a13dc95e5357bc8f24b900d855f1d46a02911bed788a02550a85881cca04c3e03a9520f60bf7c7897e950088f77a3245908f4c0a38e808a620ec5075 b/.pnpm-store/v3/files/2c/3697f9a13dc95e5357bc8f24b900d855f1d46a02911bed788a02550a85881cca04c3e03a9520f60bf7c7897e950088f77a3245908f4c0a38e808a620ec5075 new file mode 100644 index 0000000000000000000000000000000000000000..aed4af230c0200849ec8cb84e1e56cb0ae4665d6 --- /dev/null +++ b/.pnpm-store/v3/files/2c/3697f9a13dc95e5357bc8f24b900d855f1d46a02911bed788a02550a85881cca04c3e03a9520f60bf7c7897e950088f77a3245908f4c0a38e808a620ec5075 @@ -0,0 +1,51 @@ +import { existsSync } from 'node:fs'; +import { c as consola } from '../shared/nuxi.9edf0930.mjs'; +import 'node:util'; +import 'node:path'; +import 'node:process'; +import 'node:tty'; +import 'node:url'; + +async function startTunnel(opts) { + const { + installCloudflared, + startCloudflaredTunnel, + cloudflaredBinPath, + cloudflaredNotice + } = await import('./index7.mjs'); + const url = opts.url || `${opts.protocol || "http"}://${opts.hostname ?? "localhost"}:${opts.port ?? 3e3}`; + consola.start(`Starting cloudflared tunnel to ${url}`); + if (!existsSync(cloudflaredBinPath)) { + consola.log(cloudflaredNotice); + const canInstall = opts.acceptCloudflareNotice || process.env.UNTUN_ACCEPT_CLOUDFLARE_NOTICE || await consola.prompt( + `Do you agree with the above terms and wish to install the binary from GitHub?`, + { + type: "confirm" + } + ); + if (!canInstall) { + consola.fail("Skipping tunnel setup."); + return; + } + await installCloudflared(); + } + const args = [ + ["--url", url], + opts.verifyTLS ? void 0 : ["--no-tls-verify", ""] + ].filter(Boolean); + const tunnel = await startCloudflaredTunnel(Object.fromEntries(args)); + const cleanup = async () => { + await tunnel.stop(); + }; + for (const signal of ["SIGINT", "SIGUSR1", "SIGUSR2"]) { + process.once(signal, cleanup); + } + return { + getURL: async () => await tunnel.url, + close: async () => { + await cleanup(); + } + }; +} + +export { startTunnel }; diff --git a/.pnpm-store/v3/files/2d/ce6a69ca62e1588c5b9f8a4e14d8b64c1ef4fc2566b5a43dae6f5b743228b91f7697bb28254dafdcaf3141d8537e17505344b59db9f63db472dc3c089e15e7 b/.pnpm-store/v3/files/2d/ce6a69ca62e1588c5b9f8a4e14d8b64c1ef4fc2566b5a43dae6f5b743228b91f7697bb28254dafdcaf3141d8537e17505344b59db9f63db472dc3c089e15e7 new file mode 100644 index 0000000000000000000000000000000000000000..248cd393ef72f0df47b76832d7fca8b649b0a090 --- /dev/null +++ b/.pnpm-store/v3/files/2d/ce6a69ca62e1588c5b9f8a4e14d8b64c1ef4fc2566b5a43dae6f5b743228b91f7697bb28254dafdcaf3141d8537e17505344b59db9f63db472dc3c089e15e7 @@ -0,0 +1,1202 @@ +import Et from 'node:http'; +import https from 'node:https'; +import st from 'node:zlib'; +import me, { PassThrough, pipeline } from 'node:stream'; +import { Buffer as Buffer$1 } from 'node:buffer'; +import { promisify, deprecate, types } from 'node:util'; +import { format } from 'node:url'; +import { isIP } from 'node:net'; +import { statSync, promises, createReadStream } from 'node:fs'; +import { basename } from 'node:path'; +import { d as destr } from './nuxi.4ac76f59.mjs'; +import { b as withBase, c as withQuery } from './nuxi.53f5921c.mjs'; +import { a as semver$1, c as compare_1, r as reExports, b as requireRange, g as gt_1, d as requireComparator, e as satisfies_1, l as lt_1, f as lte_1, h as gte_1, i as constants$1, j as identifiers$1, k as eq_1, n as neq_1, m as cmp_1 } from '../chunks/satisfies.mjs'; +import { t as tryRequireModule } from './nuxi.5aaa4630.mjs'; + +var t$2=Object.defineProperty;var o$1=(e,l)=>t$2(e,"name",{value:l,configurable:!0});var n$1=typeof globalThis<"u"?globalThis:typeof window<"u"?window:typeof global<"u"?global:typeof self<"u"?self:{};function f$1(e){return e&&e.__esModule&&Object.prototype.hasOwnProperty.call(e,"default")?e.default:e}o$1(f$1,"getDefaultExportFromCjs"); + +var Ps=Object.defineProperty;var n=(i,o)=>Ps(i,"name",{value:o,configurable:!0});var ui=(i,o,a)=>{if(!o.has(i))throw TypeError("Cannot "+a)};var O=(i,o,a)=>(ui(i,o,"read from private field"),a?a.call(i):o.get(i)),be=(i,o,a)=>{if(o.has(i))throw TypeError("Cannot add the same private member more than once");o instanceof WeakSet?o.add(i):o.set(i,a);},X=(i,o,a,u)=>(ui(i,o,"write to private field"),u?u.call(i,a):o.set(i,a),a);var Pe,Wt,bt,Cr,Ve,qt,Ot,zt,ee,It,Ne,He,Ft;function zs(i){if(!/^data:/i.test(i))throw new TypeError('`uri` does not appear to be a Data URI (must begin with "data:")');i=i.replace(/\r?\n/g,"");const o=i.indexOf(",");if(o===-1||o<=4)throw new TypeError("malformed data: URI");const a=i.substring(5,o).split(";");let u="",f=!1;const d=a[0]||"text/plain";let b=d;for(let D=1;D`Symbol(${e})`;function f(){}n(f,"noop");function d(e){return typeof e=="object"&&e!==null||typeof e=="function"}n(d,"typeIsObject");const b=f;function p(e,t){try{Object.defineProperty(e,"name",{value:t,configurable:!0});}catch{}}n(p,"setFunctionName");const E=Promise,w=Promise.prototype.then,D=Promise.reject.bind(E);function A(e){return new E(e)}n(A,"newPromise");function S(e){return A(t=>t(e))}n(S,"promiseResolvedWith");function m(e){return D(e)}n(m,"promiseRejectedWith");function R(e,t,r){return w.call(e,t,r)}n(R,"PerformPromiseThen");function q(e,t,r){R(R(e,t,r),void 0,b);}n(q,"uponPromise");function F(e,t){q(e,t);}n(F,"uponFulfillment");function Q(e,t){q(e,void 0,t);}n(Q,"uponRejection");function M(e,t,r){return R(e,t,r)}n(M,"transformPromiseWith");function ve(e){R(e,void 0,b);}n(ve,"setPromiseIsHandledToTrue");let z=n(e=>{if(typeof queueMicrotask=="function")z=queueMicrotask;else {const t=S(void 0);z=n(r=>R(t,r),"_queueMicrotask");}return z(e)},"_queueMicrotask");function j(e,t,r){if(typeof e!="function")throw new TypeError("Argument is not a function");return Function.prototype.apply.call(e,t,r)}n(j,"reflectCall");function I(e,t,r){try{return S(j(e,t,r))}catch(s){return m(s)}}n(I,"promiseCall");const mt=16384,cn=class cn{constructor(){this._cursor=0,this._size=0,this._front={_elements:[],_next:void 0},this._back=this._front,this._cursor=0,this._size=0;}get length(){return this._size}push(t){const r=this._back;let s=r;r._elements.length===mt-1&&(s={_elements:[],_next:void 0}),r._elements.push(t),s!==r&&(this._back=s,r._next=s),++this._size;}shift(){const t=this._front;let r=t;const s=this._cursor;let l=s+1;const c=t._elements,h=c[s];return l===mt&&(r=t._next,l=0),--this._size,this._cursor=l,t!==r&&(this._front=r),c[s]=void 0,h}forEach(t){let r=this._cursor,s=this._front,l=s._elements;for(;(r!==l.length||s._next!==void 0)&&!(r===l.length&&(s=s._next,l=s._elements,r=0,l.length===0));)t(l[r]),++r;}peek(){const t=this._front,r=this._cursor;return t._elements[r]}};n(cn,"SimpleQueue");let U=cn;const xn=u("[[AbortSteps]]"),Nn=u("[[ErrorSteps]]"),Ar=u("[[CancelSteps]]"),Br=u("[[PullSteps]]"),kr=u("[[ReleaseSteps]]");function Hn(e,t){e._ownerReadableStream=t,t._reader=e,t._state==="readable"?qr(e):t._state==="closed"?Fi(e):Vn(e,t._storedError);}n(Hn,"ReadableStreamReaderGenericInitialize");function Wr(e,t){const r=e._ownerReadableStream;return ie(r,t)}n(Wr,"ReadableStreamReaderGenericCancel");function ge(e){const t=e._ownerReadableStream;t._state==="readable"?Or(e,new TypeError("Reader was released and can no longer be used to monitor the stream's closedness")):ji(e,new TypeError("Reader was released and can no longer be used to monitor the stream's closedness")),t._readableStreamController[kr](),t._reader=void 0,e._ownerReadableStream=void 0;}n(ge,"ReadableStreamReaderGenericRelease");function jt(e){return new TypeError("Cannot "+e+" a stream using a released reader")}n(jt,"readerLockException");function qr(e){e._closedPromise=A((t,r)=>{e._closedPromise_resolve=t,e._closedPromise_reject=r;});}n(qr,"defaultReaderClosedPromiseInitialize");function Vn(e,t){qr(e),Or(e,t);}n(Vn,"defaultReaderClosedPromiseInitializeAsRejected");function Fi(e){qr(e),Qn(e);}n(Fi,"defaultReaderClosedPromiseInitializeAsResolved");function Or(e,t){e._closedPromise_reject!==void 0&&(ve(e._closedPromise),e._closedPromise_reject(t),e._closedPromise_resolve=void 0,e._closedPromise_reject=void 0);}n(Or,"defaultReaderClosedPromiseReject");function ji(e,t){Vn(e,t);}n(ji,"defaultReaderClosedPromiseResetToRejected");function Qn(e){e._closedPromise_resolve!==void 0&&(e._closedPromise_resolve(void 0),e._closedPromise_resolve=void 0,e._closedPromise_reject=void 0);}n(Qn,"defaultReaderClosedPromiseResolve");const Yn=Number.isFinite||function(e){return typeof e=="number"&&isFinite(e)},Li=Math.trunc||function(e){return e<0?Math.ceil(e):Math.floor(e)};function $i(e){return typeof e=="object"||typeof e=="function"}n($i,"isDictionary");function le(e,t){if(e!==void 0&&!$i(e))throw new TypeError(`${t} is not an object.`)}n(le,"assertDictionary");function Z(e,t){if(typeof e!="function")throw new TypeError(`${t} is not a function.`)}n(Z,"assertFunction");function Di(e){return typeof e=="object"&&e!==null||typeof e=="function"}n(Di,"isObject");function Gn(e,t){if(!Di(e))throw new TypeError(`${t} is not an object.`)}n(Gn,"assertObject");function _e(e,t,r){if(e===void 0)throw new TypeError(`Parameter ${t} is required in '${r}'.`)}n(_e,"assertRequiredArgument");function zr(e,t,r){if(e===void 0)throw new TypeError(`${t} is required in '${r}'.`)}n(zr,"assertRequiredField");function Ir(e){return Number(e)}n(Ir,"convertUnrestrictedDouble");function Zn(e){return e===0?0:e}n(Zn,"censorNegativeZero");function Mi(e){return Zn(Li(e))}n(Mi,"integerPart");function Fr(e,t){const s=Number.MAX_SAFE_INTEGER;let l=Number(e);if(l=Zn(l),!Yn(l))throw new TypeError(`${t} is not a finite number`);if(l=Mi(l),l<0||l>s)throw new TypeError(`${t} is outside the accepted range of 0 to ${s}, inclusive`);return !Yn(l)||l===0?0:l}n(Fr,"convertUnsignedLongLongWithEnforceRange");function jr(e,t){if(!We(e))throw new TypeError(`${t} is not a ReadableStream.`)}n(jr,"assertReadableStream");function Qe(e){return new fe(e)}n(Qe,"AcquireReadableStreamDefaultReader");function Kn(e,t){e._reader._readRequests.push(t);}n(Kn,"ReadableStreamAddReadRequest");function Lr(e,t,r){const l=e._reader._readRequests.shift();r?l._closeSteps():l._chunkSteps(t);}n(Lr,"ReadableStreamFulfillReadRequest");function Lt(e){return e._reader._readRequests.length}n(Lt,"ReadableStreamGetNumReadRequests");function Jn(e){const t=e._reader;return !(t===void 0||!Ee(t))}n(Jn,"ReadableStreamHasDefaultReader");const dn=class dn{constructor(t){if(_e(t,1,"ReadableStreamDefaultReader"),jr(t,"First parameter"),qe(t))throw new TypeError("This stream has already been locked for exclusive reading by another reader");Hn(this,t),this._readRequests=new U;}get closed(){return Ee(this)?this._closedPromise:m($t("closed"))}cancel(t=void 0){return Ee(this)?this._ownerReadableStream===void 0?m(jt("cancel")):Wr(this,t):m($t("cancel"))}read(){if(!Ee(this))return m($t("read"));if(this._ownerReadableStream===void 0)return m(jt("read from"));let t,r;const s=A((c,h)=>{t=c,r=h;});return yt(this,{_chunkSteps:c=>t({value:c,done:!1}),_closeSteps:()=>t({value:void 0,done:!0}),_errorSteps:c=>r(c)}),s}releaseLock(){if(!Ee(this))throw $t("releaseLock");this._ownerReadableStream!==void 0&&Ui(this);}};n(dn,"ReadableStreamDefaultReader");let fe=dn;Object.defineProperties(fe.prototype,{cancel:{enumerable:!0},read:{enumerable:!0},releaseLock:{enumerable:!0},closed:{enumerable:!0}}),p(fe.prototype.cancel,"cancel"),p(fe.prototype.read,"read"),p(fe.prototype.releaseLock,"releaseLock"),typeof u.toStringTag=="symbol"&&Object.defineProperty(fe.prototype,u.toStringTag,{value:"ReadableStreamDefaultReader",configurable:!0});function Ee(e){return !d(e)||!Object.prototype.hasOwnProperty.call(e,"_readRequests")?!1:e instanceof fe}n(Ee,"IsReadableStreamDefaultReader");function yt(e,t){const r=e._ownerReadableStream;r._disturbed=!0,r._state==="closed"?t._closeSteps():r._state==="errored"?t._errorSteps(r._storedError):r._readableStreamController[Br](t);}n(yt,"ReadableStreamDefaultReaderRead");function Ui(e){ge(e);const t=new TypeError("Reader was released");Xn(e,t);}n(Ui,"ReadableStreamDefaultReaderRelease");function Xn(e,t){const r=e._readRequests;e._readRequests=new U,r.forEach(s=>{s._errorSteps(t);});}n(Xn,"ReadableStreamDefaultReaderErrorReadRequests");function $t(e){return new TypeError(`ReadableStreamDefaultReader.prototype.${e} can only be used on a ReadableStreamDefaultReader`)}n($t,"defaultReaderBrandCheckException");const eo=Object.getPrototypeOf(Object.getPrototypeOf(async function*(){}).prototype),hn=class hn{constructor(t,r){this._ongoingPromise=void 0,this._isFinished=!1,this._reader=t,this._preventCancel=r;}next(){const t=n(()=>this._nextSteps(),"nextSteps");return this._ongoingPromise=this._ongoingPromise?M(this._ongoingPromise,t,t):t(),this._ongoingPromise}return(t){const r=n(()=>this._returnSteps(t),"returnSteps");return this._ongoingPromise?M(this._ongoingPromise,r,r):r()}_nextSteps(){if(this._isFinished)return Promise.resolve({value:void 0,done:!0});const t=this._reader;let r,s;const l=A((h,y)=>{r=h,s=y;});return yt(t,{_chunkSteps:h=>{this._ongoingPromise=void 0,z(()=>r({value:h,done:!1}));},_closeSteps:()=>{this._ongoingPromise=void 0,this._isFinished=!0,ge(t),r({value:void 0,done:!0});},_errorSteps:h=>{this._ongoingPromise=void 0,this._isFinished=!0,ge(t),s(h);}}),l}_returnSteps(t){if(this._isFinished)return Promise.resolve({value:t,done:!0});this._isFinished=!0;const r=this._reader;if(!this._preventCancel){const s=Wr(r,t);return ge(r),M(s,()=>({value:t,done:!0}))}return ge(r),S({value:t,done:!0})}};n(hn,"ReadableStreamAsyncIteratorImpl");let Dt=hn;const to={next(){return ro(this)?this._asyncIteratorImpl.next():m(no("next"))},return(e){return ro(this)?this._asyncIteratorImpl.return(e):m(no("return"))}};eo!==void 0&&Object.setPrototypeOf(to,eo);function xi(e,t){const r=Qe(e),s=new Dt(r,t),l=Object.create(to);return l._asyncIteratorImpl=s,l}n(xi,"AcquireReadableStreamAsyncIterator");function ro(e){if(!d(e)||!Object.prototype.hasOwnProperty.call(e,"_asyncIteratorImpl"))return !1;try{return e._asyncIteratorImpl instanceof Dt}catch{return !1}}n(ro,"IsReadableStreamAsyncIterator");function no(e){return new TypeError(`ReadableStreamAsyncIterator.${e} can only be used on a ReadableSteamAsyncIterator`)}n(no,"streamAsyncIteratorBrandCheckException");const oo=Number.isNaN||function(e){return e!==e};function gt(e){return e.slice()}n(gt,"CreateArrayFromList");function io(e,t,r,s,l){new Uint8Array(e).set(new Uint8Array(r,s,l),t);}n(io,"CopyDataBlockBytes");let Se=n(e=>(typeof e.transfer=="function"?Se=n(t=>t.transfer(),"TransferArrayBuffer"):typeof structuredClone=="function"?Se=n(t=>structuredClone(t,{transfer:[t]}),"TransferArrayBuffer"):Se=n(t=>t,"TransferArrayBuffer"),Se(e)),"TransferArrayBuffer"),Ae=n(e=>(typeof e.detached=="boolean"?Ae=n(t=>t.detached,"IsDetachedBuffer"):Ae=n(t=>t.byteLength===0,"IsDetachedBuffer"),Ae(e)),"IsDetachedBuffer");function ao(e,t,r){if(e.slice)return e.slice(t,r);const s=r-t,l=new ArrayBuffer(s);return io(l,0,e,t,s),l}n(ao,"ArrayBufferSlice");function Mt(e,t){const r=e[t];if(r!=null){if(typeof r!="function")throw new TypeError(`${String(t)} is not a function`);return r}}n(Mt,"GetMethod");function Ni(e){const t={[u.iterator]:()=>e.iterator},r=async function*(){return yield*t}(),s=r.next;return {iterator:r,nextMethod:s,done:!1}}n(Ni,"CreateAsyncFromSyncIterator");function so(e,t="sync",r){if(r===void 0)if(t==="async"){if(r=Mt(e,u.asyncIterator),r===void 0){const c=Mt(e,u.iterator),h=so(e,"sync",c);return Ni(h)}}else r=Mt(e,u.iterator);if(r===void 0)throw new TypeError("The object is not iterable");const s=j(r,e,[]);if(!d(s))throw new TypeError("The iterator method must return an object");const l=s.next;return {iterator:s,nextMethod:l,done:!1}}n(so,"GetIterator");function Hi(e){const t=j(e.nextMethod,e.iterator,[]);if(!d(t))throw new TypeError("The iterator.next() method must return an object");return t}n(Hi,"IteratorNext");function Vi(e){return !!e.done}n(Vi,"IteratorComplete");function Qi(e){return e.value}n(Qi,"IteratorValue");function Yi(e){return !(typeof e!="number"||oo(e)||e<0)}n(Yi,"IsNonNegativeNumber");function uo(e){const t=ao(e.buffer,e.byteOffset,e.byteOffset+e.byteLength);return new Uint8Array(t)}n(uo,"CloneAsUint8Array");function $r(e){const t=e._queue.shift();return e._queueTotalSize-=t.size,e._queueTotalSize<0&&(e._queueTotalSize=0),t.value}n($r,"DequeueValue");function Dr(e,t,r){if(!Yi(r)||r===1/0)throw new RangeError("Size must be a finite, non-NaN, non-negative number.");e._queue.push({value:t,size:r}),e._queueTotalSize+=r;}n(Dr,"EnqueueValueWithSize");function Gi(e){return e._queue.peek().value}n(Gi,"PeekQueueValue");function Be(e){e._queue=new U,e._queueTotalSize=0;}n(Be,"ResetQueue");function lo(e){return e===DataView}n(lo,"isDataViewConstructor");function Zi(e){return lo(e.constructor)}n(Zi,"isDataView");function Ki(e){return lo(e)?1:e.BYTES_PER_ELEMENT}n(Ki,"arrayBufferViewElementSize");const pn=class pn{constructor(){throw new TypeError("Illegal constructor")}get view(){if(!Mr(this))throw Vr("view");return this._view}respond(t){if(!Mr(this))throw Vr("respond");if(_e(t,1,"respond"),t=Fr(t,"First parameter"),this._associatedReadableByteStreamController===void 0)throw new TypeError("This BYOB request has been invalidated");if(Ae(this._view.buffer))throw new TypeError("The BYOB request's buffer has been detached and so cannot be used as a response");Ht(this._associatedReadableByteStreamController,t);}respondWithNewView(t){if(!Mr(this))throw Vr("respondWithNewView");if(_e(t,1,"respondWithNewView"),!ArrayBuffer.isView(t))throw new TypeError("You can only respond with array buffer views");if(this._associatedReadableByteStreamController===void 0)throw new TypeError("This BYOB request has been invalidated");if(Ae(t.buffer))throw new TypeError("The given view's buffer has been detached and so cannot be used as a response");Vt(this._associatedReadableByteStreamController,t);}};n(pn,"ReadableStreamBYOBRequest");let we=pn;Object.defineProperties(we.prototype,{respond:{enumerable:!0},respondWithNewView:{enumerable:!0},view:{enumerable:!0}}),p(we.prototype.respond,"respond"),p(we.prototype.respondWithNewView,"respondWithNewView"),typeof u.toStringTag=="symbol"&&Object.defineProperty(we.prototype,u.toStringTag,{value:"ReadableStreamBYOBRequest",configurable:!0});const bn=class bn{constructor(){throw new TypeError("Illegal constructor")}get byobRequest(){if(!ze(this))throw St("byobRequest");return Hr(this)}get desiredSize(){if(!ze(this))throw St("desiredSize");return So(this)}close(){if(!ze(this))throw St("close");if(this._closeRequested)throw new TypeError("The stream has already been closed; do not close it again!");const t=this._controlledReadableByteStream._state;if(t!=="readable")throw new TypeError(`The stream (in ${t} state) is not in the readable state and cannot be closed`);_t(this);}enqueue(t){if(!ze(this))throw St("enqueue");if(_e(t,1,"enqueue"),!ArrayBuffer.isView(t))throw new TypeError("chunk must be an array buffer view");if(t.byteLength===0)throw new TypeError("chunk must have non-zero byteLength");if(t.buffer.byteLength===0)throw new TypeError("chunk's buffer must have non-zero byteLength");if(this._closeRequested)throw new TypeError("stream is closed or draining");const r=this._controlledReadableByteStream._state;if(r!=="readable")throw new TypeError(`The stream (in ${r} state) is not in the readable state and cannot be enqueued to`);Nt(this,t);}error(t=void 0){if(!ze(this))throw St("error");K(this,t);}[Ar](t){fo(this),Be(this);const r=this._cancelAlgorithm(t);return xt(this),r}[Br](t){const r=this._controlledReadableByteStream;if(this._queueTotalSize>0){_o(this,t);return}const s=this._autoAllocateChunkSize;if(s!==void 0){let l;try{l=new ArrayBuffer(s);}catch(h){t._errorSteps(h);return}const c={buffer:l,bufferByteLength:s,byteOffset:0,byteLength:s,bytesFilled:0,minimumFill:1,elementSize:1,viewConstructor:Uint8Array,readerType:"default"};this._pendingPullIntos.push(c);}Kn(r,t),Ie(this);}[kr](){if(this._pendingPullIntos.length>0){const t=this._pendingPullIntos.peek();t.readerType="none",this._pendingPullIntos=new U,this._pendingPullIntos.push(t);}}};n(bn,"ReadableByteStreamController");let te=bn;Object.defineProperties(te.prototype,{close:{enumerable:!0},enqueue:{enumerable:!0},error:{enumerable:!0},byobRequest:{enumerable:!0},desiredSize:{enumerable:!0}}),p(te.prototype.close,"close"),p(te.prototype.enqueue,"enqueue"),p(te.prototype.error,"error"),typeof u.toStringTag=="symbol"&&Object.defineProperty(te.prototype,u.toStringTag,{value:"ReadableByteStreamController",configurable:!0});function ze(e){return !d(e)||!Object.prototype.hasOwnProperty.call(e,"_controlledReadableByteStream")?!1:e instanceof te}n(ze,"IsReadableByteStreamController");function Mr(e){return !d(e)||!Object.prototype.hasOwnProperty.call(e,"_associatedReadableByteStreamController")?!1:e instanceof we}n(Mr,"IsReadableStreamBYOBRequest");function Ie(e){if(!ra(e))return;if(e._pulling){e._pullAgain=!0;return}e._pulling=!0;const r=e._pullAlgorithm();q(r,()=>(e._pulling=!1,e._pullAgain&&(e._pullAgain=!1,Ie(e)),null),s=>(K(e,s),null));}n(Ie,"ReadableByteStreamControllerCallPullIfNeeded");function fo(e){xr(e),e._pendingPullIntos=new U;}n(fo,"ReadableByteStreamControllerClearPendingPullIntos");function Ur(e,t){let r=!1;e._state==="closed"&&(r=!0);const s=co(t);t.readerType==="default"?Lr(e,s,r):ua(e,s,r);}n(Ur,"ReadableByteStreamControllerCommitPullIntoDescriptor");function co(e){const t=e.bytesFilled,r=e.elementSize;return new e.viewConstructor(e.buffer,e.byteOffset,t/r)}n(co,"ReadableByteStreamControllerConvertPullIntoDescriptor");function Ut(e,t,r,s){e._queue.push({buffer:t,byteOffset:r,byteLength:s}),e._queueTotalSize+=s;}n(Ut,"ReadableByteStreamControllerEnqueueChunkToQueue");function ho(e,t,r,s){let l;try{l=ao(t,r,r+s);}catch(c){throw K(e,c),c}Ut(e,l,0,s);}n(ho,"ReadableByteStreamControllerEnqueueClonedChunkToQueue");function po(e,t){t.bytesFilled>0&&ho(e,t.buffer,t.byteOffset,t.bytesFilled),Ye(e);}n(po,"ReadableByteStreamControllerEnqueueDetachedPullIntoToQueue");function bo(e,t){const r=Math.min(e._queueTotalSize,t.byteLength-t.bytesFilled),s=t.bytesFilled+r;let l=r,c=!1;const h=s%t.elementSize,y=s-h;y>=t.minimumFill&&(l=y-t.bytesFilled,c=!0);const T=e._queue;for(;l>0;){const g=T.peek(),C=Math.min(l,g.byteLength),P=t.byteOffset+t.bytesFilled;io(t.buffer,P,g.buffer,g.byteOffset,C),g.byteLength===C?T.shift():(g.byteOffset+=C,g.byteLength-=C),e._queueTotalSize-=C,mo(e,C,t),l-=C;}return c}n(bo,"ReadableByteStreamControllerFillPullIntoDescriptorFromQueue");function mo(e,t,r){r.bytesFilled+=t;}n(mo,"ReadableByteStreamControllerFillHeadPullIntoDescriptor");function yo(e){e._queueTotalSize===0&&e._closeRequested?(xt(e),vt(e._controlledReadableByteStream)):Ie(e);}n(yo,"ReadableByteStreamControllerHandleQueueDrain");function xr(e){e._byobRequest!==null&&(e._byobRequest._associatedReadableByteStreamController=void 0,e._byobRequest._view=null,e._byobRequest=null);}n(xr,"ReadableByteStreamControllerInvalidateBYOBRequest");function Nr(e){for(;e._pendingPullIntos.length>0;){if(e._queueTotalSize===0)return;const t=e._pendingPullIntos.peek();bo(e,t)&&(Ye(e),Ur(e._controlledReadableByteStream,t));}}n(Nr,"ReadableByteStreamControllerProcessPullIntoDescriptorsUsingQueue");function Ji(e){const t=e._controlledReadableByteStream._reader;for(;t._readRequests.length>0;){if(e._queueTotalSize===0)return;const r=t._readRequests.shift();_o(e,r);}}n(Ji,"ReadableByteStreamControllerProcessReadRequestsUsingQueue");function Xi(e,t,r,s){const l=e._controlledReadableByteStream,c=t.constructor,h=Ki(c),{byteOffset:y,byteLength:T}=t,g=r*h;let C;try{C=Se(t.buffer);}catch(B){s._errorSteps(B);return}const P={buffer:C,bufferByteLength:C.byteLength,byteOffset:y,byteLength:T,bytesFilled:0,minimumFill:g,elementSize:h,viewConstructor:c,readerType:"byob"};if(e._pendingPullIntos.length>0){e._pendingPullIntos.push(P),To(l,s);return}if(l._state==="closed"){const B=new c(P.buffer,P.byteOffset,0);s._closeSteps(B);return}if(e._queueTotalSize>0){if(bo(e,P)){const B=co(P);yo(e),s._chunkSteps(B);return}if(e._closeRequested){const B=new TypeError("Insufficient bytes to fill elements in the given buffer");K(e,B),s._errorSteps(B);return}}e._pendingPullIntos.push(P),To(l,s),Ie(e);}n(Xi,"ReadableByteStreamControllerPullInto");function ea(e,t){t.readerType==="none"&&Ye(e);const r=e._controlledReadableByteStream;if(Qr(r))for(;Co(r)>0;){const s=Ye(e);Ur(r,s);}}n(ea,"ReadableByteStreamControllerRespondInClosedState");function ta(e,t,r){if(mo(e,t,r),r.readerType==="none"){po(e,r),Nr(e);return}if(r.bytesFilled0){const l=r.byteOffset+r.bytesFilled;ho(e,r.buffer,l-s,s);}r.bytesFilled-=s,Ur(e._controlledReadableByteStream,r),Nr(e);}n(ta,"ReadableByteStreamControllerRespondInReadableState");function go(e,t){const r=e._pendingPullIntos.peek();xr(e),e._controlledReadableByteStream._state==="closed"?ea(e,r):ta(e,t,r),Ie(e);}n(go,"ReadableByteStreamControllerRespondInternal");function Ye(e){return e._pendingPullIntos.shift()}n(Ye,"ReadableByteStreamControllerShiftPendingPullInto");function ra(e){const t=e._controlledReadableByteStream;return t._state!=="readable"||e._closeRequested||!e._started?!1:!!(Jn(t)&&Lt(t)>0||Qr(t)&&Co(t)>0||So(e)>0)}n(ra,"ReadableByteStreamControllerShouldCallPull");function xt(e){e._pullAlgorithm=void 0,e._cancelAlgorithm=void 0;}n(xt,"ReadableByteStreamControllerClearAlgorithms");function _t(e){const t=e._controlledReadableByteStream;if(!(e._closeRequested||t._state!=="readable")){if(e._queueTotalSize>0){e._closeRequested=!0;return}if(e._pendingPullIntos.length>0){const r=e._pendingPullIntos.peek();if(r.bytesFilled%r.elementSize!==0){const s=new TypeError("Insufficient bytes to fill elements in the given buffer");throw K(e,s),s}}xt(e),vt(t);}}n(_t,"ReadableByteStreamControllerClose");function Nt(e,t){const r=e._controlledReadableByteStream;if(e._closeRequested||r._state!=="readable")return;const{buffer:s,byteOffset:l,byteLength:c}=t;if(Ae(s))throw new TypeError("chunk's buffer is detached and so cannot be enqueued");const h=Se(s);if(e._pendingPullIntos.length>0){const y=e._pendingPullIntos.peek();if(Ae(y.buffer))throw new TypeError("The BYOB request's buffer has been detached and so cannot be filled with an enqueued chunk");xr(e),y.buffer=Se(y.buffer),y.readerType==="none"&&po(e,y);}if(Jn(r))if(Ji(e),Lt(r)===0)Ut(e,h,l,c);else {e._pendingPullIntos.length>0&&Ye(e);const y=new Uint8Array(h,l,c);Lr(r,y,!1);}else Qr(r)?(Ut(e,h,l,c),Nr(e)):Ut(e,h,l,c);Ie(e);}n(Nt,"ReadableByteStreamControllerEnqueue");function K(e,t){const r=e._controlledReadableByteStream;r._state==="readable"&&(fo(e),Be(e),xt(e),Yo(r,t));}n(K,"ReadableByteStreamControllerError");function _o(e,t){const r=e._queue.shift();e._queueTotalSize-=r.byteLength,yo(e);const s=new Uint8Array(r.buffer,r.byteOffset,r.byteLength);t._chunkSteps(s);}n(_o,"ReadableByteStreamControllerFillReadRequestFromQueue");function Hr(e){if(e._byobRequest===null&&e._pendingPullIntos.length>0){const t=e._pendingPullIntos.peek(),r=new Uint8Array(t.buffer,t.byteOffset+t.bytesFilled,t.byteLength-t.bytesFilled),s=Object.create(we.prototype);oa(s,e,r),e._byobRequest=s;}return e._byobRequest}n(Hr,"ReadableByteStreamControllerGetBYOBRequest");function So(e){const t=e._controlledReadableByteStream._state;return t==="errored"?null:t==="closed"?0:e._strategyHWM-e._queueTotalSize}n(So,"ReadableByteStreamControllerGetDesiredSize");function Ht(e,t){const r=e._pendingPullIntos.peek();if(e._controlledReadableByteStream._state==="closed"){if(t!==0)throw new TypeError("bytesWritten must be 0 when calling respond() on a closed stream")}else {if(t===0)throw new TypeError("bytesWritten must be greater than 0 when calling respond() on a readable stream");if(r.bytesFilled+t>r.byteLength)throw new RangeError("bytesWritten out of range")}r.buffer=Se(r.buffer),go(e,t);}n(Ht,"ReadableByteStreamControllerRespond");function Vt(e,t){const r=e._pendingPullIntos.peek();if(e._controlledReadableByteStream._state==="closed"){if(t.byteLength!==0)throw new TypeError("The view's length must be 0 when calling respondWithNewView() on a closed stream")}else if(t.byteLength===0)throw new TypeError("The view's length must be greater than 0 when calling respondWithNewView() on a readable stream");if(r.byteOffset+r.bytesFilled!==t.byteOffset)throw new RangeError("The region specified by view does not match byobRequest");if(r.bufferByteLength!==t.buffer.byteLength)throw new RangeError("The buffer of view has different capacity than byobRequest");if(r.bytesFilled+t.byteLength>r.byteLength)throw new RangeError("The region specified by view is larger than byobRequest");const l=t.byteLength;r.buffer=Se(t.buffer),go(e,l);}n(Vt,"ReadableByteStreamControllerRespondWithNewView");function wo(e,t,r,s,l,c,h){t._controlledReadableByteStream=e,t._pullAgain=!1,t._pulling=!1,t._byobRequest=null,t._queue=t._queueTotalSize=void 0,Be(t),t._closeRequested=!1,t._started=!1,t._strategyHWM=c,t._pullAlgorithm=s,t._cancelAlgorithm=l,t._autoAllocateChunkSize=h,t._pendingPullIntos=new U,e._readableStreamController=t;const y=r();q(S(y),()=>(t._started=!0,Ie(t),null),T=>(K(t,T),null));}n(wo,"SetUpReadableByteStreamController");function na(e,t,r){const s=Object.create(te.prototype);let l,c,h;t.start!==void 0?l=n(()=>t.start(s),"startAlgorithm"):l=n(()=>{},"startAlgorithm"),t.pull!==void 0?c=n(()=>t.pull(s),"pullAlgorithm"):c=n(()=>S(void 0),"pullAlgorithm"),t.cancel!==void 0?h=n(T=>t.cancel(T),"cancelAlgorithm"):h=n(()=>S(void 0),"cancelAlgorithm");const y=t.autoAllocateChunkSize;if(y===0)throw new TypeError("autoAllocateChunkSize must be greater than 0");wo(e,s,l,c,h,r,y);}n(na,"SetUpReadableByteStreamControllerFromUnderlyingSource");function oa(e,t,r){e._associatedReadableByteStreamController=t,e._view=r;}n(oa,"SetUpReadableStreamBYOBRequest");function Vr(e){return new TypeError(`ReadableStreamBYOBRequest.prototype.${e} can only be used on a ReadableStreamBYOBRequest`)}n(Vr,"byobRequestBrandCheckException");function St(e){return new TypeError(`ReadableByteStreamController.prototype.${e} can only be used on a ReadableByteStreamController`)}n(St,"byteStreamControllerBrandCheckException");function ia(e,t){le(e,t);const r=e?.mode;return {mode:r===void 0?void 0:aa(r,`${t} has member 'mode' that`)}}n(ia,"convertReaderOptions");function aa(e,t){if(e=`${e}`,e!=="byob")throw new TypeError(`${t} '${e}' is not a valid enumeration value for ReadableStreamReaderMode`);return e}n(aa,"convertReadableStreamReaderMode");function sa(e,t){var r;le(e,t);const s=(r=e?.min)!==null&&r!==void 0?r:1;return {min:Fr(s,`${t} has member 'min' that`)}}n(sa,"convertByobReadOptions");function Ro(e){return new ce(e)}n(Ro,"AcquireReadableStreamBYOBReader");function To(e,t){e._reader._readIntoRequests.push(t);}n(To,"ReadableStreamAddReadIntoRequest");function ua(e,t,r){const l=e._reader._readIntoRequests.shift();r?l._closeSteps(t):l._chunkSteps(t);}n(ua,"ReadableStreamFulfillReadIntoRequest");function Co(e){return e._reader._readIntoRequests.length}n(Co,"ReadableStreamGetNumReadIntoRequests");function Qr(e){const t=e._reader;return !(t===void 0||!Fe(t))}n(Qr,"ReadableStreamHasBYOBReader");const mn=class mn{constructor(t){if(_e(t,1,"ReadableStreamBYOBReader"),jr(t,"First parameter"),qe(t))throw new TypeError("This stream has already been locked for exclusive reading by another reader");if(!ze(t._readableStreamController))throw new TypeError("Cannot construct a ReadableStreamBYOBReader for a stream not constructed with a byte source");Hn(this,t),this._readIntoRequests=new U;}get closed(){return Fe(this)?this._closedPromise:m(Qt("closed"))}cancel(t=void 0){return Fe(this)?this._ownerReadableStream===void 0?m(jt("cancel")):Wr(this,t):m(Qt("cancel"))}read(t,r={}){if(!Fe(this))return m(Qt("read"));if(!ArrayBuffer.isView(t))return m(new TypeError("view must be an array buffer view"));if(t.byteLength===0)return m(new TypeError("view must have non-zero byteLength"));if(t.buffer.byteLength===0)return m(new TypeError("view's buffer must have non-zero byteLength"));if(Ae(t.buffer))return m(new TypeError("view's buffer has been detached"));let s;try{s=sa(r,"options");}catch(g){return m(g)}const l=s.min;if(l===0)return m(new TypeError("options.min must be greater than 0"));if(Zi(t)){if(l>t.byteLength)return m(new RangeError("options.min must be less than or equal to view's byteLength"))}else if(l>t.length)return m(new RangeError("options.min must be less than or equal to view's length"));if(this._ownerReadableStream===void 0)return m(jt("read from"));let c,h;const y=A((g,C)=>{c=g,h=C;});return Po(this,t,l,{_chunkSteps:g=>c({value:g,done:!1}),_closeSteps:g=>c({value:g,done:!0}),_errorSteps:g=>h(g)}),y}releaseLock(){if(!Fe(this))throw Qt("releaseLock");this._ownerReadableStream!==void 0&&la(this);}};n(mn,"ReadableStreamBYOBReader");let ce=mn;Object.defineProperties(ce.prototype,{cancel:{enumerable:!0},read:{enumerable:!0},releaseLock:{enumerable:!0},closed:{enumerable:!0}}),p(ce.prototype.cancel,"cancel"),p(ce.prototype.read,"read"),p(ce.prototype.releaseLock,"releaseLock"),typeof u.toStringTag=="symbol"&&Object.defineProperty(ce.prototype,u.toStringTag,{value:"ReadableStreamBYOBReader",configurable:!0});function Fe(e){return !d(e)||!Object.prototype.hasOwnProperty.call(e,"_readIntoRequests")?!1:e instanceof ce}n(Fe,"IsReadableStreamBYOBReader");function Po(e,t,r,s){const l=e._ownerReadableStream;l._disturbed=!0,l._state==="errored"?s._errorSteps(l._storedError):Xi(l._readableStreamController,t,r,s);}n(Po,"ReadableStreamBYOBReaderRead");function la(e){ge(e);const t=new TypeError("Reader was released");vo(e,t);}n(la,"ReadableStreamBYOBReaderRelease");function vo(e,t){const r=e._readIntoRequests;e._readIntoRequests=new U,r.forEach(s=>{s._errorSteps(t);});}n(vo,"ReadableStreamBYOBReaderErrorReadIntoRequests");function Qt(e){return new TypeError(`ReadableStreamBYOBReader.prototype.${e} can only be used on a ReadableStreamBYOBReader`)}n(Qt,"byobReaderBrandCheckException");function wt(e,t){const{highWaterMark:r}=e;if(r===void 0)return t;if(oo(r)||r<0)throw new RangeError("Invalid highWaterMark");return r}n(wt,"ExtractHighWaterMark");function Yt(e){const{size:t}=e;return t||(()=>1)}n(Yt,"ExtractSizeAlgorithm");function Gt(e,t){le(e,t);const r=e?.highWaterMark,s=e?.size;return {highWaterMark:r===void 0?void 0:Ir(r),size:s===void 0?void 0:fa(s,`${t} has member 'size' that`)}}n(Gt,"convertQueuingStrategy");function fa(e,t){return Z(e,t),r=>Ir(e(r))}n(fa,"convertQueuingStrategySize");function ca(e,t){le(e,t);const r=e?.abort,s=e?.close,l=e?.start,c=e?.type,h=e?.write;return {abort:r===void 0?void 0:da(r,e,`${t} has member 'abort' that`),close:s===void 0?void 0:ha(s,e,`${t} has member 'close' that`),start:l===void 0?void 0:pa(l,e,`${t} has member 'start' that`),write:h===void 0?void 0:ba(h,e,`${t} has member 'write' that`),type:c}}n(ca,"convertUnderlyingSink");function da(e,t,r){return Z(e,r),s=>I(e,t,[s])}n(da,"convertUnderlyingSinkAbortCallback");function ha(e,t,r){return Z(e,r),()=>I(e,t,[])}n(ha,"convertUnderlyingSinkCloseCallback");function pa(e,t,r){return Z(e,r),s=>j(e,t,[s])}n(pa,"convertUnderlyingSinkStartCallback");function ba(e,t,r){return Z(e,r),(s,l)=>I(e,t,[s,l])}n(ba,"convertUnderlyingSinkWriteCallback");function Eo(e,t){if(!Ge(e))throw new TypeError(`${t} is not a WritableStream.`)}n(Eo,"assertWritableStream");function ma(e){if(typeof e!="object"||e===null)return !1;try{return typeof e.aborted=="boolean"}catch{return !1}}n(ma,"isAbortSignal");const ya=typeof AbortController=="function";function ga(){if(ya)return new AbortController}n(ga,"createAbortController");const yn=class yn{constructor(t={},r={}){t===void 0?t=null:Gn(t,"First parameter");const s=Gt(r,"Second parameter"),l=ca(t,"First parameter");if(Bo(this),l.type!==void 0)throw new RangeError("Invalid type is specified");const h=Yt(s),y=wt(s,1);qa(this,l,y,h);}get locked(){if(!Ge(this))throw er("locked");return Ze(this)}abort(t=void 0){return Ge(this)?Ze(this)?m(new TypeError("Cannot abort a stream that already has a writer")):Zt(this,t):m(er("abort"))}close(){return Ge(this)?Ze(this)?m(new TypeError("Cannot close a stream that already has a writer")):he(this)?m(new TypeError("Cannot close an already-closing stream")):ko(this):m(er("close"))}getWriter(){if(!Ge(this))throw er("getWriter");return Ao(this)}};n(yn,"WritableStream");let de=yn;Object.defineProperties(de.prototype,{abort:{enumerable:!0},close:{enumerable:!0},getWriter:{enumerable:!0},locked:{enumerable:!0}}),p(de.prototype.abort,"abort"),p(de.prototype.close,"close"),p(de.prototype.getWriter,"getWriter"),typeof u.toStringTag=="symbol"&&Object.defineProperty(de.prototype,u.toStringTag,{value:"WritableStream",configurable:!0});function Ao(e){return new re(e)}n(Ao,"AcquireWritableStreamDefaultWriter");function _a(e,t,r,s,l=1,c=()=>1){const h=Object.create(de.prototype);Bo(h);const y=Object.create(ke.prototype);return Fo(h,y,e,t,r,s,l,c),h}n(_a,"CreateWritableStream");function Bo(e){e._state="writable",e._storedError=void 0,e._writer=void 0,e._writableStreamController=void 0,e._writeRequests=new U,e._inFlightWriteRequest=void 0,e._closeRequest=void 0,e._inFlightCloseRequest=void 0,e._pendingAbortRequest=void 0,e._backpressure=!1;}n(Bo,"InitializeWritableStream");function Ge(e){return !d(e)||!Object.prototype.hasOwnProperty.call(e,"_writableStreamController")?!1:e instanceof de}n(Ge,"IsWritableStream");function Ze(e){return e._writer!==void 0}n(Ze,"IsWritableStreamLocked");function Zt(e,t){var r;if(e._state==="closed"||e._state==="errored")return S(void 0);e._writableStreamController._abortReason=t,(r=e._writableStreamController._abortController)===null||r===void 0||r.abort(t);const s=e._state;if(s==="closed"||s==="errored")return S(void 0);if(e._pendingAbortRequest!==void 0)return e._pendingAbortRequest._promise;let l=!1;s==="erroring"&&(l=!0,t=void 0);const c=A((h,y)=>{e._pendingAbortRequest={_promise:void 0,_resolve:h,_reject:y,_reason:t,_wasAlreadyErroring:l};});return e._pendingAbortRequest._promise=c,l||Gr(e,t),c}n(Zt,"WritableStreamAbort");function ko(e){const t=e._state;if(t==="closed"||t==="errored")return m(new TypeError(`The stream (in ${t} state) is not in the writable state and cannot be closed`));const r=A((l,c)=>{const h={_resolve:l,_reject:c};e._closeRequest=h;}),s=e._writer;return s!==void 0&&e._backpressure&&t==="writable"&&nn(s),Oa(e._writableStreamController),r}n(ko,"WritableStreamClose");function Sa(e){return A((r,s)=>{const l={_resolve:r,_reject:s};e._writeRequests.push(l);})}n(Sa,"WritableStreamAddWriteRequest");function Yr(e,t){if(e._state==="writable"){Gr(e,t);return}Zr(e);}n(Yr,"WritableStreamDealWithRejection");function Gr(e,t){const r=e._writableStreamController;e._state="erroring",e._storedError=t;const s=e._writer;s!==void 0&&qo(s,t),!Pa(e)&&r._started&&Zr(e);}n(Gr,"WritableStreamStartErroring");function Zr(e){e._state="errored",e._writableStreamController[Nn]();const t=e._storedError;if(e._writeRequests.forEach(l=>{l._reject(t);}),e._writeRequests=new U,e._pendingAbortRequest===void 0){Kt(e);return}const r=e._pendingAbortRequest;if(e._pendingAbortRequest=void 0,r._wasAlreadyErroring){r._reject(t),Kt(e);return}const s=e._writableStreamController[xn](r._reason);q(s,()=>(r._resolve(),Kt(e),null),l=>(r._reject(l),Kt(e),null));}n(Zr,"WritableStreamFinishErroring");function wa(e){e._inFlightWriteRequest._resolve(void 0),e._inFlightWriteRequest=void 0;}n(wa,"WritableStreamFinishInFlightWrite");function Ra(e,t){e._inFlightWriteRequest._reject(t),e._inFlightWriteRequest=void 0,Yr(e,t);}n(Ra,"WritableStreamFinishInFlightWriteWithError");function Ta(e){e._inFlightCloseRequest._resolve(void 0),e._inFlightCloseRequest=void 0,e._state==="erroring"&&(e._storedError=void 0,e._pendingAbortRequest!==void 0&&(e._pendingAbortRequest._resolve(),e._pendingAbortRequest=void 0)),e._state="closed";const r=e._writer;r!==void 0&&Do(r);}n(Ta,"WritableStreamFinishInFlightClose");function Ca(e,t){e._inFlightCloseRequest._reject(t),e._inFlightCloseRequest=void 0,e._pendingAbortRequest!==void 0&&(e._pendingAbortRequest._reject(t),e._pendingAbortRequest=void 0),Yr(e,t);}n(Ca,"WritableStreamFinishInFlightCloseWithError");function he(e){return !(e._closeRequest===void 0&&e._inFlightCloseRequest===void 0)}n(he,"WritableStreamCloseQueuedOrInFlight");function Pa(e){return !(e._inFlightWriteRequest===void 0&&e._inFlightCloseRequest===void 0)}n(Pa,"WritableStreamHasOperationMarkedInFlight");function va(e){e._inFlightCloseRequest=e._closeRequest,e._closeRequest=void 0;}n(va,"WritableStreamMarkCloseRequestInFlight");function Ea(e){e._inFlightWriteRequest=e._writeRequests.shift();}n(Ea,"WritableStreamMarkFirstWriteRequestInFlight");function Kt(e){e._closeRequest!==void 0&&(e._closeRequest._reject(e._storedError),e._closeRequest=void 0);const t=e._writer;t!==void 0&&tn(t,e._storedError);}n(Kt,"WritableStreamRejectCloseAndClosedPromiseIfNeeded");function Kr(e,t){const r=e._writer;r!==void 0&&t!==e._backpressure&&(t?Da(r):nn(r)),e._backpressure=t;}n(Kr,"WritableStreamUpdateBackpressure");const gn=class gn{constructor(t){if(_e(t,1,"WritableStreamDefaultWriter"),Eo(t,"First parameter"),Ze(t))throw new TypeError("This stream has already been locked for exclusive writing by another writer");this._ownerWritableStream=t,t._writer=this;const r=t._state;if(r==="writable")!he(t)&&t._backpressure?rr(this):Mo(this),tr(this);else if(r==="erroring")rn(this,t._storedError),tr(this);else if(r==="closed")Mo(this),La(this);else {const s=t._storedError;rn(this,s),$o(this,s);}}get closed(){return je(this)?this._closedPromise:m(Le("closed"))}get desiredSize(){if(!je(this))throw Le("desiredSize");if(this._ownerWritableStream===void 0)throw Tt("desiredSize");return Wa(this)}get ready(){return je(this)?this._readyPromise:m(Le("ready"))}abort(t=void 0){return je(this)?this._ownerWritableStream===void 0?m(Tt("abort")):Aa(this,t):m(Le("abort"))}close(){if(!je(this))return m(Le("close"));const t=this._ownerWritableStream;return t===void 0?m(Tt("close")):he(t)?m(new TypeError("Cannot close an already-closing stream")):Wo(this)}releaseLock(){if(!je(this))throw Le("releaseLock");this._ownerWritableStream!==void 0&&Oo(this);}write(t=void 0){return je(this)?this._ownerWritableStream===void 0?m(Tt("write to")):zo(this,t):m(Le("write"))}};n(gn,"WritableStreamDefaultWriter");let re=gn;Object.defineProperties(re.prototype,{abort:{enumerable:!0},close:{enumerable:!0},releaseLock:{enumerable:!0},write:{enumerable:!0},closed:{enumerable:!0},desiredSize:{enumerable:!0},ready:{enumerable:!0}}),p(re.prototype.abort,"abort"),p(re.prototype.close,"close"),p(re.prototype.releaseLock,"releaseLock"),p(re.prototype.write,"write"),typeof u.toStringTag=="symbol"&&Object.defineProperty(re.prototype,u.toStringTag,{value:"WritableStreamDefaultWriter",configurable:!0});function je(e){return !d(e)||!Object.prototype.hasOwnProperty.call(e,"_ownerWritableStream")?!1:e instanceof re}n(je,"IsWritableStreamDefaultWriter");function Aa(e,t){const r=e._ownerWritableStream;return Zt(r,t)}n(Aa,"WritableStreamDefaultWriterAbort");function Wo(e){const t=e._ownerWritableStream;return ko(t)}n(Wo,"WritableStreamDefaultWriterClose");function Ba(e){const t=e._ownerWritableStream,r=t._state;return he(t)||r==="closed"?S(void 0):r==="errored"?m(t._storedError):Wo(e)}n(Ba,"WritableStreamDefaultWriterCloseWithErrorPropagation");function ka(e,t){e._closedPromiseState==="pending"?tn(e,t):$a(e,t);}n(ka,"WritableStreamDefaultWriterEnsureClosedPromiseRejected");function qo(e,t){e._readyPromiseState==="pending"?Uo(e,t):Ma(e,t);}n(qo,"WritableStreamDefaultWriterEnsureReadyPromiseRejected");function Wa(e){const t=e._ownerWritableStream,r=t._state;return r==="errored"||r==="erroring"?null:r==="closed"?0:jo(t._writableStreamController)}n(Wa,"WritableStreamDefaultWriterGetDesiredSize");function Oo(e){const t=e._ownerWritableStream,r=new TypeError("Writer was released and can no longer be used to monitor the stream's closedness");qo(e,r),ka(e,r),t._writer=void 0,e._ownerWritableStream=void 0;}n(Oo,"WritableStreamDefaultWriterRelease");function zo(e,t){const r=e._ownerWritableStream,s=r._writableStreamController,l=za(s,t);if(r!==e._ownerWritableStream)return m(Tt("write to"));const c=r._state;if(c==="errored")return m(r._storedError);if(he(r)||c==="closed")return m(new TypeError("The stream is closing or closed and cannot be written to"));if(c==="erroring")return m(r._storedError);const h=Sa(r);return Ia(s,t,l),h}n(zo,"WritableStreamDefaultWriterWrite");const Io={},_n=class _n{constructor(){throw new TypeError("Illegal constructor")}get abortReason(){if(!Jr(this))throw en("abortReason");return this._abortReason}get signal(){if(!Jr(this))throw en("signal");if(this._abortController===void 0)throw new TypeError("WritableStreamDefaultController.prototype.signal is not supported");return this._abortController.signal}error(t=void 0){if(!Jr(this))throw en("error");this._controlledWritableStream._state==="writable"&&Lo(this,t);}[xn](t){const r=this._abortAlgorithm(t);return Jt(this),r}[Nn](){Be(this);}};n(_n,"WritableStreamDefaultController");let ke=_n;Object.defineProperties(ke.prototype,{abortReason:{enumerable:!0},signal:{enumerable:!0},error:{enumerable:!0}}),typeof u.toStringTag=="symbol"&&Object.defineProperty(ke.prototype,u.toStringTag,{value:"WritableStreamDefaultController",configurable:!0});function Jr(e){return !d(e)||!Object.prototype.hasOwnProperty.call(e,"_controlledWritableStream")?!1:e instanceof ke}n(Jr,"IsWritableStreamDefaultController");function Fo(e,t,r,s,l,c,h,y){t._controlledWritableStream=e,e._writableStreamController=t,t._queue=void 0,t._queueTotalSize=void 0,Be(t),t._abortReason=void 0,t._abortController=ga(),t._started=!1,t._strategySizeAlgorithm=y,t._strategyHWM=h,t._writeAlgorithm=s,t._closeAlgorithm=l,t._abortAlgorithm=c;const T=Xr(t);Kr(e,T);const g=r(),C=S(g);q(C,()=>(t._started=!0,Xt(t),null),P=>(t._started=!0,Yr(e,P),null));}n(Fo,"SetUpWritableStreamDefaultController");function qa(e,t,r,s){const l=Object.create(ke.prototype);let c,h,y,T;t.start!==void 0?c=n(()=>t.start(l),"startAlgorithm"):c=n(()=>{},"startAlgorithm"),t.write!==void 0?h=n(g=>t.write(g,l),"writeAlgorithm"):h=n(()=>S(void 0),"writeAlgorithm"),t.close!==void 0?y=n(()=>t.close(),"closeAlgorithm"):y=n(()=>S(void 0),"closeAlgorithm"),t.abort!==void 0?T=n(g=>t.abort(g),"abortAlgorithm"):T=n(()=>S(void 0),"abortAlgorithm"),Fo(e,l,c,h,y,T,r,s);}n(qa,"SetUpWritableStreamDefaultControllerFromUnderlyingSink");function Jt(e){e._writeAlgorithm=void 0,e._closeAlgorithm=void 0,e._abortAlgorithm=void 0,e._strategySizeAlgorithm=void 0;}n(Jt,"WritableStreamDefaultControllerClearAlgorithms");function Oa(e){Dr(e,Io,0),Xt(e);}n(Oa,"WritableStreamDefaultControllerClose");function za(e,t){try{return e._strategySizeAlgorithm(t)}catch(r){return Rt(e,r),1}}n(za,"WritableStreamDefaultControllerGetChunkSize");function jo(e){return e._strategyHWM-e._queueTotalSize}n(jo,"WritableStreamDefaultControllerGetDesiredSize");function Ia(e,t,r){try{Dr(e,t,r);}catch(l){Rt(e,l);return}const s=e._controlledWritableStream;if(!he(s)&&s._state==="writable"){const l=Xr(e);Kr(s,l);}Xt(e);}n(Ia,"WritableStreamDefaultControllerWrite");function Xt(e){const t=e._controlledWritableStream;if(!e._started||t._inFlightWriteRequest!==void 0)return;if(t._state==="erroring"){Zr(t);return}if(e._queue.length===0)return;const s=Gi(e);s===Io?Fa(e):ja(e,s);}n(Xt,"WritableStreamDefaultControllerAdvanceQueueIfNeeded");function Rt(e,t){e._controlledWritableStream._state==="writable"&&Lo(e,t);}n(Rt,"WritableStreamDefaultControllerErrorIfNeeded");function Fa(e){const t=e._controlledWritableStream;va(t),$r(e);const r=e._closeAlgorithm();Jt(e),q(r,()=>(Ta(t),null),s=>(Ca(t,s),null));}n(Fa,"WritableStreamDefaultControllerProcessClose");function ja(e,t){const r=e._controlledWritableStream;Ea(r);const s=e._writeAlgorithm(t);q(s,()=>{wa(r);const l=r._state;if($r(e),!he(r)&&l==="writable"){const c=Xr(e);Kr(r,c);}return Xt(e),null},l=>(r._state==="writable"&&Jt(e),Ra(r,l),null));}n(ja,"WritableStreamDefaultControllerProcessWrite");function Xr(e){return jo(e)<=0}n(Xr,"WritableStreamDefaultControllerGetBackpressure");function Lo(e,t){const r=e._controlledWritableStream;Jt(e),Gr(r,t);}n(Lo,"WritableStreamDefaultControllerError");function er(e){return new TypeError(`WritableStream.prototype.${e} can only be used on a WritableStream`)}n(er,"streamBrandCheckException$2");function en(e){return new TypeError(`WritableStreamDefaultController.prototype.${e} can only be used on a WritableStreamDefaultController`)}n(en,"defaultControllerBrandCheckException$2");function Le(e){return new TypeError(`WritableStreamDefaultWriter.prototype.${e} can only be used on a WritableStreamDefaultWriter`)}n(Le,"defaultWriterBrandCheckException");function Tt(e){return new TypeError("Cannot "+e+" a stream using a released writer")}n(Tt,"defaultWriterLockException");function tr(e){e._closedPromise=A((t,r)=>{e._closedPromise_resolve=t,e._closedPromise_reject=r,e._closedPromiseState="pending";});}n(tr,"defaultWriterClosedPromiseInitialize");function $o(e,t){tr(e),tn(e,t);}n($o,"defaultWriterClosedPromiseInitializeAsRejected");function La(e){tr(e),Do(e);}n(La,"defaultWriterClosedPromiseInitializeAsResolved");function tn(e,t){e._closedPromise_reject!==void 0&&(ve(e._closedPromise),e._closedPromise_reject(t),e._closedPromise_resolve=void 0,e._closedPromise_reject=void 0,e._closedPromiseState="rejected");}n(tn,"defaultWriterClosedPromiseReject");function $a(e,t){$o(e,t);}n($a,"defaultWriterClosedPromiseResetToRejected");function Do(e){e._closedPromise_resolve!==void 0&&(e._closedPromise_resolve(void 0),e._closedPromise_resolve=void 0,e._closedPromise_reject=void 0,e._closedPromiseState="resolved");}n(Do,"defaultWriterClosedPromiseResolve");function rr(e){e._readyPromise=A((t,r)=>{e._readyPromise_resolve=t,e._readyPromise_reject=r;}),e._readyPromiseState="pending";}n(rr,"defaultWriterReadyPromiseInitialize");function rn(e,t){rr(e),Uo(e,t);}n(rn,"defaultWriterReadyPromiseInitializeAsRejected");function Mo(e){rr(e),nn(e);}n(Mo,"defaultWriterReadyPromiseInitializeAsResolved");function Uo(e,t){e._readyPromise_reject!==void 0&&(ve(e._readyPromise),e._readyPromise_reject(t),e._readyPromise_resolve=void 0,e._readyPromise_reject=void 0,e._readyPromiseState="rejected");}n(Uo,"defaultWriterReadyPromiseReject");function Da(e){rr(e);}n(Da,"defaultWriterReadyPromiseReset");function Ma(e,t){rn(e,t);}n(Ma,"defaultWriterReadyPromiseResetToRejected");function nn(e){e._readyPromise_resolve!==void 0&&(e._readyPromise_resolve(void 0),e._readyPromise_resolve=void 0,e._readyPromise_reject=void 0,e._readyPromiseState="fulfilled");}n(nn,"defaultWriterReadyPromiseResolve");function Ua(){if(typeof globalThis<"u")return globalThis;if(typeof self<"u")return self;if(typeof n$1<"u")return n$1}n(Ua,"getGlobals");const on=Ua();function xa(e){if(!(typeof e=="function"||typeof e=="object")||e.name!=="DOMException")return !1;try{return new e,!0}catch{return !1}}n(xa,"isDOMExceptionConstructor");function Na(){const e=on?.DOMException;return xa(e)?e:void 0}n(Na,"getFromGlobal");function Ha(){const e=n(function(r,s){this.message=r||"",this.name=s||"Error",Error.captureStackTrace&&Error.captureStackTrace(this,this.constructor);},"DOMException");return p(e,"DOMException"),e.prototype=Object.create(Error.prototype),Object.defineProperty(e.prototype,"constructor",{value:e,writable:!0,configurable:!0}),e}n(Ha,"createPolyfill");const Va=Na()||Ha();function xo(e,t,r,s,l,c){const h=Qe(e),y=Ao(t);e._disturbed=!0;let T=!1,g=S(void 0);return A((C,P)=>{let B;if(c!==void 0){if(B=n(()=>{const _=c.reason!==void 0?c.reason:new Va("Aborted","AbortError"),v=[];s||v.push(()=>t._state==="writable"?Zt(t,_):S(void 0)),l||v.push(()=>e._state==="readable"?ie(e,_):S(void 0)),H(()=>Promise.all(v.map(k=>k())),!0,_);},"abortAlgorithm"),c.aborted){B();return}c.addEventListener("abort",B);}function ae(){return A((_,v)=>{function k(Y){Y?_():R(nt(),k,v);}n(k,"next"),k(!1);})}n(ae,"pipeLoop");function nt(){return T?S(!0):R(y._readyPromise,()=>A((_,v)=>{yt(h,{_chunkSteps:k=>{g=R(zo(y,k),void 0,f),_(!1);},_closeSteps:()=>_(!0),_errorSteps:v});}))}if(n(nt,"pipeStep"),Re(e,h._closedPromise,_=>(s?J(!0,_):H(()=>Zt(t,_),!0,_),null)),Re(t,y._closedPromise,_=>(l?J(!0,_):H(()=>ie(e,_),!0,_),null)),N(e,h._closedPromise,()=>(r?J():H(()=>Ba(y)),null)),he(t)||t._state==="closed"){const _=new TypeError("the destination writable stream closed before all data could be piped to it");l?J(!0,_):H(()=>ie(e,_),!0,_);}ve(ae());function Oe(){const _=g;return R(g,()=>_!==g?Oe():void 0)}n(Oe,"waitForWritesToFinish");function Re(_,v,k){_._state==="errored"?k(_._storedError):Q(v,k);}n(Re,"isOrBecomesErrored");function N(_,v,k){_._state==="closed"?k():F(v,k);}n(N,"isOrBecomesClosed");function H(_,v,k){if(T)return;T=!0,t._state==="writable"&&!he(t)?F(Oe(),Y):Y();function Y(){return q(_(),()=>Te(v,k),ot=>Te(!0,ot)),null}n(Y,"doTheRest");}n(H,"shutdownWithAction");function J(_,v){T||(T=!0,t._state==="writable"&&!he(t)?F(Oe(),()=>Te(_,v)):Te(_,v));}n(J,"shutdown");function Te(_,v){return Oo(y),ge(h),c!==void 0&&c.removeEventListener("abort",B),_?P(v):C(void 0),null}n(Te,"finalize");})}n(xo,"ReadableStreamPipeTo");const Sn=class Sn{constructor(){throw new TypeError("Illegal constructor")}get desiredSize(){if(!nr(this))throw ir("desiredSize");return an(this)}close(){if(!nr(this))throw ir("close");if(!Je(this))throw new TypeError("The stream is not in a state that permits close");$e(this);}enqueue(t=void 0){if(!nr(this))throw ir("enqueue");if(!Je(this))throw new TypeError("The stream is not in a state that permits enqueue");return Ke(this,t)}error(t=void 0){if(!nr(this))throw ir("error");oe(this,t);}[Ar](t){Be(this);const r=this._cancelAlgorithm(t);return or(this),r}[Br](t){const r=this._controlledReadableStream;if(this._queue.length>0){const s=$r(this);this._closeRequested&&this._queue.length===0?(or(this),vt(r)):Ct(this),t._chunkSteps(s);}else Kn(r,t),Ct(this);}[kr](){}};n(Sn,"ReadableStreamDefaultController");let ne=Sn;Object.defineProperties(ne.prototype,{close:{enumerable:!0},enqueue:{enumerable:!0},error:{enumerable:!0},desiredSize:{enumerable:!0}}),p(ne.prototype.close,"close"),p(ne.prototype.enqueue,"enqueue"),p(ne.prototype.error,"error"),typeof u.toStringTag=="symbol"&&Object.defineProperty(ne.prototype,u.toStringTag,{value:"ReadableStreamDefaultController",configurable:!0});function nr(e){return !d(e)||!Object.prototype.hasOwnProperty.call(e,"_controlledReadableStream")?!1:e instanceof ne}n(nr,"IsReadableStreamDefaultController");function Ct(e){if(!No(e))return;if(e._pulling){e._pullAgain=!0;return}e._pulling=!0;const r=e._pullAlgorithm();q(r,()=>(e._pulling=!1,e._pullAgain&&(e._pullAgain=!1,Ct(e)),null),s=>(oe(e,s),null));}n(Ct,"ReadableStreamDefaultControllerCallPullIfNeeded");function No(e){const t=e._controlledReadableStream;return !Je(e)||!e._started?!1:!!(qe(t)&&Lt(t)>0||an(e)>0)}n(No,"ReadableStreamDefaultControllerShouldCallPull");function or(e){e._pullAlgorithm=void 0,e._cancelAlgorithm=void 0,e._strategySizeAlgorithm=void 0;}n(or,"ReadableStreamDefaultControllerClearAlgorithms");function $e(e){if(!Je(e))return;const t=e._controlledReadableStream;e._closeRequested=!0,e._queue.length===0&&(or(e),vt(t));}n($e,"ReadableStreamDefaultControllerClose");function Ke(e,t){if(!Je(e))return;const r=e._controlledReadableStream;if(qe(r)&&Lt(r)>0)Lr(r,t,!1);else {let s;try{s=e._strategySizeAlgorithm(t);}catch(l){throw oe(e,l),l}try{Dr(e,t,s);}catch(l){throw oe(e,l),l}}Ct(e);}n(Ke,"ReadableStreamDefaultControllerEnqueue");function oe(e,t){const r=e._controlledReadableStream;r._state==="readable"&&(Be(e),or(e),Yo(r,t));}n(oe,"ReadableStreamDefaultControllerError");function an(e){const t=e._controlledReadableStream._state;return t==="errored"?null:t==="closed"?0:e._strategyHWM-e._queueTotalSize}n(an,"ReadableStreamDefaultControllerGetDesiredSize");function Qa(e){return !No(e)}n(Qa,"ReadableStreamDefaultControllerHasBackpressure");function Je(e){const t=e._controlledReadableStream._state;return !e._closeRequested&&t==="readable"}n(Je,"ReadableStreamDefaultControllerCanCloseOrEnqueue");function Ho(e,t,r,s,l,c,h){t._controlledReadableStream=e,t._queue=void 0,t._queueTotalSize=void 0,Be(t),t._started=!1,t._closeRequested=!1,t._pullAgain=!1,t._pulling=!1,t._strategySizeAlgorithm=h,t._strategyHWM=c,t._pullAlgorithm=s,t._cancelAlgorithm=l,e._readableStreamController=t;const y=r();q(S(y),()=>(t._started=!0,Ct(t),null),T=>(oe(t,T),null));}n(Ho,"SetUpReadableStreamDefaultController");function Ya(e,t,r,s){const l=Object.create(ne.prototype);let c,h,y;t.start!==void 0?c=n(()=>t.start(l),"startAlgorithm"):c=n(()=>{},"startAlgorithm"),t.pull!==void 0?h=n(()=>t.pull(l),"pullAlgorithm"):h=n(()=>S(void 0),"pullAlgorithm"),t.cancel!==void 0?y=n(T=>t.cancel(T),"cancelAlgorithm"):y=n(()=>S(void 0),"cancelAlgorithm"),Ho(e,l,c,h,y,r,s);}n(Ya,"SetUpReadableStreamDefaultControllerFromUnderlyingSource");function ir(e){return new TypeError(`ReadableStreamDefaultController.prototype.${e} can only be used on a ReadableStreamDefaultController`)}n(ir,"defaultControllerBrandCheckException$1");function Ga(e,t){return ze(e._readableStreamController)?Ka(e):Za(e)}n(Ga,"ReadableStreamTee");function Za(e,t){const r=Qe(e);let s=!1,l=!1,c=!1,h=!1,y,T,g,C,P;const B=A(N=>{P=N;});function ae(){return s?(l=!0,S(void 0)):(s=!0,yt(r,{_chunkSteps:H=>{z(()=>{l=!1;const J=H,Te=H;c||Ke(g._readableStreamController,J),h||Ke(C._readableStreamController,Te),s=!1,l&&ae();});},_closeSteps:()=>{s=!1,c||$e(g._readableStreamController),h||$e(C._readableStreamController),(!c||!h)&&P(void 0);},_errorSteps:()=>{s=!1;}}),S(void 0))}n(ae,"pullAlgorithm");function nt(N){if(c=!0,y=N,h){const H=gt([y,T]),J=ie(e,H);P(J);}return B}n(nt,"cancel1Algorithm");function Oe(N){if(h=!0,T=N,c){const H=gt([y,T]),J=ie(e,H);P(J);}return B}n(Oe,"cancel2Algorithm");function Re(){}return n(Re,"startAlgorithm"),g=Pt(Re,ae,nt),C=Pt(Re,ae,Oe),Q(r._closedPromise,N=>(oe(g._readableStreamController,N),oe(C._readableStreamController,N),(!c||!h)&&P(void 0),null)),[g,C]}n(Za,"ReadableStreamDefaultTee");function Ka(e){let t=Qe(e),r=!1,s=!1,l=!1,c=!1,h=!1,y,T,g,C,P;const B=A(_=>{P=_;});function ae(_){Q(_._closedPromise,v=>(_!==t||(K(g._readableStreamController,v),K(C._readableStreamController,v),(!c||!h)&&P(void 0)),null));}n(ae,"forwardReaderError");function nt(){Fe(t)&&(ge(t),t=Qe(e),ae(t)),yt(t,{_chunkSteps:v=>{z(()=>{s=!1,l=!1;const k=v;let Y=v;if(!c&&!h)try{Y=uo(v);}catch(ot){K(g._readableStreamController,ot),K(C._readableStreamController,ot),P(ie(e,ot));return}c||Nt(g._readableStreamController,k),h||Nt(C._readableStreamController,Y),r=!1,s?Re():l&&N();});},_closeSteps:()=>{r=!1,c||_t(g._readableStreamController),h||_t(C._readableStreamController),g._readableStreamController._pendingPullIntos.length>0&&Ht(g._readableStreamController,0),C._readableStreamController._pendingPullIntos.length>0&&Ht(C._readableStreamController,0),(!c||!h)&&P(void 0);},_errorSteps:()=>{r=!1;}});}n(nt,"pullWithDefaultReader");function Oe(_,v){Ee(t)&&(ge(t),t=Ro(e),ae(t));const k=v?C:g,Y=v?g:C;Po(t,_,1,{_chunkSteps:it=>{z(()=>{s=!1,l=!1;const at=v?h:c;if(v?c:h)at||Vt(k._readableStreamController,it);else {let si;try{si=uo(it);}catch(vn){K(k._readableStreamController,vn),K(Y._readableStreamController,vn),P(ie(e,vn));return}at||Vt(k._readableStreamController,it),Nt(Y._readableStreamController,si);}r=!1,s?Re():l&&N();});},_closeSteps:it=>{r=!1;const at=v?h:c,fr=v?c:h;at||_t(k._readableStreamController),fr||_t(Y._readableStreamController),it!==void 0&&(at||Vt(k._readableStreamController,it),!fr&&Y._readableStreamController._pendingPullIntos.length>0&&Ht(Y._readableStreamController,0)),(!at||!fr)&&P(void 0);},_errorSteps:()=>{r=!1;}});}n(Oe,"pullWithBYOBReader");function Re(){if(r)return s=!0,S(void 0);r=!0;const _=Hr(g._readableStreamController);return _===null?nt():Oe(_._view,!1),S(void 0)}n(Re,"pull1Algorithm");function N(){if(r)return l=!0,S(void 0);r=!0;const _=Hr(C._readableStreamController);return _===null?nt():Oe(_._view,!0),S(void 0)}n(N,"pull2Algorithm");function H(_){if(c=!0,y=_,h){const v=gt([y,T]),k=ie(e,v);P(k);}return B}n(H,"cancel1Algorithm");function J(_){if(h=!0,T=_,c){const v=gt([y,T]),k=ie(e,v);P(k);}return B}n(J,"cancel2Algorithm");function Te(){}return n(Te,"startAlgorithm"),g=Qo(Te,Re,H),C=Qo(Te,N,J),ae(t),[g,C]}n(Ka,"ReadableByteStreamTee");function Ja(e){return d(e)&&typeof e.getReader<"u"}n(Ja,"isReadableStreamLike");function Xa(e){return Ja(e)?ts(e.getReader()):es(e)}n(Xa,"ReadableStreamFrom");function es(e){let t;const r=so(e,"async"),s=f;function l(){let h;try{h=Hi(r);}catch(T){return m(T)}const y=S(h);return M(y,T=>{if(!d(T))throw new TypeError("The promise returned by the iterator.next() method must fulfill with an object");if(Vi(T))$e(t._readableStreamController);else {const C=Qi(T);Ke(t._readableStreamController,C);}})}n(l,"pullAlgorithm");function c(h){const y=r.iterator;let T;try{T=Mt(y,"return");}catch(P){return m(P)}if(T===void 0)return S(void 0);let g;try{g=j(T,y,[h]);}catch(P){return m(P)}const C=S(g);return M(C,P=>{if(!d(P))throw new TypeError("The promise returned by the iterator.return() method must fulfill with an object")})}return n(c,"cancelAlgorithm"),t=Pt(s,l,c,0),t}n(es,"ReadableStreamFromIterable");function ts(e){let t;const r=f;function s(){let c;try{c=e.read();}catch(h){return m(h)}return M(c,h=>{if(!d(h))throw new TypeError("The promise returned by the reader.read() method must fulfill with an object");if(h.done)$e(t._readableStreamController);else {const y=h.value;Ke(t._readableStreamController,y);}})}n(s,"pullAlgorithm");function l(c){try{return S(e.cancel(c))}catch(h){return m(h)}}return n(l,"cancelAlgorithm"),t=Pt(r,s,l,0),t}n(ts,"ReadableStreamFromDefaultReader");function rs(e,t){le(e,t);const r=e,s=r?.autoAllocateChunkSize,l=r?.cancel,c=r?.pull,h=r?.start,y=r?.type;return {autoAllocateChunkSize:s===void 0?void 0:Fr(s,`${t} has member 'autoAllocateChunkSize' that`),cancel:l===void 0?void 0:ns(l,r,`${t} has member 'cancel' that`),pull:c===void 0?void 0:os(c,r,`${t} has member 'pull' that`),start:h===void 0?void 0:is(h,r,`${t} has member 'start' that`),type:y===void 0?void 0:as(y,`${t} has member 'type' that`)}}n(rs,"convertUnderlyingDefaultOrByteSource");function ns(e,t,r){return Z(e,r),s=>I(e,t,[s])}n(ns,"convertUnderlyingSourceCancelCallback");function os(e,t,r){return Z(e,r),s=>I(e,t,[s])}n(os,"convertUnderlyingSourcePullCallback");function is(e,t,r){return Z(e,r),s=>j(e,t,[s])}n(is,"convertUnderlyingSourceStartCallback");function as(e,t){if(e=`${e}`,e!=="bytes")throw new TypeError(`${t} '${e}' is not a valid enumeration value for ReadableStreamType`);return e}n(as,"convertReadableStreamType");function ss(e,t){return le(e,t),{preventCancel:!!e?.preventCancel}}n(ss,"convertIteratorOptions");function Vo(e,t){le(e,t);const r=e?.preventAbort,s=e?.preventCancel,l=e?.preventClose,c=e?.signal;return c!==void 0&&us(c,`${t} has member 'signal' that`),{preventAbort:!!r,preventCancel:!!s,preventClose:!!l,signal:c}}n(Vo,"convertPipeOptions");function us(e,t){if(!ma(e))throw new TypeError(`${t} is not an AbortSignal.`)}n(us,"assertAbortSignal");function ls(e,t){le(e,t);const r=e?.readable;zr(r,"readable","ReadableWritablePair"),jr(r,`${t} has member 'readable' that`);const s=e?.writable;return zr(s,"writable","ReadableWritablePair"),Eo(s,`${t} has member 'writable' that`),{readable:r,writable:s}}n(ls,"convertReadableWritablePair");const wn=class wn{constructor(t={},r={}){t===void 0?t=null:Gn(t,"First parameter");const s=Gt(r,"Second parameter"),l=rs(t,"First parameter");if(sn(this),l.type==="bytes"){if(s.size!==void 0)throw new RangeError("The strategy for a byte stream cannot have a size function");const c=wt(s,0);na(this,l,c);}else {const c=Yt(s),h=wt(s,1);Ya(this,l,h,c);}}get locked(){if(!We(this))throw De("locked");return qe(this)}cancel(t=void 0){return We(this)?qe(this)?m(new TypeError("Cannot cancel a stream that already has a reader")):ie(this,t):m(De("cancel"))}getReader(t=void 0){if(!We(this))throw De("getReader");return ia(t,"First parameter").mode===void 0?Qe(this):Ro(this)}pipeThrough(t,r={}){if(!We(this))throw De("pipeThrough");_e(t,1,"pipeThrough");const s=ls(t,"First parameter"),l=Vo(r,"Second parameter");if(qe(this))throw new TypeError("ReadableStream.prototype.pipeThrough cannot be used on a locked ReadableStream");if(Ze(s.writable))throw new TypeError("ReadableStream.prototype.pipeThrough cannot be used on a locked WritableStream");const c=xo(this,s.writable,l.preventClose,l.preventAbort,l.preventCancel,l.signal);return ve(c),s.readable}pipeTo(t,r={}){if(!We(this))return m(De("pipeTo"));if(t===void 0)return m("Parameter 1 is required in 'pipeTo'.");if(!Ge(t))return m(new TypeError("ReadableStream.prototype.pipeTo's first argument must be a WritableStream"));let s;try{s=Vo(r,"Second parameter");}catch(l){return m(l)}return qe(this)?m(new TypeError("ReadableStream.prototype.pipeTo cannot be used on a locked ReadableStream")):Ze(t)?m(new TypeError("ReadableStream.prototype.pipeTo cannot be used on a locked WritableStream")):xo(this,t,s.preventClose,s.preventAbort,s.preventCancel,s.signal)}tee(){if(!We(this))throw De("tee");const t=Ga(this);return gt(t)}values(t=void 0){if(!We(this))throw De("values");const r=ss(t,"First parameter");return xi(this,r.preventCancel)}static from(t){return Xa(t)}};n(wn,"ReadableStream");let L=wn;Object.defineProperties(L,{from:{enumerable:!0}}),Object.defineProperties(L.prototype,{cancel:{enumerable:!0},getReader:{enumerable:!0},pipeThrough:{enumerable:!0},pipeTo:{enumerable:!0},tee:{enumerable:!0},values:{enumerable:!0},locked:{enumerable:!0}}),p(L.from,"from"),p(L.prototype.cancel,"cancel"),p(L.prototype.getReader,"getReader"),p(L.prototype.pipeThrough,"pipeThrough"),p(L.prototype.pipeTo,"pipeTo"),p(L.prototype.tee,"tee"),p(L.prototype.values,"values"),typeof u.toStringTag=="symbol"&&Object.defineProperty(L.prototype,u.toStringTag,{value:"ReadableStream",configurable:!0}),typeof u.asyncIterator=="symbol"&&Object.defineProperty(L.prototype,u.asyncIterator,{value:L.prototype.values,writable:!0,configurable:!0});function Pt(e,t,r,s=1,l=()=>1){const c=Object.create(L.prototype);sn(c);const h=Object.create(ne.prototype);return Ho(c,h,e,t,r,s,l),c}n(Pt,"CreateReadableStream");function Qo(e,t,r){const s=Object.create(L.prototype);sn(s);const l=Object.create(te.prototype);return wo(s,l,e,t,r,0,void 0),s}n(Qo,"CreateReadableByteStream");function sn(e){e._state="readable",e._reader=void 0,e._storedError=void 0,e._disturbed=!1;}n(sn,"InitializeReadableStream");function We(e){return !d(e)||!Object.prototype.hasOwnProperty.call(e,"_readableStreamController")?!1:e instanceof L}n(We,"IsReadableStream");function qe(e){return e._reader!==void 0}n(qe,"IsReadableStreamLocked");function ie(e,t){if(e._disturbed=!0,e._state==="closed")return S(void 0);if(e._state==="errored")return m(e._storedError);vt(e);const r=e._reader;if(r!==void 0&&Fe(r)){const l=r._readIntoRequests;r._readIntoRequests=new U,l.forEach(c=>{c._closeSteps(void 0);});}const s=e._readableStreamController[Ar](t);return M(s,f)}n(ie,"ReadableStreamCancel");function vt(e){e._state="closed";const t=e._reader;if(t!==void 0&&(Qn(t),Ee(t))){const r=t._readRequests;t._readRequests=new U,r.forEach(s=>{s._closeSteps();});}}n(vt,"ReadableStreamClose");function Yo(e,t){e._state="errored",e._storedError=t;const r=e._reader;r!==void 0&&(Or(r,t),Ee(r)?Xn(r,t):vo(r,t));}n(Yo,"ReadableStreamError");function De(e){return new TypeError(`ReadableStream.prototype.${e} can only be used on a ReadableStream`)}n(De,"streamBrandCheckException$1");function Go(e,t){le(e,t);const r=e?.highWaterMark;return zr(r,"highWaterMark","QueuingStrategyInit"),{highWaterMark:Ir(r)}}n(Go,"convertQueuingStrategyInit");const Zo=n(e=>e.byteLength,"byteLengthSizeFunction");p(Zo,"size");const Rn=class Rn{constructor(t){_e(t,1,"ByteLengthQueuingStrategy"),t=Go(t,"First parameter"),this._byteLengthQueuingStrategyHighWaterMark=t.highWaterMark;}get highWaterMark(){if(!Jo(this))throw Ko("highWaterMark");return this._byteLengthQueuingStrategyHighWaterMark}get size(){if(!Jo(this))throw Ko("size");return Zo}};n(Rn,"ByteLengthQueuingStrategy");let Xe=Rn;Object.defineProperties(Xe.prototype,{highWaterMark:{enumerable:!0},size:{enumerable:!0}}),typeof u.toStringTag=="symbol"&&Object.defineProperty(Xe.prototype,u.toStringTag,{value:"ByteLengthQueuingStrategy",configurable:!0});function Ko(e){return new TypeError(`ByteLengthQueuingStrategy.prototype.${e} can only be used on a ByteLengthQueuingStrategy`)}n(Ko,"byteLengthBrandCheckException");function Jo(e){return !d(e)||!Object.prototype.hasOwnProperty.call(e,"_byteLengthQueuingStrategyHighWaterMark")?!1:e instanceof Xe}n(Jo,"IsByteLengthQueuingStrategy");const Xo=n(()=>1,"countSizeFunction");p(Xo,"size");const Tn=class Tn{constructor(t){_e(t,1,"CountQueuingStrategy"),t=Go(t,"First parameter"),this._countQueuingStrategyHighWaterMark=t.highWaterMark;}get highWaterMark(){if(!ti(this))throw ei("highWaterMark");return this._countQueuingStrategyHighWaterMark}get size(){if(!ti(this))throw ei("size");return Xo}};n(Tn,"CountQueuingStrategy");let et=Tn;Object.defineProperties(et.prototype,{highWaterMark:{enumerable:!0},size:{enumerable:!0}}),typeof u.toStringTag=="symbol"&&Object.defineProperty(et.prototype,u.toStringTag,{value:"CountQueuingStrategy",configurable:!0});function ei(e){return new TypeError(`CountQueuingStrategy.prototype.${e} can only be used on a CountQueuingStrategy`)}n(ei,"countBrandCheckException");function ti(e){return !d(e)||!Object.prototype.hasOwnProperty.call(e,"_countQueuingStrategyHighWaterMark")?!1:e instanceof et}n(ti,"IsCountQueuingStrategy");function fs(e,t){le(e,t);const r=e?.cancel,s=e?.flush,l=e?.readableType,c=e?.start,h=e?.transform,y=e?.writableType;return {cancel:r===void 0?void 0:ps(r,e,`${t} has member 'cancel' that`),flush:s===void 0?void 0:cs(s,e,`${t} has member 'flush' that`),readableType:l,start:c===void 0?void 0:ds(c,e,`${t} has member 'start' that`),transform:h===void 0?void 0:hs(h,e,`${t} has member 'transform' that`),writableType:y}}n(fs,"convertTransformer");function cs(e,t,r){return Z(e,r),s=>I(e,t,[s])}n(cs,"convertTransformerFlushCallback");function ds(e,t,r){return Z(e,r),s=>j(e,t,[s])}n(ds,"convertTransformerStartCallback");function hs(e,t,r){return Z(e,r),(s,l)=>I(e,t,[s,l])}n(hs,"convertTransformerTransformCallback");function ps(e,t,r){return Z(e,r),s=>I(e,t,[s])}n(ps,"convertTransformerCancelCallback");const Cn=class Cn{constructor(t={},r={},s={}){t===void 0&&(t=null);const l=Gt(r,"Second parameter"),c=Gt(s,"Third parameter"),h=fs(t,"First parameter");if(h.readableType!==void 0)throw new RangeError("Invalid readableType specified");if(h.writableType!==void 0)throw new RangeError("Invalid writableType specified");const y=wt(c,0),T=Yt(c),g=wt(l,1),C=Yt(l);let P;const B=A(ae=>{P=ae;});bs(this,B,g,C,y,T),ys(this,h),h.start!==void 0?P(h.start(this._transformStreamController)):P(void 0);}get readable(){if(!ri(this))throw ai("readable");return this._readable}get writable(){if(!ri(this))throw ai("writable");return this._writable}};n(Cn,"TransformStream");let tt=Cn;Object.defineProperties(tt.prototype,{readable:{enumerable:!0},writable:{enumerable:!0}}),typeof u.toStringTag=="symbol"&&Object.defineProperty(tt.prototype,u.toStringTag,{value:"TransformStream",configurable:!0});function bs(e,t,r,s,l,c){function h(){return t}n(h,"startAlgorithm");function y(B){return Ss(e,B)}n(y,"writeAlgorithm");function T(B){return ws(e,B)}n(T,"abortAlgorithm");function g(){return Rs(e)}n(g,"closeAlgorithm"),e._writable=_a(h,y,g,T,r,s);function C(){return Ts(e)}n(C,"pullAlgorithm");function P(B){return Cs(e,B)}n(P,"cancelAlgorithm"),e._readable=Pt(h,C,P,l,c),e._backpressure=void 0,e._backpressureChangePromise=void 0,e._backpressureChangePromise_resolve=void 0,ar(e,!0),e._transformStreamController=void 0;}n(bs,"InitializeTransformStream");function ri(e){return !d(e)||!Object.prototype.hasOwnProperty.call(e,"_transformStreamController")?!1:e instanceof tt}n(ri,"IsTransformStream");function ni(e,t){oe(e._readable._readableStreamController,t),un(e,t);}n(ni,"TransformStreamError");function un(e,t){ur(e._transformStreamController),Rt(e._writable._writableStreamController,t),ln(e);}n(un,"TransformStreamErrorWritableAndUnblockWrite");function ln(e){e._backpressure&&ar(e,!1);}n(ln,"TransformStreamUnblockWrite");function ar(e,t){e._backpressureChangePromise!==void 0&&e._backpressureChangePromise_resolve(),e._backpressureChangePromise=A(r=>{e._backpressureChangePromise_resolve=r;}),e._backpressure=t;}n(ar,"TransformStreamSetBackpressure");const Pn=class Pn{constructor(){throw new TypeError("Illegal constructor")}get desiredSize(){if(!sr(this))throw lr("desiredSize");const t=this._controlledTransformStream._readable._readableStreamController;return an(t)}enqueue(t=void 0){if(!sr(this))throw lr("enqueue");oi(this,t);}error(t=void 0){if(!sr(this))throw lr("error");gs(this,t);}terminate(){if(!sr(this))throw lr("terminate");_s(this);}};n(Pn,"TransformStreamDefaultController");let pe=Pn;Object.defineProperties(pe.prototype,{enqueue:{enumerable:!0},error:{enumerable:!0},terminate:{enumerable:!0},desiredSize:{enumerable:!0}}),p(pe.prototype.enqueue,"enqueue"),p(pe.prototype.error,"error"),p(pe.prototype.terminate,"terminate"),typeof u.toStringTag=="symbol"&&Object.defineProperty(pe.prototype,u.toStringTag,{value:"TransformStreamDefaultController",configurable:!0});function sr(e){return !d(e)||!Object.prototype.hasOwnProperty.call(e,"_controlledTransformStream")?!1:e instanceof pe}n(sr,"IsTransformStreamDefaultController");function ms(e,t,r,s,l){t._controlledTransformStream=e,e._transformStreamController=t,t._transformAlgorithm=r,t._flushAlgorithm=s,t._cancelAlgorithm=l,t._finishPromise=void 0,t._finishPromise_resolve=void 0,t._finishPromise_reject=void 0;}n(ms,"SetUpTransformStreamDefaultController");function ys(e,t){const r=Object.create(pe.prototype);let s,l,c;t.transform!==void 0?s=n(h=>t.transform(h,r),"transformAlgorithm"):s=n(h=>{try{return oi(r,h),S(void 0)}catch(y){return m(y)}},"transformAlgorithm"),t.flush!==void 0?l=n(()=>t.flush(r),"flushAlgorithm"):l=n(()=>S(void 0),"flushAlgorithm"),t.cancel!==void 0?c=n(h=>t.cancel(h),"cancelAlgorithm"):c=n(()=>S(void 0),"cancelAlgorithm"),ms(e,r,s,l,c);}n(ys,"SetUpTransformStreamDefaultControllerFromTransformer");function ur(e){e._transformAlgorithm=void 0,e._flushAlgorithm=void 0,e._cancelAlgorithm=void 0;}n(ur,"TransformStreamDefaultControllerClearAlgorithms");function oi(e,t){const r=e._controlledTransformStream,s=r._readable._readableStreamController;if(!Je(s))throw new TypeError("Readable side is not in a state that permits enqueue");try{Ke(s,t);}catch(c){throw un(r,c),r._readable._storedError}Qa(s)!==r._backpressure&&ar(r,!0);}n(oi,"TransformStreamDefaultControllerEnqueue");function gs(e,t){ni(e._controlledTransformStream,t);}n(gs,"TransformStreamDefaultControllerError");function ii(e,t){const r=e._transformAlgorithm(t);return M(r,void 0,s=>{throw ni(e._controlledTransformStream,s),s})}n(ii,"TransformStreamDefaultControllerPerformTransform");function _s(e){const t=e._controlledTransformStream,r=t._readable._readableStreamController;$e(r);const s=new TypeError("TransformStream terminated");un(t,s);}n(_s,"TransformStreamDefaultControllerTerminate");function Ss(e,t){const r=e._transformStreamController;if(e._backpressure){const s=e._backpressureChangePromise;return M(s,()=>{const l=e._writable;if(l._state==="erroring")throw l._storedError;return ii(r,t)})}return ii(r,t)}n(Ss,"TransformStreamDefaultSinkWriteAlgorithm");function ws(e,t){const r=e._transformStreamController;if(r._finishPromise!==void 0)return r._finishPromise;const s=e._readable;r._finishPromise=A((c,h)=>{r._finishPromise_resolve=c,r._finishPromise_reject=h;});const l=r._cancelAlgorithm(t);return ur(r),q(l,()=>(s._state==="errored"?rt(r,s._storedError):(oe(s._readableStreamController,t),fn(r)),null),c=>(oe(s._readableStreamController,c),rt(r,c),null)),r._finishPromise}n(ws,"TransformStreamDefaultSinkAbortAlgorithm");function Rs(e){const t=e._transformStreamController;if(t._finishPromise!==void 0)return t._finishPromise;const r=e._readable;t._finishPromise=A((l,c)=>{t._finishPromise_resolve=l,t._finishPromise_reject=c;});const s=t._flushAlgorithm();return ur(t),q(s,()=>(r._state==="errored"?rt(t,r._storedError):($e(r._readableStreamController),fn(t)),null),l=>(oe(r._readableStreamController,l),rt(t,l),null)),t._finishPromise}n(Rs,"TransformStreamDefaultSinkCloseAlgorithm");function Ts(e){return ar(e,!1),e._backpressureChangePromise}n(Ts,"TransformStreamDefaultSourcePullAlgorithm");function Cs(e,t){const r=e._transformStreamController;if(r._finishPromise!==void 0)return r._finishPromise;const s=e._writable;r._finishPromise=A((c,h)=>{r._finishPromise_resolve=c,r._finishPromise_reject=h;});const l=r._cancelAlgorithm(t);return ur(r),q(l,()=>(s._state==="errored"?rt(r,s._storedError):(Rt(s._writableStreamController,t),ln(e),fn(r)),null),c=>(Rt(s._writableStreamController,c),ln(e),rt(r,c),null)),r._finishPromise}n(Cs,"TransformStreamDefaultSourceCancelAlgorithm");function lr(e){return new TypeError(`TransformStreamDefaultController.prototype.${e} can only be used on a TransformStreamDefaultController`)}n(lr,"defaultControllerBrandCheckException");function fn(e){e._finishPromise_resolve!==void 0&&(e._finishPromise_resolve(),e._finishPromise_resolve=void 0,e._finishPromise_reject=void 0);}n(fn,"defaultControllerFinishPromiseResolve");function rt(e,t){e._finishPromise_reject!==void 0&&(ve(e._finishPromise),e._finishPromise_reject(t),e._finishPromise_resolve=void 0,e._finishPromise_reject=void 0);}n(rt,"defaultControllerFinishPromiseReject");function ai(e){return new TypeError(`TransformStream.prototype.${e} can only be used on a TransformStream`)}n(ai,"streamBrandCheckException"),a.ByteLengthQueuingStrategy=Xe,a.CountQueuingStrategy=et,a.ReadableByteStreamController=te,a.ReadableStream=L,a.ReadableStreamBYOBReader=ce,a.ReadableStreamBYOBRequest=we,a.ReadableStreamDefaultController=ne,a.ReadableStreamDefaultReader=fe,a.TransformStream=tt,a.TransformStreamDefaultController=pe,a.WritableStream=de,a.WritableStreamDefaultController=ke,a.WritableStreamDefaultWriter=re;});}(pr,pr.exports)),pr.exports}n(Is,"requirePonyfill_es2018");const Fs=65536;if(!globalThis.ReadableStream)try{const i=require("node:process"),{emitWarning:o}=i;try{i.emitWarning=()=>{},Object.assign(globalThis,require("node:stream/web")),i.emitWarning=o;}catch(a){throw i.emitWarning=o,a}}catch{Object.assign(globalThis,Is());}try{const{Blob:i}=require("buffer");i&&!i.prototype.stream&&(i.prototype.stream=n(function(a){let u=0;const f=this;return new ReadableStream({type:"bytes",async pull(d){const p=await f.slice(u,Math.min(f.size,u+Fs)).arrayBuffer();u+=p.byteLength,d.enqueue(new Uint8Array(p)),u===f.size&&d.close();}})},"name"));}catch{}/*! fetch-blob. MIT License. Jimmy Wärting */const ci=65536;async function*An(i,o=!0){for(const a of i)if("stream"in a)yield*a.stream();else if(ArrayBuffer.isView(a))if(o){let u=a.byteOffset;const f=a.byteOffset+a.byteLength;for(;u!==f;){const d=Math.min(f-u,ci),b=a.buffer.slice(u,u+d);u+=b.byteLength,yield new Uint8Array(b);}}else yield a;else {let u=0,f=a;for(;u!==f.size;){const b=await f.slice(u,Math.min(f.size,u+ci)).arrayBuffer();u+=b.byteLength,yield new Uint8Array(b);}}}n(An,"toIterator");const di=(Ve=class{constructor(o=[],a={}){be(this,Pe,[]);be(this,Wt,"");be(this,bt,0);be(this,Cr,"transparent");if(typeof o!="object"||o===null)throw new TypeError("Failed to construct 'Blob': The provided value cannot be converted to a sequence.");if(typeof o[Symbol.iterator]!="function")throw new TypeError("Failed to construct 'Blob': The object must have a callable @@iterator property.");if(typeof a!="object"&&typeof a!="function")throw new TypeError("Failed to construct 'Blob': parameter 2 cannot convert to dictionary.");a===null&&(a={});const u=new TextEncoder;for(const d of o){let b;ArrayBuffer.isView(d)?b=new Uint8Array(d.buffer.slice(d.byteOffset,d.byteOffset+d.byteLength)):d instanceof ArrayBuffer?b=new Uint8Array(d.slice(0)):d instanceof Ve?b=d:b=u.encode(`${d}`),X(this,bt,O(this,bt)+(ArrayBuffer.isView(b)?b.byteLength:b.size)),O(this,Pe).push(b);}X(this,Cr,`${a.endings===void 0?"transparent":a.endings}`);const f=a.type===void 0?"":String(a.type);X(this,Wt,/^[\x20-\x7E]*$/.test(f)?f:"");}get size(){return O(this,bt)}get type(){return O(this,Wt)}async text(){const o=new TextDecoder;let a="";for await(const u of An(O(this,Pe),!1))a+=o.decode(u,{stream:!0});return a+=o.decode(),a}async arrayBuffer(){const o=new Uint8Array(this.size);let a=0;for await(const u of An(O(this,Pe),!1))o.set(u,a),a+=u.length;return o.buffer}stream(){const o=An(O(this,Pe),!0);return new globalThis.ReadableStream({type:"bytes",async pull(a){const u=await o.next();u.done?a.close():a.enqueue(u.value);},async cancel(){await o.return();}})}slice(o=0,a=this.size,u=""){const{size:f}=this;let d=o<0?Math.max(f+o,0):Math.min(o,f),b=a<0?Math.max(f+a,0):Math.min(a,f);const p=Math.max(b-d,0),E=O(this,Pe),w=[];let D=0;for(const S of E){if(D>=p)break;const m=ArrayBuffer.isView(S)?S.byteLength:S.size;if(d&&m<=d)d-=m,b-=m;else {let R;ArrayBuffer.isView(S)?(R=S.subarray(d,Math.min(m,b)),D+=R.byteLength):(R=S.slice(d,Math.min(m,b)),D+=R.size),b-=m,w.push(R),d=0;}}const A=new Ve([],{type:String(u).toLowerCase()});return X(A,bt,p),X(A,Pe,w),A}get[Symbol.toStringTag](){return "Blob"}static[Symbol.hasInstance](o){return o&&typeof o=="object"&&typeof o.constructor=="function"&&(typeof o.stream=="function"||typeof o.arrayBuffer=="function")&&/^(Blob|File)$/.test(o[Symbol.toStringTag])}},Pe=new WeakMap,Wt=new WeakMap,bt=new WeakMap,Cr=new WeakMap,n(Ve,"Blob"),Ve);Object.defineProperties(di.prototype,{size:{enumerable:!0},type:{enumerable:!0},slice:{enumerable:!0}});const js=di,lt$2=js,Ls=(zt=class extends lt$2{constructor(a,u,f={}){if(arguments.length<2)throw new TypeError(`Failed to construct 'File': 2 arguments required, but only ${arguments.length} present.`);super(a,f);be(this,qt,0);be(this,Ot,"");f===null&&(f={});const d=f.lastModified===void 0?Date.now():Number(f.lastModified);Number.isNaN(d)||X(this,qt,d),X(this,Ot,String(u));}get name(){return O(this,Ot)}get lastModified(){return O(this,qt)}get[Symbol.toStringTag](){return "File"}static[Symbol.hasInstance](a){return !!a&&a instanceof lt$2&&/^(File)$/.test(a[Symbol.toStringTag])}},qt=new WeakMap,Ot=new WeakMap,n(zt,"File"),zt),$s=Ls,Bn=$s;/*! formdata-polyfill. MIT License. Jimmy Wärting */var{toStringTag:At,iterator:Ds,hasInstance:Ms}=Symbol,hi=Math.random,Us="append,set,get,getAll,delete,keys,values,entries,forEach,constructor".split(","),pi=n((i,o,a)=>(i+="",/^(Blob|File)$/.test(o&&o[At])?[(a=a!==void 0?a+"":o[At]=="File"?o.name:"blob",i),o.name!==a||o[At]=="blob"?new Bn([o],a,o):o]:[i,o+""]),"f"),kn=n((i,o)=>(o?i:i.replace(/\r?\n|\r/g,`\r +`)).replace(/\n/g,"%0A").replace(/\r/g,"%0D").replace(/"/g,"%22"),"e$1"),Me=n((i,o,a)=>{if(o.lengthtypeof o[a]!="function")}append(...o){Me("append",arguments,2),O(this,ee).push(pi(...o));}delete(o){Me("delete",arguments,1),o+="",X(this,ee,O(this,ee).filter(([a])=>a!==o));}get(o){Me("get",arguments,1),o+="";for(var a=O(this,ee),u=a.length,f=0;fu[0]===o&&a.push(u[1])),a}has(o){return Me("has",arguments,1),o+="",O(this,ee).some(a=>a[0]===o)}forEach(o,a){Me("forEach",arguments,1);for(var[u,f]of this)o.call(a,f,u,this);}set(...o){Me("set",arguments,2);var a=[],u=!0;o=pi(...o),O(this,ee).forEach(f=>{f[0]===o[0]?u&&(u=!a.push(o)):a.push(f);}),u&&a.push(o),X(this,ee,a);}*entries(){yield*O(this,ee);}*keys(){for(var[o]of this)yield o;}*values(){for(var[,o]of this)yield o;}},ee=new WeakMap,n(It,"FormData"),It);function xs(i,o=lt$2){var a=`${hi()}${hi()}`.replace(/\./g,"").slice(-28).padStart(32,"-"),u=[],f=`--${a}\r +Content-Disposition: form-data; name="`;return i.forEach((d,b)=>typeof d=="string"?u.push(f+kn(b)+`"\r +\r +${d.replace(/\r(?!\n)|(?typeof i=="object"&&typeof i.append=="function"&&typeof i.delete=="function"&&typeof i.get=="function"&&typeof i.getAll=="function"&&typeof i.has=="function"&&typeof i.set=="function"&&typeof i.sort=="function"&&i[mr]==="URLSearchParams","isURLSearchParameters"),yr=n(i=>i&&typeof i=="object"&&typeof i.arrayBuffer=="function"&&typeof i.type=="string"&&typeof i.stream=="function"&&typeof i.constructor=="function"&&/^(Blob|File)$/.test(i[mr]),"isBlob"),Ns=n(i=>typeof i=="object"&&(i[mr]==="AbortSignal"||i[mr]==="EventTarget"),"isAbortSignal"),Hs=n((i,o)=>{const a=new URL(o).hostname,u=new URL(i).hostname;return a===u||a.endsWith(`.${u}`)},"isDomainOrSubdomain"),Vs=n((i,o)=>{const a=new URL(o).protocol,u=new URL(i).protocol;return a===u},"isSameProtocol"),Qs=promisify(me.pipeline),V=Symbol("Body internals"),Dn=class Dn{constructor(o,{size:a=0}={}){let u=null;o===null?o=null:bi(o)?o=Buffer$1.from(o.toString()):yr(o)||Buffer$1.isBuffer(o)||(types.isAnyArrayBuffer(o)?o=Buffer$1.from(o):ArrayBuffer.isView(o)?o=Buffer$1.from(o.buffer,o.byteOffset,o.byteLength):o instanceof me||(o instanceof br?(o=xs(o),u=o.type.split("=")[1]):o=Buffer$1.from(String(o))));let f=o;Buffer$1.isBuffer(o)?f=me.Readable.from(o):yr(o)&&(f=me.Readable.from(o.stream())),this[V]={body:o,stream:f,boundary:u,disturbed:!1,error:null},this.size=a,o instanceof me&&o.on("error",d=>{const b=d instanceof ft?d:new G(`Invalid response body while trying to fetch ${this.url}: ${d.message}`,"system",d);this[V].error=b;});}get body(){return this[V].stream}get bodyUsed(){return this[V].disturbed}async arrayBuffer(){const{buffer:o,byteOffset:a,byteLength:u}=await Wn(this);return o.slice(a,a+u)}async formData(){const o=this.headers.get("content-type");if(o.startsWith("application/x-www-form-urlencoded")){const u=new br,f=new URLSearchParams(await this.text());for(const[d,b]of f)u.append(d,b);return u}const{toFormData:a}=await import('../chunks/multipart-parser.mjs');return a(this.body,o)}async blob(){const o=this.headers&&this.headers.get("content-type")||this[V].body&&this[V].body.type||"",a=await this.arrayBuffer();return new lt$2([a],{type:o})}async json(){const o=await this.text();return JSON.parse(o)}async text(){const o=await Wn(this);return new TextDecoder().decode(o)}buffer(){return Wn(this)}};n(Dn,"Body");let Ue=Dn;Ue.prototype.buffer=deprecate(Ue.prototype.buffer,"Please use 'response.arrayBuffer()' instead of 'response.buffer()'","node-fetch#buffer"),Object.defineProperties(Ue.prototype,{body:{enumerable:!0},bodyUsed:{enumerable:!0},arrayBuffer:{enumerable:!0},blob:{enumerable:!0},json:{enumerable:!0},text:{enumerable:!0},data:{get:deprecate(()=>{},"data doesn't exist, use json(), text(), arrayBuffer(), or body instead","https://github.com/node-fetch/node-fetch/issues/1000 (response)")}});async function Wn(i){if(i[V].disturbed)throw new TypeError(`body used already for: ${i.url}`);if(i[V].disturbed=!0,i[V].error)throw i[V].error;const{body:o}=i;if(o===null)return Buffer$1.alloc(0);if(!(o instanceof me))return Buffer$1.alloc(0);const a=[];let u=0;try{for await(const f of o){if(i.size>0&&u+f.length>i.size){const d=new G(`content size at ${i.url} over limit: ${i.size}`,"max-size");throw o.destroy(d),d}u+=f.length,a.push(f);}}catch(f){throw f instanceof ft?f:new G(`Invalid response body while trying to fetch ${i.url}: ${f.message}`,"system",f)}if(o.readableEnded===!0||o._readableState.ended===!0)try{return a.every(f=>typeof f=="string")?Buffer$1.from(a.join("")):Buffer$1.concat(a,u)}catch(f){throw new G(`Could not create Buffer from response body for ${i.url}: ${f.message}`,"system",f)}else throw new G(`Premature close of server response while trying to fetch ${i.url}`)}n(Wn,"consumeBody");const qn=n((i,o)=>{let a,u,{body:f}=i[V];if(i.bodyUsed)throw new Error("cannot clone body after it is used");return f instanceof me&&typeof f.getBoundary!="function"&&(a=new PassThrough({highWaterMark:o}),u=new PassThrough({highWaterMark:o}),f.pipe(a),f.pipe(u),i[V].stream=a,f=u),f},"clone"),Ys=deprecate(i=>i.getBoundary(),"form-data doesn't follow the spec and requires special treatment. Use alternative package","https://github.com/node-fetch/node-fetch/issues/1167"),mi=n((i,o)=>i===null?null:typeof i=="string"?"text/plain;charset=UTF-8":bi(i)?"application/x-www-form-urlencoded;charset=UTF-8":yr(i)?i.type||null:Buffer$1.isBuffer(i)||types.isAnyArrayBuffer(i)||ArrayBuffer.isView(i)?null:i instanceof br?`multipart/form-data; boundary=${o[V].boundary}`:i&&typeof i.getBoundary=="function"?`multipart/form-data;boundary=${Ys(i)}`:i instanceof me?null:"text/plain;charset=UTF-8","extractContentType"),Gs=n(i=>{const{body:o}=i[V];return o===null?0:yr(o)?o.size:Buffer$1.isBuffer(o)?o.length:o&&typeof o.getLengthSync=="function"&&o.hasKnownLength&&o.hasKnownLength()?o.getLengthSync():null},"getTotalBytes"),Zs=n(async(i,{body:o})=>{o===null?i.end():await Qs(o,i);},"writeToStream"),gr=typeof Et.validateHeaderName=="function"?Et.validateHeaderName:i=>{if(!/^[\^`\-\w!#$%&'*+.|~]+$/.test(i)){const o=new TypeError(`Header name must be a valid HTTP token [${i}]`);throw Object.defineProperty(o,"code",{value:"ERR_INVALID_HTTP_TOKEN"}),o}},On=typeof Et.validateHeaderValue=="function"?Et.validateHeaderValue:(i,o)=>{if(/[^\t\u0020-\u007E\u0080-\u00FF]/.test(o)){const a=new TypeError(`Invalid character in header content ["${i}"]`);throw Object.defineProperty(a,"code",{value:"ERR_INVALID_CHAR"}),a}},Pr=class Pr extends URLSearchParams{constructor(o){let a=[];if(o instanceof Pr){const u=o.raw();for(const[f,d]of Object.entries(u))a.push(...d.map(b=>[f,b]));}else if(o!=null)if(typeof o=="object"&&!types.isBoxedPrimitive(o)){const u=o[Symbol.iterator];if(u==null)a.push(...Object.entries(o));else {if(typeof u!="function")throw new TypeError("Header pairs must be iterable");a=[...o].map(f=>{if(typeof f!="object"||types.isBoxedPrimitive(f))throw new TypeError("Each header pair must be an iterable object");return [...f]}).map(f=>{if(f.length!==2)throw new TypeError("Each header pair must be a name/value tuple");return [...f]});}}else throw new TypeError("Failed to construct 'Headers': The provided value is not of type '(sequence> or record)");return a=a.length>0?a.map(([u,f])=>(gr(u),On(u,String(f)),[String(u).toLowerCase(),String(f)])):void 0,super(a),new Proxy(this,{get(u,f,d){switch(f){case"append":case"set":return (b,p)=>(gr(b),On(b,String(p)),URLSearchParams.prototype[f].call(u,String(b).toLowerCase(),String(p)));case"delete":case"has":case"getAll":return b=>(gr(b),URLSearchParams.prototype[f].call(u,String(b).toLowerCase()));case"keys":return ()=>(u.sort(),new Set(URLSearchParams.prototype.keys.call(u)).keys());default:return Reflect.get(u,f,d)}}})}get[Symbol.toStringTag](){return this.constructor.name}toString(){return Object.prototype.toString.call(this)}get(o){const a=this.getAll(o);if(a.length===0)return null;let u=a.join(", ");return /^content-encoding$/i.test(o)&&(u=u.toLowerCase()),u}forEach(o,a=void 0){for(const u of this.keys())Reflect.apply(o,a,[this.get(u),u,this]);}*values(){for(const o of this.keys())yield this.get(o);}*entries(){for(const o of this.keys())yield [o,this.get(o)];}[Symbol.iterator](){return this.entries()}raw(){return [...this.keys()].reduce((o,a)=>(o[a]=this.getAll(a),o),{})}[Symbol.for("nodejs.util.inspect.custom")](){return [...this.keys()].reduce((o,a)=>{const u=this.getAll(a);return a==="host"?o[a]=u[0]:o[a]=u.length>1?u:u[0],o},{})}};n(Pr,"Headers");let ye=Pr;Object.defineProperties(ye.prototype,["get","entries","forEach","values"].reduce((i,o)=>(i[o]={enumerable:!0},i),{}));function Ks(i=[]){return new ye(i.reduce((o,a,u,f)=>(u%2===0&&o.push(f.slice(u,u+2)),o),[]).filter(([o,a])=>{try{return gr(o),On(o,String(a)),!0}catch{return !1}}))}n(Ks,"fromRawHeaders");const Js=new Set([301,302,303,307,308]),zn=n(i=>Js.has(i),"isRedirect"),se=Symbol("Response internals"),xe=class xe extends Ue{constructor(o=null,a={}){super(o,a);const u=a.status!=null?a.status:200,f=new ye(a.headers);if(o!==null&&!f.has("Content-Type")){const d=mi(o,this);d&&f.append("Content-Type",d);}this[se]={type:"default",url:a.url,status:u,statusText:a.statusText||"",headers:f,counter:a.counter,highWaterMark:a.highWaterMark};}get type(){return this[se].type}get url(){return this[se].url||""}get status(){return this[se].status}get ok(){return this[se].status>=200&&this[se].status<300}get redirected(){return this[se].counter>0}get statusText(){return this[se].statusText}get headers(){return this[se].headers}get highWaterMark(){return this[se].highWaterMark}clone(){return new xe(qn(this,this.highWaterMark),{type:this.type,url:this.url,status:this.status,statusText:this.statusText,headers:this.headers,ok:this.ok,redirected:this.redirected,size:this.size,highWaterMark:this.highWaterMark})}static redirect(o,a=302){if(!zn(a))throw new RangeError('Failed to execute "redirect" on "response": Invalid status code');return new xe(null,{headers:{location:new URL(o).toString()},status:a})}static error(){const o=new xe(null,{status:0,statusText:""});return o[se].type="error",o}static json(o=void 0,a={}){const u=JSON.stringify(o);if(u===void 0)throw new TypeError("data is not JSON serializable");const f=new ye(a&&a.headers);return f.has("content-type")||f.set("content-type","application/json"),new xe(u,{...a,headers:f})}get[Symbol.toStringTag](){return "Response"}};n(xe,"Response");let ue=xe;Object.defineProperties(ue.prototype,{type:{enumerable:!0},url:{enumerable:!0},status:{enumerable:!0},ok:{enumerable:!0},redirected:{enumerable:!0},statusText:{enumerable:!0},headers:{enumerable:!0},clone:{enumerable:!0}});const Xs=n(i=>{if(i.search)return i.search;const o=i.href.length-1,a=i.hash||(i.href[o]==="#"?"#":"");return i.href[o-a.length]==="?"?"?":""},"getSearch");function yi(i,o=!1){return i==null||(i=new URL(i),/^(about|blob|data):$/.test(i.protocol))?"no-referrer":(i.username="",i.password="",i.hash="",o&&(i.pathname="",i.search=""),i)}n(yi,"stripURLForUseAsAReferrer");const gi=new Set(["","no-referrer","no-referrer-when-downgrade","same-origin","origin","strict-origin","origin-when-cross-origin","strict-origin-when-cross-origin","unsafe-url"]),eu="strict-origin-when-cross-origin";function tu(i){if(!gi.has(i))throw new TypeError(`Invalid referrerPolicy: ${i}`);return i}n(tu,"validateReferrerPolicy");function ru(i){if(/^(http|ws)s:$/.test(i.protocol))return !0;const o=i.host.replace(/(^\[)|(]$)/g,""),a=isIP(o);return a===4&&/^127\./.test(o)||a===6&&/^(((0+:){7})|(::(0+:){0,6}))0*1$/.test(o)?!0:i.host==="localhost"||i.host.endsWith(".localhost")?!1:i.protocol==="file:"}n(ru,"isOriginPotentiallyTrustworthy");function ct(i){return /^about:(blank|srcdoc)$/.test(i)||i.protocol==="data:"||/^(blob|filesystem):$/.test(i.protocol)?!0:ru(i)}n(ct,"isUrlPotentiallyTrustworthy");function nu(i,{referrerURLCallback:o,referrerOriginCallback:a}={}){if(i.referrer==="no-referrer"||i.referrerPolicy==="")return null;const u=i.referrerPolicy;if(i.referrer==="about:client")return "no-referrer";const f=i.referrer;let d=yi(f),b=yi(f,!0);d.toString().length>4096&&(d=b),o&&(d=o(d)),a&&(b=a(b));const p=new URL(i.url);switch(u){case"no-referrer":return "no-referrer";case"origin":return b;case"unsafe-url":return d;case"strict-origin":return ct(d)&&!ct(p)?"no-referrer":b.toString();case"strict-origin-when-cross-origin":return d.origin===p.origin?d:ct(d)&&!ct(p)?"no-referrer":b;case"same-origin":return d.origin===p.origin?d:"no-referrer";case"origin-when-cross-origin":return d.origin===p.origin?d:b;case"no-referrer-when-downgrade":return ct(d)&&!ct(p)?"no-referrer":d;default:throw new TypeError(`Invalid referrerPolicy: ${u}`)}}n(nu,"determineRequestsReferrer");function ou(i){const o=(i.get("referrer-policy")||"").split(/[,\s]+/);let a="";for(const u of o)u&&gi.has(u)&&(a=u);return a}n(ou,"parseReferrerPolicyFromHeader");const $=Symbol("Request internals"),Bt=n(i=>typeof i=="object"&&typeof i[$]=="object","isRequest"),iu=deprecate(()=>{},".data is not a valid RequestInit property, use .body instead","https://github.com/node-fetch/node-fetch/issues/1000 (request)"),vr=class vr extends Ue{constructor(o,a={}){let u;if(Bt(o)?u=new URL(o.url):(u=new URL(o),o={}),u.username!==""||u.password!=="")throw new TypeError(`${u} is an url with embedded credentials.`);let f=a.method||o.method||"GET";if(/^(delete|get|head|options|post|put)$/i.test(f)&&(f=f.toUpperCase()),!Bt(a)&&"data"in a&&iu(),(a.body!=null||Bt(o)&&o.body!==null)&&(f==="GET"||f==="HEAD"))throw new TypeError("Request with GET/HEAD method cannot have body");const d=a.body?a.body:Bt(o)&&o.body!==null?qn(o):null;super(d,{size:a.size||o.size||0});const b=new ye(a.headers||o.headers||{});if(d!==null&&!b.has("Content-Type")){const w=mi(d,this);w&&b.set("Content-Type",w);}let p=Bt(o)?o.signal:null;if("signal"in a&&(p=a.signal),p!=null&&!Ns(p))throw new TypeError("Expected signal to be an instanceof AbortSignal or EventTarget");let E=a.referrer==null?o.referrer:a.referrer;if(E==="")E="no-referrer";else if(E){const w=new URL(E);E=/^about:(\/\/)?client$/.test(w)?"client":w;}else E=void 0;this[$]={method:f,redirect:a.redirect||o.redirect||"follow",headers:b,parsedURL:u,signal:p,referrer:E},this.follow=a.follow===void 0?o.follow===void 0?20:o.follow:a.follow,this.compress=a.compress===void 0?o.compress===void 0?!0:o.compress:a.compress,this.counter=a.counter||o.counter||0,this.agent=a.agent||o.agent,this.highWaterMark=a.highWaterMark||o.highWaterMark||16384,this.insecureHTTPParser=a.insecureHTTPParser||o.insecureHTTPParser||!1,this.referrerPolicy=a.referrerPolicy||o.referrerPolicy||"";}get method(){return this[$].method}get url(){return format(this[$].parsedURL)}get headers(){return this[$].headers}get redirect(){return this[$].redirect}get signal(){return this[$].signal}get referrer(){if(this[$].referrer==="no-referrer")return "";if(this[$].referrer==="client")return "about:client";if(this[$].referrer)return this[$].referrer.toString()}get referrerPolicy(){return this[$].referrerPolicy}set referrerPolicy(o){this[$].referrerPolicy=tu(o);}clone(){return new vr(this)}get[Symbol.toStringTag](){return "Request"}};n(vr,"Request");let dt=vr;Object.defineProperties(dt.prototype,{method:{enumerable:!0},url:{enumerable:!0},headers:{enumerable:!0},redirect:{enumerable:!0},clone:{enumerable:!0},signal:{enumerable:!0},referrer:{enumerable:!0},referrerPolicy:{enumerable:!0}});const au=n(i=>{const{parsedURL:o}=i[$],a=new ye(i[$].headers);a.has("Accept")||a.set("Accept","*/*");let u=null;if(i.body===null&&/^(post|put)$/i.test(i.method)&&(u="0"),i.body!==null){const p=Gs(i);typeof p=="number"&&!Number.isNaN(p)&&(u=String(p));}u&&a.set("Content-Length",u),i.referrerPolicy===""&&(i.referrerPolicy=eu),i.referrer&&i.referrer!=="no-referrer"?i[$].referrer=nu(i):i[$].referrer="no-referrer",i[$].referrer instanceof URL&&a.set("Referer",i.referrer),a.has("User-Agent")||a.set("User-Agent","node-fetch"),i.compress&&!a.has("Accept-Encoding")&&a.set("Accept-Encoding","gzip, deflate, br");let{agent:f}=i;typeof f=="function"&&(f=f(o));const d=Xs(o),b={path:o.pathname+d,method:i.method,headers:a[Symbol.for("nodejs.util.inspect.custom")](),insecureHTTPParser:i.insecureHTTPParser,agent:f};return {parsedURL:o,options:b}},"getNodeRequestOptions"),Mn=class Mn extends ft{constructor(o,a="aborted"){super(o,a);}};n(Mn,"AbortError");let _r=Mn;/*! node-domexception. MIT License. Jimmy Wärting */if(!globalThis.DOMException)try{const{MessageChannel:i}=require("worker_threads"),o=new i().port1,a=new ArrayBuffer;o.postMessage(a,[a,a]);}catch(i){i.constructor.name==="DOMException"&&(globalThis.DOMException=i.constructor);}var su=globalThis.DOMException;const uu=f$1(su),{stat:In}=promises;n((i,o)=>_i(statSync(i),i,o),"blobFromSync");n((i,o)=>In(i).then(a=>_i(a,i,o)),"blobFrom");n((i,o)=>In(i).then(a=>Si(a,i,o)),"fileFrom");n((i,o)=>Si(statSync(i),i,o),"fileFromSync");const _i=n((i,o,a="")=>new lt$2([new Sr({path:o,size:i.size,lastModified:i.mtimeMs,start:0})],{type:a}),"fromBlob"),Si=n((i,o,a="")=>new Bn([new Sr({path:o,size:i.size,lastModified:i.mtimeMs,start:0})],basename(o),{type:a,lastModified:i.mtimeMs}),"fromFile"),Er=class Er{constructor(o){be(this,Ne,void 0);be(this,He,void 0);X(this,Ne,o.path),X(this,He,o.start),this.size=o.size,this.lastModified=o.lastModified;}slice(o,a){return new Er({path:O(this,Ne),lastModified:this.lastModified,size:a-o,start:O(this,He)+o})}async*stream(){const{mtimeMs:o}=await In(O(this,Ne));if(o>this.lastModified)throw new uu("The requested file could not be read, typically due to permission problems that have occurred after a reference to a file was acquired.","NotReadableError");yield*createReadStream(O(this,Ne),{start:O(this,He),end:O(this,He)+this.size-1});}get[Symbol.toStringTag](){return "Blob"}};Ne=new WeakMap,He=new WeakMap,n(Er,"BlobDataItem");let Sr=Er;const hu=new Set(["data:","http:","https:"]);async function wi(i,o){return new Promise((a,u)=>{const f=new dt(i,o),{parsedURL:d,options:b}=au(f);if(!hu.has(d.protocol))throw new TypeError(`node-fetch cannot load ${i}. URL scheme "${d.protocol.replace(/:$/,"")}" is not supported.`);if(d.protocol==="data:"){const R=zs(f.url),q=new ue(R,{headers:{"Content-Type":R.typeFull}});a(q);return}const p=(d.protocol==="https:"?https:Et).request,{signal:E}=f;let w=null;const D=n(()=>{const R=new _r("The operation was aborted.");u(R),f.body&&f.body instanceof me.Readable&&f.body.destroy(R),!(!w||!w.body)&&w.body.emit("error",R);},"abort");if(E&&E.aborted){D();return}const A=n(()=>{D(),m();},"abortAndFinalize"),S=p(d.toString(),b);E&&E.addEventListener("abort",A);const m=n(()=>{S.abort(),E&&E.removeEventListener("abort",A);},"finalize");S.on("error",R=>{u(new G(`request to ${f.url} failed, reason: ${R.message}`,"system",R)),m();}),pu(S,R=>{w&&w.body&&w.body.destroy(R);}),process.version<"v14"&&S.on("socket",R=>{let q;R.prependListener("end",()=>{q=R._eventsCount;}),R.prependListener("close",F=>{if(w&&q{S.setTimeout(0);const q=Ks(R.rawHeaders);if(zn(R.statusCode)){const z=q.get("Location");let j=null;try{j=z===null?null:new URL(z,f.url);}catch{if(f.redirect!=="manual"){u(new G(`uri requested responds with an invalid redirect URL: ${z}`,"invalid-redirect")),m();return}}switch(f.redirect){case"error":u(new G(`uri requested responds with a redirect, redirect mode is set to error: ${f.url}`,"no-redirect")),m();return;case"manual":break;case"follow":{if(j===null)break;if(f.counter>=f.follow){u(new G(`maximum redirect reached at: ${f.url}`,"max-redirect")),m();return}const I={headers:new ye(f.headers),follow:f.follow,counter:f.counter+1,agent:f.agent,compress:f.compress,method:f.method,body:qn(f),signal:f.signal,size:f.size,referrer:f.referrer,referrerPolicy:f.referrerPolicy};if(!Hs(f.url,j)||!Vs(f.url,j))for(const U of ["authorization","www-authenticate","cookie","cookie2"])I.headers.delete(U);if(R.statusCode!==303&&f.body&&o.body instanceof me.Readable){u(new G("Cannot follow redirect with body being a readable stream","unsupported-redirect")),m();return}(R.statusCode===303||(R.statusCode===301||R.statusCode===302)&&f.method==="POST")&&(I.method="GET",I.body=void 0,I.headers.delete("content-length"));const mt=ou(q);mt&&(I.referrerPolicy=mt),a(wi(new dt(j,I))),m();return}default:return u(new TypeError(`Redirect option '${f.redirect}' is not a valid value of RequestRedirect`))}}E&&R.once("end",()=>{E.removeEventListener("abort",A);});let F=pipeline(R,new PassThrough,z=>{z&&u(z);});process.version<"v12.10"&&R.on("aborted",A);const Q={url:f.url,status:R.statusCode,statusText:R.statusMessage,headers:q,size:f.size,counter:f.counter,highWaterMark:f.highWaterMark},M=q.get("Content-Encoding");if(!f.compress||f.method==="HEAD"||M===null||R.statusCode===204||R.statusCode===304){w=new ue(F,Q),a(w);return}const ve={flush:st.Z_SYNC_FLUSH,finishFlush:st.Z_SYNC_FLUSH};if(M==="gzip"||M==="x-gzip"){F=pipeline(F,st.createGunzip(ve),z=>{z&&u(z);}),w=new ue(F,Q),a(w);return}if(M==="deflate"||M==="x-deflate"){const z=pipeline(R,new PassThrough,j=>{j&&u(j);});z.once("data",j=>{(j[0]&15)===8?F=pipeline(F,st.createInflate(),I=>{I&&u(I);}):F=pipeline(F,st.createInflateRaw(),I=>{I&&u(I);}),w=new ue(F,Q),a(w);}),z.once("end",()=>{w||(w=new ue(F,Q),a(w));});return}if(M==="br"){F=pipeline(F,st.createBrotliDecompress(),z=>{z&&u(z);}),w=new ue(F,Q),a(w);return}w=new ue(F,Q),a(w);}),Zs(S,f).catch(u);})}n(wi,"fetch$1");function pu(i,o){const a=Buffer$1.from(`0\r +\r +`);let u=!1,f=!1,d;i.on("response",b=>{const{headers:p}=b;u=p["transfer-encoding"]==="chunked"&&!p["content-length"];}),i.on("socket",b=>{const p=n(()=>{if(u&&!f){const w=new Error("Premature close");w.code="ERR_STREAM_PREMATURE_CLOSE",o(w);}},"onSocketClose"),E=n(w=>{f=Buffer$1.compare(w.slice(-5),a)===0,!f&&d&&(f=Buffer$1.compare(d.slice(-3),a.slice(0,3))===0&&Buffer$1.compare(w.slice(-2),a.slice(3))===0),d=w;},"onData");b.prependListener("close",p),b.on("data",E),i.on("close",()=>{b.removeListener("close",p),b.removeListener("data",E);});});}n(pu,"fixResponseChunkedTransferBadEnding");const Ri=new WeakMap,Fn=new WeakMap;function W(i){const o=Ri.get(i);return console.assert(o!=null,"'this' is expected an Event object, but got",i),o}n(W,"pd");function Ti(i){if(i.passiveListener!=null){typeof console<"u"&&typeof console.error=="function"&&console.error("Unable to preventDefault inside passive event listener invocation.",i.passiveListener);return}i.event.cancelable&&(i.canceled=!0,typeof i.event.preventDefault=="function"&&i.event.preventDefault());}n(Ti,"setCancelFlag");function ht(i,o){Ri.set(this,{eventTarget:i,event:o,eventPhase:2,currentTarget:i,canceled:!1,stopped:!1,immediateStopped:!1,passiveListener:null,timeStamp:o.timeStamp||Date.now()}),Object.defineProperty(this,"isTrusted",{value:!1,enumerable:!0});const a=Object.keys(o);for(let u=0;u0){const i=new Array(arguments.length);for(let o=0;oCu(i,"name",{value:o,configurable:!0}),"e");const zi=wi;Ii();function Ii(){!globalThis.process?.versions?.node&&!globalThis.process?.env.DISABLE_NODE_FETCH_NATIVE_WARN&&console.warn("[node-fetch-native] Node.js compatible build of `node-fetch-native` is being used in a non-Node.js environment. Please make sure you are using proper export conditions or report this issue to https://github.com/unjs/node-fetch-native. You can set `process.env.DISABLE_NODE_FETCH_NATIVE_WARN` to disable this warning.");}n(Ii,"s"),Pu(Ii,"checkNodeEnvironment"); + +var a=Object.defineProperty;var t$1=(e,r)=>a(e,"name",{value:r,configurable:!0});var f=Object.defineProperty,g=t$1((e,r)=>f(e,"name",{value:r,configurable:!0}),"e");const o=!!globalThis.process?.env?.FORCE_NODE_FETCH;function l(){return !o&&globalThis.fetch?globalThis.fetch:zi}t$1(l,"p"),g(l,"_getFetch");const s=l(),d=!o&&globalThis.Headers||ye,A=!o&&globalThis.AbortController||jn; + +class FetchError extends Error { + constructor(message, opts) { + super(message, opts); + this.name = "FetchError"; + if (opts?.cause && !this.cause) { + this.cause = opts.cause; + } + } +} +function createFetchError(ctx) { + const errorMessage = ctx.error?.message || ctx.error?.toString() || ""; + const method = ctx.request?.method || ctx.options?.method || "GET"; + const url = ctx.request?.url || String(ctx.request) || "/"; + const requestStr = `[${method}] ${JSON.stringify(url)}`; + const statusStr = ctx.response ? `${ctx.response.status} ${ctx.response.statusText}` : ""; + const message = `${requestStr}: ${statusStr}${errorMessage ? ` ${errorMessage}` : ""}`; + const fetchError = new FetchError( + message, + ctx.error ? { cause: ctx.error } : void 0 + ); + for (const key of ["request", "options", "response"]) { + Object.defineProperty(fetchError, key, { + get() { + return ctx[key]; + } + }); + } + for (const [key, refKey] of [ + ["data", "_data"], + ["status", "status"], + ["statusCode", "status"], + ["statusText", "statusText"], + ["statusMessage", "statusText"] + ]) { + Object.defineProperty(fetchError, key, { + get() { + return ctx.response && ctx.response[refKey]; + } + }); + } + return fetchError; +} + +const payloadMethods = new Set( + Object.freeze(["PATCH", "POST", "PUT", "DELETE"]) +); +function isPayloadMethod(method = "GET") { + return payloadMethods.has(method.toUpperCase()); +} +function isJSONSerializable(value) { + if (value === void 0) { + return false; + } + const t = typeof value; + if (t === "string" || t === "number" || t === "boolean" || t === null) { + return true; + } + if (t !== "object") { + return false; + } + if (Array.isArray(value)) { + return true; + } + if (value.buffer) { + return false; + } + return value.constructor && value.constructor.name === "Object" || typeof value.toJSON === "function"; +} +const textTypes = /* @__PURE__ */ new Set([ + "image/svg", + "application/xml", + "application/xhtml", + "application/html" +]); +const JSON_RE = /^application\/(?:[\w!#$%&*.^`~-]*\+)?json(;.+)?$/i; +function detectResponseType(_contentType = "") { + if (!_contentType) { + return "json"; + } + const contentType = _contentType.split(";").shift() || ""; + if (JSON_RE.test(contentType)) { + return "json"; + } + if (textTypes.has(contentType) || contentType.startsWith("text/")) { + return "text"; + } + return "blob"; +} +function mergeFetchOptions(input, defaults, Headers = globalThis.Headers) { + const merged = { + ...defaults, + ...input + }; + if (defaults?.params && input?.params) { + merged.params = { + ...defaults?.params, + ...input?.params + }; + } + if (defaults?.query && input?.query) { + merged.query = { + ...defaults?.query, + ...input?.query + }; + } + if (defaults?.headers && input?.headers) { + merged.headers = new Headers(defaults?.headers || {}); + for (const [key, value] of new Headers(input?.headers || {})) { + merged.headers.set(key, value); + } + } + return merged; +} + +const retryStatusCodes = /* @__PURE__ */ new Set([ + 408, + // Request Timeout + 409, + // Conflict + 425, + // Too Early + 429, + // Too Many Requests + 500, + // Internal Server Error + 502, + // Bad Gateway + 503, + // Service Unavailable + 504 + // Gateway Timeout +]); +const nullBodyResponses = /* @__PURE__ */ new Set([101, 204, 205, 304]); +function createFetch(globalOptions = {}) { + const { + fetch = globalThis.fetch, + Headers = globalThis.Headers, + AbortController = globalThis.AbortController + } = globalOptions; + async function onError(context) { + const isAbort = context.error && context.error.name === "AbortError" && !context.options.timeout || false; + if (context.options.retry !== false && !isAbort) { + let retries; + if (typeof context.options.retry === "number") { + retries = context.options.retry; + } else { + retries = isPayloadMethod(context.options.method) ? 0 : 1; + } + const responseCode = context.response && context.response.status || 500; + if (retries > 0 && (Array.isArray(context.options.retryStatusCodes) ? context.options.retryStatusCodes.includes(responseCode) : retryStatusCodes.has(responseCode))) { + const retryDelay = context.options.retryDelay || 0; + if (retryDelay > 0) { + await new Promise((resolve) => setTimeout(resolve, retryDelay)); + } + return $fetchRaw(context.request, { + ...context.options, + retry: retries - 1, + timeout: context.options.timeout + }); + } + } + const error = createFetchError(context); + if (Error.captureStackTrace) { + Error.captureStackTrace(error, $fetchRaw); + } + throw error; + } + const $fetchRaw = async function $fetchRaw2(_request, _options = {}) { + const context = { + request: _request, + options: mergeFetchOptions(_options, globalOptions.defaults, Headers), + response: void 0, + error: void 0 + }; + context.options.method = context.options.method?.toUpperCase(); + if (context.options.onRequest) { + await context.options.onRequest(context); + } + if (typeof context.request === "string") { + if (context.options.baseURL) { + context.request = withBase(context.request, context.options.baseURL); + } + if (context.options.query || context.options.params) { + context.request = withQuery(context.request, { + ...context.options.params, + ...context.options.query + }); + } + } + if (context.options.body && isPayloadMethod(context.options.method)) { + if (isJSONSerializable(context.options.body)) { + context.options.body = typeof context.options.body === "string" ? context.options.body : JSON.stringify(context.options.body); + context.options.headers = new Headers(context.options.headers || {}); + if (!context.options.headers.has("content-type")) { + context.options.headers.set("content-type", "application/json"); + } + if (!context.options.headers.has("accept")) { + context.options.headers.set("accept", "application/json"); + } + } else if ( + // ReadableStream Body + "pipeTo" in context.options.body && typeof context.options.body.pipeTo === "function" || // Node.js Stream Body + typeof context.options.body.pipe === "function" + ) { + if (!("duplex" in context.options)) { + context.options.duplex = "half"; + } + } + } + if (!context.options.signal && context.options.timeout) { + const controller = new AbortController(); + setTimeout(() => controller.abort(), context.options.timeout); + context.options.signal = controller.signal; + } + try { + context.response = await fetch( + context.request, + context.options + ); + } catch (error) { + context.error = error; + if (context.options.onRequestError) { + await context.options.onRequestError(context); + } + return await onError(context); + } + const hasBody = context.response.body && !nullBodyResponses.has(context.response.status) && context.options.method !== "HEAD"; + if (hasBody) { + const responseType = (context.options.parseResponse ? "json" : context.options.responseType) || detectResponseType(context.response.headers.get("content-type") || ""); + switch (responseType) { + case "json": { + const data = await context.response.text(); + const parseFunction = context.options.parseResponse || destr; + context.response._data = parseFunction(data); + break; + } + case "stream": { + context.response._data = context.response.body; + break; + } + default: { + context.response._data = await context.response[responseType](); + } + } + } + if (context.options.onResponse) { + await context.options.onResponse(context); + } + if (!context.options.ignoreResponseError && context.response.status >= 400 && context.response.status < 600) { + if (context.options.onResponseError) { + await context.options.onResponseError(context); + } + return await onError(context); + } + return context.response; + }; + const $fetch = async function $fetch2(request, options) { + const r = await $fetchRaw(request, options); + return r._data; + }; + $fetch.raw = $fetchRaw; + $fetch.native = (...args) => fetch(...args); + $fetch.create = (defaultOptions = {}) => createFetch({ + ...globalOptions, + defaults: { + ...globalOptions.defaults, + ...defaultOptions + } + }); + return $fetch; +} + +function createNodeFetch() { + const useKeepAlive = JSON.parse(process.env.FETCH_KEEP_ALIVE || "false"); + if (!useKeepAlive) { + return s; + } + const agentOptions = { keepAlive: true }; + const httpAgent = new Et.Agent(agentOptions); + const httpsAgent = new https.Agent(agentOptions); + const nodeFetchOptions = { + agent(parsedURL) { + return parsedURL.protocol === "http:" ? httpAgent : httpsAgent; + } + }; + return function nodeFetchWithKeepAlive(input, init) { + return s(input, { ...nodeFetchOptions, ...init }); + }; +} +const fetch = globalThis.fetch || createNodeFetch(); +const Headers = globalThis.Headers || d; +const AbortController$1 = globalThis.AbortController || A; +const ofetch = createFetch({ fetch, Headers, AbortController: AbortController$1 }); +const $fetch = ofetch; + +const SemVer$b = semver$1; +const parse$6 = (version, options, throwErrors = false) => { + if (version instanceof SemVer$b) { + return version + } + try { + return new SemVer$b(version, options) + } catch (er) { + if (!throwErrors) { + return null + } + throw er + } +}; + +var parse_1 = parse$6; + +const parse$5 = parse_1; +const valid$2 = (version, options) => { + const v = parse$5(version, options); + return v ? v.version : null +}; +var valid_1 = valid$2; + +const parse$4 = parse_1; +const clean$1 = (version, options) => { + const s = parse$4(version.trim().replace(/^[=v]+/, ''), options); + return s ? s.version : null +}; +var clean_1 = clean$1; + +const SemVer$a = semver$1; + +const inc$1 = (version, release, options, identifier, identifierBase) => { + if (typeof (options) === 'string') { + identifierBase = identifier; + identifier = options; + options = undefined; + } + + try { + return new SemVer$a( + version instanceof SemVer$a ? version.version : version, + options + ).inc(release, identifier, identifierBase).version + } catch (er) { + return null + } +}; +var inc_1 = inc$1; + +const parse$3 = parse_1; + +const diff$1 = (version1, version2) => { + const v1 = parse$3(version1, null, true); + const v2 = parse$3(version2, null, true); + const comparison = v1.compare(v2); + + if (comparison === 0) { + return null + } + + const v1Higher = comparison > 0; + const highVersion = v1Higher ? v1 : v2; + const lowVersion = v1Higher ? v2 : v1; + const highHasPre = !!highVersion.prerelease.length; + const lowHasPre = !!lowVersion.prerelease.length; + + if (lowHasPre && !highHasPre) { + // Going from prerelease -> no prerelease requires some special casing + + // If the low version has only a major, then it will always be a major + // Some examples: + // 1.0.0-1 -> 1.0.0 + // 1.0.0-1 -> 1.1.1 + // 1.0.0-1 -> 2.0.0 + if (!lowVersion.patch && !lowVersion.minor) { + return 'major' + } + + // Otherwise it can be determined by checking the high version + + if (highVersion.patch) { + // anything higher than a patch bump would result in the wrong version + return 'patch' + } + + if (highVersion.minor) { + // anything higher than a minor bump would result in the wrong version + return 'minor' + } + + // bumping major/minor/patch all have same result + return 'major' + } + + // add the `pre` prefix if we are going to a prerelease version + const prefix = highHasPre ? 'pre' : ''; + + if (v1.major !== v2.major) { + return prefix + 'major' + } + + if (v1.minor !== v2.minor) { + return prefix + 'minor' + } + + if (v1.patch !== v2.patch) { + return prefix + 'patch' + } + + // high and low are preleases + return 'prerelease' +}; + +var diff_1 = diff$1; + +const SemVer$9 = semver$1; +const major$1 = (a, loose) => new SemVer$9(a, loose).major; +var major_1 = major$1; + +const SemVer$8 = semver$1; +const minor$1 = (a, loose) => new SemVer$8(a, loose).minor; +var minor_1 = minor$1; + +const SemVer$7 = semver$1; +const patch$1 = (a, loose) => new SemVer$7(a, loose).patch; +var patch_1 = patch$1; + +const parse$2 = parse_1; +const prerelease$1 = (version, options) => { + const parsed = parse$2(version, options); + return (parsed && parsed.prerelease.length) ? parsed.prerelease : null +}; +var prerelease_1 = prerelease$1; + +const compare$4 = compare_1; +const rcompare$1 = (a, b, loose) => compare$4(b, a, loose); +var rcompare_1 = rcompare$1; + +const compare$3 = compare_1; +const compareLoose$1 = (a, b) => compare$3(a, b, true); +var compareLoose_1 = compareLoose$1; + +const SemVer$6 = semver$1; +const compareBuild$3 = (a, b, loose) => { + const versionA = new SemVer$6(a, loose); + const versionB = new SemVer$6(b, loose); + return versionA.compare(versionB) || versionA.compareBuild(versionB) +}; +var compareBuild_1 = compareBuild$3; + +const compareBuild$2 = compareBuild_1; +const sort$1 = (list, loose) => list.sort((a, b) => compareBuild$2(a, b, loose)); +var sort_1 = sort$1; + +const compareBuild$1 = compareBuild_1; +const rsort$1 = (list, loose) => list.sort((a, b) => compareBuild$1(b, a, loose)); +var rsort_1 = rsort$1; + +const SemVer$5 = semver$1; +const parse$1 = parse_1; +const { safeRe: re, t } = reExports; + +const coerce$1 = (version, options) => { + if (version instanceof SemVer$5) { + return version + } + + if (typeof version === 'number') { + version = String(version); + } + + if (typeof version !== 'string') { + return null + } + + options = options || {}; + + let match = null; + if (!options.rtl) { + match = version.match(options.includePrerelease ? re[t.COERCEFULL] : re[t.COERCE]); + } else { + // Find the right-most coercible string that does not share + // a terminus with a more left-ward coercible string. + // Eg, '1.2.3.4' wants to coerce '2.3.4', not '3.4' or '4' + // With includePrerelease option set, '1.2.3.4-rc' wants to coerce '2.3.4-rc', not '2.3.4' + // + // Walk through the string checking with a /g regexp + // Manually set the index so as to pick up overlapping matches. + // Stop when we get a match that ends at the string end, since no + // coercible string can be more right-ward without the same terminus. + const coerceRtlRegex = options.includePrerelease ? re[t.COERCERTLFULL] : re[t.COERCERTL]; + let next; + while ((next = coerceRtlRegex.exec(version)) && + (!match || match.index + match[0].length !== version.length) + ) { + if (!match || + next.index + next[0].length !== match.index + match[0].length) { + match = next; + } + coerceRtlRegex.lastIndex = next.index + next[1].length + next[2].length; + } + // leave it in a clean state + coerceRtlRegex.lastIndex = -1; + } + + if (match === null) { + return null + } + + const major = match[2]; + const minor = match[3] || '0'; + const patch = match[4] || '0'; + const prerelease = options.includePrerelease && match[5] ? `-${match[5]}` : ''; + const build = options.includePrerelease && match[6] ? `+${match[6]}` : ''; + + return parse$1(`${major}.${minor}.${patch}${prerelease}${build}`, options) +}; +var coerce_1 = coerce$1; + +const Range$8 = requireRange(); + +// Mostly just for testing and legacy API reasons +const toComparators$1 = (range, options) => + new Range$8(range, options).set + .map(comp => comp.map(c => c.value).join(' ').trim().split(' ')); + +var toComparators_1 = toComparators$1; + +const SemVer$4 = semver$1; +const Range$7 = requireRange(); + +const maxSatisfying$1 = (versions, range, options) => { + let max = null; + let maxSV = null; + let rangeObj = null; + try { + rangeObj = new Range$7(range, options); + } catch (er) { + return null + } + versions.forEach((v) => { + if (rangeObj.test(v)) { + // satisfies(v, range, options) + if (!max || maxSV.compare(v) === -1) { + // compare(max, v, true) + max = v; + maxSV = new SemVer$4(max, options); + } + } + }); + return max +}; +var maxSatisfying_1 = maxSatisfying$1; + +const SemVer$3 = semver$1; +const Range$6 = requireRange(); +const minSatisfying$1 = (versions, range, options) => { + let min = null; + let minSV = null; + let rangeObj = null; + try { + rangeObj = new Range$6(range, options); + } catch (er) { + return null + } + versions.forEach((v) => { + if (rangeObj.test(v)) { + // satisfies(v, range, options) + if (!min || minSV.compare(v) === 1) { + // compare(min, v, true) + min = v; + minSV = new SemVer$3(min, options); + } + } + }); + return min +}; +var minSatisfying_1 = minSatisfying$1; + +const SemVer$2 = semver$1; +const Range$5 = requireRange(); +const gt$2 = gt_1; + +const minVersion$1 = (range, loose) => { + range = new Range$5(range, loose); + + let minver = new SemVer$2('0.0.0'); + if (range.test(minver)) { + return minver + } + + minver = new SemVer$2('0.0.0-0'); + if (range.test(minver)) { + return minver + } + + minver = null; + for (let i = 0; i < range.set.length; ++i) { + const comparators = range.set[i]; + + let setMin = null; + comparators.forEach((comparator) => { + // Clone to avoid manipulating the comparator's semver object. + const compver = new SemVer$2(comparator.semver.version); + switch (comparator.operator) { + case '>': + if (compver.prerelease.length === 0) { + compver.patch++; + } else { + compver.prerelease.push(0); + } + compver.raw = compver.format(); + /* fallthrough */ + case '': + case '>=': + if (!setMin || gt$2(compver, setMin)) { + setMin = compver; + } + break + case '<': + case '<=': + /* Ignore maximum versions */ + break + /* istanbul ignore next */ + default: + throw new Error(`Unexpected operation: ${comparator.operator}`) + } + }); + if (setMin && (!minver || gt$2(minver, setMin))) { + minver = setMin; + } + } + + if (minver && range.test(minver)) { + return minver + } + + return null +}; +var minVersion_1 = minVersion$1; + +const Range$4 = requireRange(); +const validRange$1 = (range, options) => { + try { + // Return '*' instead of '' so that truthiness works. + // This will throw if it's invalid anyway + return new Range$4(range, options).range || '*' + } catch (er) { + return null + } +}; +var valid$1 = validRange$1; + +const SemVer$1 = semver$1; +const Comparator$2 = requireComparator(); +const { ANY: ANY$1 } = Comparator$2; +const Range$3 = requireRange(); +const satisfies$3 = satisfies_1; +const gt$1 = gt_1; +const lt$1 = lt_1; +const lte$1 = lte_1; +const gte$1 = gte_1; + +const outside$3 = (version, range, hilo, options) => { + version = new SemVer$1(version, options); + range = new Range$3(range, options); + + let gtfn, ltefn, ltfn, comp, ecomp; + switch (hilo) { + case '>': + gtfn = gt$1; + ltefn = lte$1; + ltfn = lt$1; + comp = '>'; + ecomp = '>='; + break + case '<': + gtfn = lt$1; + ltefn = gte$1; + ltfn = gt$1; + comp = '<'; + ecomp = '<='; + break + default: + throw new TypeError('Must provide a hilo val of "<" or ">"') + } + + // If it satisfies the range it is not outside + if (satisfies$3(version, range, options)) { + return false + } + + // From now on, variable terms are as if we're in "gtr" mode. + // but note that everything is flipped for the "ltr" function. + + for (let i = 0; i < range.set.length; ++i) { + const comparators = range.set[i]; + + let high = null; + let low = null; + + comparators.forEach((comparator) => { + if (comparator.semver === ANY$1) { + comparator = new Comparator$2('>=0.0.0'); + } + high = high || comparator; + low = low || comparator; + if (gtfn(comparator.semver, high.semver, options)) { + high = comparator; + } else if (ltfn(comparator.semver, low.semver, options)) { + low = comparator; + } + }); + + // If the edge version comparator has a operator then our version + // isn't outside it + if (high.operator === comp || high.operator === ecomp) { + return false + } + + // If the lowest version comparator has an operator and our version + // is less than it then it isn't higher than the range + if ((!low.operator || low.operator === comp) && + ltefn(version, low.semver)) { + return false + } else if (low.operator === ecomp && ltfn(version, low.semver)) { + return false + } + } + return true +}; + +var outside_1 = outside$3; + +// Determine if version is greater than all the versions possible in the range. +const outside$2 = outside_1; +const gtr$1 = (version, range, options) => outside$2(version, range, '>', options); +var gtr_1 = gtr$1; + +const outside$1 = outside_1; +// Determine if version is less than all the versions possible in the range +const ltr$1 = (version, range, options) => outside$1(version, range, '<', options); +var ltr_1 = ltr$1; + +const Range$2 = requireRange(); +const intersects$1 = (r1, r2, options) => { + r1 = new Range$2(r1, options); + r2 = new Range$2(r2, options); + return r1.intersects(r2, options) +}; +var intersects_1 = intersects$1; + +// given a set of versions and a range, create a "simplified" range +// that includes the same versions that the original range does +// If the original range is shorter than the simplified one, return that. +const satisfies$2 = satisfies_1; +const compare$2 = compare_1; +var simplify = (versions, range, options) => { + const set = []; + let first = null; + let prev = null; + const v = versions.sort((a, b) => compare$2(a, b, options)); + for (const version of v) { + const included = satisfies$2(version, range, options); + if (included) { + prev = version; + if (!first) { + first = version; + } + } else { + if (prev) { + set.push([first, prev]); + } + prev = null; + first = null; + } + } + if (first) { + set.push([first, null]); + } + + const ranges = []; + for (const [min, max] of set) { + if (min === max) { + ranges.push(min); + } else if (!max && min === v[0]) { + ranges.push('*'); + } else if (!max) { + ranges.push(`>=${min}`); + } else if (min === v[0]) { + ranges.push(`<=${max}`); + } else { + ranges.push(`${min} - ${max}`); + } + } + const simplified = ranges.join(' || '); + const original = typeof range.raw === 'string' ? range.raw : String(range); + return simplified.length < original.length ? simplified : range +}; + +const Range$1 = requireRange(); +const Comparator$1 = requireComparator(); +const { ANY } = Comparator$1; +const satisfies$1 = satisfies_1; +const compare$1 = compare_1; + +// Complex range `r1 || r2 || ...` is a subset of `R1 || R2 || ...` iff: +// - Every simple range `r1, r2, ...` is a null set, OR +// - Every simple range `r1, r2, ...` which is not a null set is a subset of +// some `R1, R2, ...` +// +// Simple range `c1 c2 ...` is a subset of simple range `C1 C2 ...` iff: +// - If c is only the ANY comparator +// - If C is only the ANY comparator, return true +// - Else if in prerelease mode, return false +// - else replace c with `[>=0.0.0]` +// - If C is only the ANY comparator +// - if in prerelease mode, return true +// - else replace C with `[>=0.0.0]` +// - Let EQ be the set of = comparators in c +// - If EQ is more than one, return true (null set) +// - Let GT be the highest > or >= comparator in c +// - Let LT be the lowest < or <= comparator in c +// - If GT and LT, and GT.semver > LT.semver, return true (null set) +// - If any C is a = range, and GT or LT are set, return false +// - If EQ +// - If GT, and EQ does not satisfy GT, return true (null set) +// - If LT, and EQ does not satisfy LT, return true (null set) +// - If EQ satisfies every C, return true +// - Else return false +// - If GT +// - If GT.semver is lower than any > or >= comp in C, return false +// - If GT is >=, and GT.semver does not satisfy every C, return false +// - If GT.semver has a prerelease, and not in prerelease mode +// - If no C has a prerelease and the GT.semver tuple, return false +// - If LT +// - If LT.semver is greater than any < or <= comp in C, return false +// - If LT is <=, and LT.semver does not satisfy every C, return false +// - If GT.semver has a prerelease, and not in prerelease mode +// - If no C has a prerelease and the LT.semver tuple, return false +// - Else return true + +const subset$1 = (sub, dom, options = {}) => { + if (sub === dom) { + return true + } + + sub = new Range$1(sub, options); + dom = new Range$1(dom, options); + let sawNonNull = false; + + OUTER: for (const simpleSub of sub.set) { + for (const simpleDom of dom.set) { + const isSub = simpleSubset(simpleSub, simpleDom, options); + sawNonNull = sawNonNull || isSub !== null; + if (isSub) { + continue OUTER + } + } + // the null set is a subset of everything, but null simple ranges in + // a complex range should be ignored. so if we saw a non-null range, + // then we know this isn't a subset, but if EVERY simple range was null, + // then it is a subset. + if (sawNonNull) { + return false + } + } + return true +}; + +const minimumVersionWithPreRelease = [new Comparator$1('>=0.0.0-0')]; +const minimumVersion = [new Comparator$1('>=0.0.0')]; + +const simpleSubset = (sub, dom, options) => { + if (sub === dom) { + return true + } + + if (sub.length === 1 && sub[0].semver === ANY) { + if (dom.length === 1 && dom[0].semver === ANY) { + return true + } else if (options.includePrerelease) { + sub = minimumVersionWithPreRelease; + } else { + sub = minimumVersion; + } + } + + if (dom.length === 1 && dom[0].semver === ANY) { + if (options.includePrerelease) { + return true + } else { + dom = minimumVersion; + } + } + + const eqSet = new Set(); + let gt, lt; + for (const c of sub) { + if (c.operator === '>' || c.operator === '>=') { + gt = higherGT(gt, c, options); + } else if (c.operator === '<' || c.operator === '<=') { + lt = lowerLT(lt, c, options); + } else { + eqSet.add(c.semver); + } + } + + if (eqSet.size > 1) { + return null + } + + let gtltComp; + if (gt && lt) { + gtltComp = compare$1(gt.semver, lt.semver, options); + if (gtltComp > 0) { + return null + } else if (gtltComp === 0 && (gt.operator !== '>=' || lt.operator !== '<=')) { + return null + } + } + + // will iterate one or zero times + for (const eq of eqSet) { + if (gt && !satisfies$1(eq, String(gt), options)) { + return null + } + + if (lt && !satisfies$1(eq, String(lt), options)) { + return null + } + + for (const c of dom) { + if (!satisfies$1(eq, String(c), options)) { + return false + } + } + + return true + } + + let higher, lower; + let hasDomLT, hasDomGT; + // if the subset has a prerelease, we need a comparator in the superset + // with the same tuple and a prerelease, or it's not a subset + let needDomLTPre = lt && + !options.includePrerelease && + lt.semver.prerelease.length ? lt.semver : false; + let needDomGTPre = gt && + !options.includePrerelease && + gt.semver.prerelease.length ? gt.semver : false; + // exception: <1.2.3-0 is the same as <1.2.3 + if (needDomLTPre && needDomLTPre.prerelease.length === 1 && + lt.operator === '<' && needDomLTPre.prerelease[0] === 0) { + needDomLTPre = false; + } + + for (const c of dom) { + hasDomGT = hasDomGT || c.operator === '>' || c.operator === '>='; + hasDomLT = hasDomLT || c.operator === '<' || c.operator === '<='; + if (gt) { + if (needDomGTPre) { + if (c.semver.prerelease && c.semver.prerelease.length && + c.semver.major === needDomGTPre.major && + c.semver.minor === needDomGTPre.minor && + c.semver.patch === needDomGTPre.patch) { + needDomGTPre = false; + } + } + if (c.operator === '>' || c.operator === '>=') { + higher = higherGT(gt, c, options); + if (higher === c && higher !== gt) { + return false + } + } else if (gt.operator === '>=' && !satisfies$1(gt.semver, String(c), options)) { + return false + } + } + if (lt) { + if (needDomLTPre) { + if (c.semver.prerelease && c.semver.prerelease.length && + c.semver.major === needDomLTPre.major && + c.semver.minor === needDomLTPre.minor && + c.semver.patch === needDomLTPre.patch) { + needDomLTPre = false; + } + } + if (c.operator === '<' || c.operator === '<=') { + lower = lowerLT(lt, c, options); + if (lower === c && lower !== lt) { + return false + } + } else if (lt.operator === '<=' && !satisfies$1(lt.semver, String(c), options)) { + return false + } + } + if (!c.operator && (lt || gt) && gtltComp !== 0) { + return false + } + } + + // if there was a < or >, and nothing in the dom, then must be false + // UNLESS it was limited by another range in the other direction. + // Eg, >1.0.0 <1.0.1 is still a subset of <2.0.0 + if (gt && hasDomLT && !lt && gtltComp !== 0) { + return false + } + + if (lt && hasDomGT && !gt && gtltComp !== 0) { + return false + } + + // we needed a prerelease range in a specific tuple, but didn't get one + // then this isn't a subset. eg >=1.2.3-pre is not a subset of >=1.0.0, + // because it includes prereleases in the 1.2.3 tuple + if (needDomGTPre || needDomLTPre) { + return false + } + + return true +}; + +// >=1.2.3 is lower than >1.2.3 +const higherGT = (a, b, options) => { + if (!a) { + return b + } + const comp = compare$1(a.semver, b.semver, options); + return comp > 0 ? a + : comp < 0 ? b + : b.operator === '>' && a.operator === '>=' ? b + : a +}; + +// <=1.2.3 is higher than <1.2.3 +const lowerLT = (a, b, options) => { + if (!a) { + return b + } + const comp = compare$1(a.semver, b.semver, options); + return comp < 0 ? a + : comp > 0 ? b + : b.operator === '<' && a.operator === '<=' ? b + : a +}; + +var subset_1 = subset$1; + +// just pre-load all the stuff that index.js lazily exports +const internalRe = reExports; +const constants = constants$1; +const SemVer = semver$1; +const identifiers = identifiers$1; +const parse = parse_1; +const valid = valid_1; +const clean = clean_1; +const inc = inc_1; +const diff = diff_1; +const major = major_1; +const minor = minor_1; +const patch = patch_1; +const prerelease = prerelease_1; +const compare = compare_1; +const rcompare = rcompare_1; +const compareLoose = compareLoose_1; +const compareBuild = compareBuild_1; +const sort = sort_1; +const rsort = rsort_1; +const gt = gt_1; +const lt = lt_1; +const eq = eq_1; +const neq = neq_1; +const gte = gte_1; +const lte = lte_1; +const cmp = cmp_1; +const coerce = coerce_1; +const Comparator = requireComparator(); +const Range = requireRange(); +const satisfies = satisfies_1; +const toComparators = toComparators_1; +const maxSatisfying = maxSatisfying_1; +const minSatisfying = minSatisfying_1; +const minVersion = minVersion_1; +const validRange = valid$1; +const outside = outside_1; +const gtr = gtr_1; +const ltr = ltr_1; +const intersects = intersects_1; +const simplifyRange = simplify; +const subset = subset_1; +var semver = { + parse, + valid, + clean, + inc, + diff, + major, + minor, + patch, + prerelease, + compare, + rcompare, + compareLoose, + compareBuild, + sort, + rsort, + gt, + lt, + eq, + neq, + gte, + lte, + cmp, + coerce, + Comparator, + Range, + satisfies, + toComparators, + maxSatisfying, + minSatisfying, + minVersion, + validRange, + outside, + gtr, + ltr, + intersects, + simplifyRange, + subset, + SemVer, + re: internalRe.re, + src: internalRe.src, + tokens: internalRe.t, + SEMVER_SPEC_VERSION: constants.SEMVER_SPEC_VERSION, + RELEASE_TYPES: constants.RELEASE_TYPES, + compareIdentifiers: identifiers.compareIdentifiers, + rcompareIdentifiers: identifiers.rcompareIdentifiers, +}; + +async function fetchModules() { + const { modules } = await $fetch( + `https://api.nuxt.com/modules?version=all` + ); + return modules; +} +function checkNuxtCompatibility(module, nuxtVersion) { + if (!module.compatibility?.nuxt) { + return true; + } + return semver.satisfies(nuxtVersion, module.compatibility.nuxt, { + includePrerelease: true + }); +} +async function getNuxtVersion(cwd) { + const nuxtPkg = tryRequireModule("nuxt/package.json", cwd); + if (nuxtPkg) { + return nuxtPkg.version; + } + const pkg = await getProjectPackage(cwd); + const pkgDep = pkg?.dependencies?.["nuxt"] || pkg?.devDependencies?.["nuxt"]; + return pkgDep && semver.coerce(pkgDep)?.version || "3.0.0"; +} +async function getProjectPackage(cwd) { + return await tryRequireModule("./package.json", cwd); +} + +export { $fetch as $, Bn as B, getNuxtVersion as a, br as b, checkNuxtCompatibility as c, fetchModules as f, getProjectPackage as g, semver as s }; diff --git a/.pnpm-store/v3/files/3b/f1299e9874b4aa87e9c4316447b242e7e89a8394f873a1e78bb29ed8cc57d71b6dcef47cb51f53289fa28230ae82f2cd5b58fff39ee9948c34a09f381096de b/.pnpm-store/v3/files/3b/f1299e9874b4aa87e9c4316447b242e7e89a8394f873a1e78bb29ed8cc57d71b6dcef47cb51f53289fa28230ae82f2cd5b58fff39ee9948c34a09f381096de new file mode 100644 index 0000000000000000000000000000000000000000..6a0f644dd00bf13b772f14a2a9303abedc9b6fb5 --- /dev/null +++ b/.pnpm-store/v3/files/3b/f1299e9874b4aa87e9c4316447b242e7e89a8394f873a1e78bb29ed8cc57d71b6dcef47cb51f53289fa28230ae82f2cd5b58fff39ee9948c34a09f381096de @@ -0,0 +1,427 @@ +import { stdin, stdout } from 'node:process'; +import f from 'node:readline'; +import { WriteStream } from 'node:tty'; +import { i as isUnicodeSupported, a as colors, f as getDefaultExportFromCjs } from '../shared/nuxi.9edf0930.mjs'; +import tty__default from 'tty'; +import 'node:util'; +import 'node:path'; +import 'node:url'; + +const ESC = '\x1B'; +const CSI = `${ESC}[`; +const beep = '\u0007'; + +const cursor = { + to(x, y) { + if (!y) return `${CSI}${x + 1}G`; + return `${CSI}${y + 1};${x + 1}H`; + }, + move(x, y) { + let ret = ''; + + if (x < 0) ret += `${CSI}${-x}D`; + else if (x > 0) ret += `${CSI}${x}C`; + + if (y < 0) ret += `${CSI}${-y}A`; + else if (y > 0) ret += `${CSI}${y}B`; + + return ret; + }, + up: (count = 1) => `${CSI}${count}A`, + down: (count = 1) => `${CSI}${count}B`, + forward: (count = 1) => `${CSI}${count}C`, + backward: (count = 1) => `${CSI}${count}D`, + nextLine: (count = 1) => `${CSI}E`.repeat(count), + prevLine: (count = 1) => `${CSI}F`.repeat(count), + left: `${CSI}G`, + hide: `${CSI}?25l`, + show: `${CSI}?25h`, + save: `${ESC}7`, + restore: `${ESC}8` +}; + +const scroll = { + up: (count = 1) => `${CSI}S`.repeat(count), + down: (count = 1) => `${CSI}T`.repeat(count) +}; + +const erase = { + screen: `${CSI}2J`, + up: (count = 1) => `${CSI}1J`.repeat(count), + down: (count = 1) => `${CSI}J`.repeat(count), + line: `${CSI}2K`, + lineEnd: `${CSI}K`, + lineStart: `${CSI}1K`, + lines(count) { + let clear = ''; + for (let i = 0; i < count; i++) + clear += this.line + (i < count - 1 ? cursor.up() : ''); + if (count) + clear += cursor.left; + return clear; + } +}; + +var src = { cursor, scroll, erase, beep }; + +var picocolors = {exports: {}}; + +let tty = tty__default; + +let isColorSupported = + !("NO_COLOR" in process.env || process.argv.includes("--no-color")) && + ("FORCE_COLOR" in process.env || + process.argv.includes("--color") || + process.platform === "win32" || + (tty.isatty(1) && process.env.TERM !== "dumb") || + "CI" in process.env); + +let formatter = + (open, close, replace = open) => + input => { + let string = "" + input; + let index = string.indexOf(close, open.length); + return ~index + ? open + replaceClose(string, close, replace, index) + close + : open + string + close + }; + +let replaceClose = (string, close, replace, index) => { + let start = string.substring(0, index) + replace; + let end = string.substring(index + close.length); + let nextIndex = end.indexOf(close); + return ~nextIndex ? start + replaceClose(end, close, replace, nextIndex) : start + end +}; + +let createColors = (enabled = isColorSupported) => ({ + isColorSupported: enabled, + reset: enabled ? s => `\x1b[0m${s}\x1b[0m` : String, + bold: enabled ? formatter("\x1b[1m", "\x1b[22m", "\x1b[22m\x1b[1m") : String, + dim: enabled ? formatter("\x1b[2m", "\x1b[22m", "\x1b[22m\x1b[2m") : String, + italic: enabled ? formatter("\x1b[3m", "\x1b[23m") : String, + underline: enabled ? formatter("\x1b[4m", "\x1b[24m") : String, + inverse: enabled ? formatter("\x1b[7m", "\x1b[27m") : String, + hidden: enabled ? formatter("\x1b[8m", "\x1b[28m") : String, + strikethrough: enabled ? formatter("\x1b[9m", "\x1b[29m") : String, + black: enabled ? formatter("\x1b[30m", "\x1b[39m") : String, + red: enabled ? formatter("\x1b[31m", "\x1b[39m") : String, + green: enabled ? formatter("\x1b[32m", "\x1b[39m") : String, + yellow: enabled ? formatter("\x1b[33m", "\x1b[39m") : String, + blue: enabled ? formatter("\x1b[34m", "\x1b[39m") : String, + magenta: enabled ? formatter("\x1b[35m", "\x1b[39m") : String, + cyan: enabled ? formatter("\x1b[36m", "\x1b[39m") : String, + white: enabled ? formatter("\x1b[37m", "\x1b[39m") : String, + gray: enabled ? formatter("\x1b[90m", "\x1b[39m") : String, + bgBlack: enabled ? formatter("\x1b[40m", "\x1b[49m") : String, + bgRed: enabled ? formatter("\x1b[41m", "\x1b[49m") : String, + bgGreen: enabled ? formatter("\x1b[42m", "\x1b[49m") : String, + bgYellow: enabled ? formatter("\x1b[43m", "\x1b[49m") : String, + bgBlue: enabled ? formatter("\x1b[44m", "\x1b[49m") : String, + bgMagenta: enabled ? formatter("\x1b[45m", "\x1b[49m") : String, + bgCyan: enabled ? formatter("\x1b[46m", "\x1b[49m") : String, + bgWhite: enabled ? formatter("\x1b[47m", "\x1b[49m") : String, +}); + +picocolors.exports = createColors(); +picocolors.exports.createColors = createColors; + +var picocolorsExports = picocolors.exports; +const l = /*@__PURE__*/getDefaultExportFromCjs(picocolorsExports); + +function z({onlyFirst:t=!1}={}){const u=["[\\u001B\\u009B][[\\]()#;?]*(?:(?:(?:(?:;[-a-zA-Z\\d\\/#&.:=?%@~_]+)*|[a-zA-Z\\d]+(?:;[-a-zA-Z\\d\\/#&.:=?%@~_]*)*)?\\u0007)","(?:(?:\\d{1,4}(?:;\\d{0,4})*)?[\\dA-PR-TZcf-ntqry=><~]))"].join("|");return new RegExp(u,t?void 0:"g")}function $(t){if(typeof t!="string")throw new TypeError(`Expected a \`string\`, got \`${typeof t}\``);return t.replace(z(),"")}var m={},G={get exports(){return m},set exports(t){m=t;}};(function(t){var u={};t.exports=u,u.eastAsianWidth=function(e){var s=e.charCodeAt(0),C=e.length==2?e.charCodeAt(1):0,D=s;return 55296<=s&&s<=56319&&56320<=C&&C<=57343&&(s&=1023,C&=1023,D=s<<10|C,D+=65536),D==12288||65281<=D&&D<=65376||65504<=D&&D<=65510?"F":D==8361||65377<=D&&D<=65470||65474<=D&&D<=65479||65482<=D&&D<=65487||65490<=D&&D<=65495||65498<=D&&D<=65500||65512<=D&&D<=65518?"H":4352<=D&&D<=4447||4515<=D&&D<=4519||4602<=D&&D<=4607||9001<=D&&D<=9002||11904<=D&&D<=11929||11931<=D&&D<=12019||12032<=D&&D<=12245||12272<=D&&D<=12283||12289<=D&&D<=12350||12353<=D&&D<=12438||12441<=D&&D<=12543||12549<=D&&D<=12589||12593<=D&&D<=12686||12688<=D&&D<=12730||12736<=D&&D<=12771||12784<=D&&D<=12830||12832<=D&&D<=12871||12880<=D&&D<=13054||13056<=D&&D<=19903||19968<=D&&D<=42124||42128<=D&&D<=42182||43360<=D&&D<=43388||44032<=D&&D<=55203||55216<=D&&D<=55238||55243<=D&&D<=55291||63744<=D&&D<=64255||65040<=D&&D<=65049||65072<=D&&D<=65106||65108<=D&&D<=65126||65128<=D&&D<=65131||110592<=D&&D<=110593||127488<=D&&D<=127490||127504<=D&&D<=127546||127552<=D&&D<=127560||127568<=D&&D<=127569||131072<=D&&D<=194367||177984<=D&&D<=196605||196608<=D&&D<=262141?"W":32<=D&&D<=126||162<=D&&D<=163||165<=D&&D<=166||D==172||D==175||10214<=D&&D<=10221||10629<=D&&D<=10630?"Na":D==161||D==164||167<=D&&D<=168||D==170||173<=D&&D<=174||176<=D&&D<=180||182<=D&&D<=186||188<=D&&D<=191||D==198||D==208||215<=D&&D<=216||222<=D&&D<=225||D==230||232<=D&&D<=234||236<=D&&D<=237||D==240||242<=D&&D<=243||247<=D&&D<=250||D==252||D==254||D==257||D==273||D==275||D==283||294<=D&&D<=295||D==299||305<=D&&D<=307||D==312||319<=D&&D<=322||D==324||328<=D&&D<=331||D==333||338<=D&&D<=339||358<=D&&D<=359||D==363||D==462||D==464||D==466||D==468||D==470||D==472||D==474||D==476||D==593||D==609||D==708||D==711||713<=D&&D<=715||D==717||D==720||728<=D&&D<=731||D==733||D==735||768<=D&&D<=879||913<=D&&D<=929||931<=D&&D<=937||945<=D&&D<=961||963<=D&&D<=969||D==1025||1040<=D&&D<=1103||D==1105||D==8208||8211<=D&&D<=8214||8216<=D&&D<=8217||8220<=D&&D<=8221||8224<=D&&D<=8226||8228<=D&&D<=8231||D==8240||8242<=D&&D<=8243||D==8245||D==8251||D==8254||D==8308||D==8319||8321<=D&&D<=8324||D==8364||D==8451||D==8453||D==8457||D==8467||D==8470||8481<=D&&D<=8482||D==8486||D==8491||8531<=D&&D<=8532||8539<=D&&D<=8542||8544<=D&&D<=8555||8560<=D&&D<=8569||D==8585||8592<=D&&D<=8601||8632<=D&&D<=8633||D==8658||D==8660||D==8679||D==8704||8706<=D&&D<=8707||8711<=D&&D<=8712||D==8715||D==8719||D==8721||D==8725||D==8730||8733<=D&&D<=8736||D==8739||D==8741||8743<=D&&D<=8748||D==8750||8756<=D&&D<=8759||8764<=D&&D<=8765||D==8776||D==8780||D==8786||8800<=D&&D<=8801||8804<=D&&D<=8807||8810<=D&&D<=8811||8814<=D&&D<=8815||8834<=D&&D<=8835||8838<=D&&D<=8839||D==8853||D==8857||D==8869||D==8895||D==8978||9312<=D&&D<=9449||9451<=D&&D<=9547||9552<=D&&D<=9587||9600<=D&&D<=9615||9618<=D&&D<=9621||9632<=D&&D<=9633||9635<=D&&D<=9641||9650<=D&&D<=9651||9654<=D&&D<=9655||9660<=D&&D<=9661||9664<=D&&D<=9665||9670<=D&&D<=9672||D==9675||9678<=D&&D<=9681||9698<=D&&D<=9701||D==9711||9733<=D&&D<=9734||D==9737||9742<=D&&D<=9743||9748<=D&&D<=9749||D==9756||D==9758||D==9792||D==9794||9824<=D&&D<=9825||9827<=D&&D<=9829||9831<=D&&D<=9834||9836<=D&&D<=9837||D==9839||9886<=D&&D<=9887||9918<=D&&D<=9919||9924<=D&&D<=9933||9935<=D&&D<=9953||D==9955||9960<=D&&D<=9983||D==10045||D==10071||10102<=D&&D<=10111||11093<=D&&D<=11097||12872<=D&&D<=12879||57344<=D&&D<=63743||65024<=D&&D<=65039||D==65533||127232<=D&&D<=127242||127248<=D&&D<=127277||127280<=D&&D<=127337||127344<=D&&D<=127386||917760<=D&&D<=917999||983040<=D&&D<=1048573||1048576<=D&&D<=1114109?"A":"N"},u.characterLength=function(e){var s=this.eastAsianWidth(e);return s=="F"||s=="W"||s=="A"?2:1};function F(e){return e.match(/[\uD800-\uDBFF][\uDC00-\uDFFF]|[^\uD800-\uDFFF]/g)||[]}u.length=function(e){for(var s=F(e),C=0,D=0;D=s-(n==2?1:0))if(i+n<=C)D+=a;else break;i+=n;}return D};})(G);const K=m;var Y=function(){return /\uD83C\uDFF4\uDB40\uDC67\uDB40\uDC62(?:\uDB40\uDC77\uDB40\uDC6C\uDB40\uDC73|\uDB40\uDC73\uDB40\uDC63\uDB40\uDC74|\uDB40\uDC65\uDB40\uDC6E\uDB40\uDC67)\uDB40\uDC7F|(?:\uD83E\uDDD1\uD83C\uDFFF\u200D\u2764\uFE0F\u200D(?:\uD83D\uDC8B\u200D)?\uD83E\uDDD1|\uD83D\uDC69\uD83C\uDFFF\u200D\uD83E\uDD1D\u200D(?:\uD83D[\uDC68\uDC69]))(?:\uD83C[\uDFFB-\uDFFE])|(?:\uD83E\uDDD1\uD83C\uDFFE\u200D\u2764\uFE0F\u200D(?:\uD83D\uDC8B\u200D)?\uD83E\uDDD1|\uD83D\uDC69\uD83C\uDFFE\u200D\uD83E\uDD1D\u200D(?:\uD83D[\uDC68\uDC69]))(?:\uD83C[\uDFFB-\uDFFD\uDFFF])|(?:\uD83E\uDDD1\uD83C\uDFFD\u200D\u2764\uFE0F\u200D(?:\uD83D\uDC8B\u200D)?\uD83E\uDDD1|\uD83D\uDC69\uD83C\uDFFD\u200D\uD83E\uDD1D\u200D(?:\uD83D[\uDC68\uDC69]))(?:\uD83C[\uDFFB\uDFFC\uDFFE\uDFFF])|(?:\uD83E\uDDD1\uD83C\uDFFC\u200D\u2764\uFE0F\u200D(?:\uD83D\uDC8B\u200D)?\uD83E\uDDD1|\uD83D\uDC69\uD83C\uDFFC\u200D\uD83E\uDD1D\u200D(?:\uD83D[\uDC68\uDC69]))(?:\uD83C[\uDFFB\uDFFD-\uDFFF])|(?:\uD83E\uDDD1\uD83C\uDFFB\u200D\u2764\uFE0F\u200D(?:\uD83D\uDC8B\u200D)?\uD83E\uDDD1|\uD83D\uDC69\uD83C\uDFFB\u200D\uD83E\uDD1D\u200D(?:\uD83D[\uDC68\uDC69]))(?:\uD83C[\uDFFC-\uDFFF])|\uD83D\uDC68(?:\uD83C\uDFFB(?:\u200D(?:\u2764\uFE0F\u200D(?:\uD83D\uDC8B\u200D\uD83D\uDC68(?:\uD83C[\uDFFB-\uDFFF])|\uD83D\uDC68(?:\uD83C[\uDFFB-\uDFFF]))|\uD83E\uDD1D\u200D\uD83D\uDC68(?:\uD83C[\uDFFC-\uDFFF])|[\u2695\u2696\u2708]\uFE0F|\uD83C[\uDF3E\uDF73\uDF7C\uDF93\uDFA4\uDFA8\uDFEB\uDFED]|\uD83D[\uDCBB\uDCBC\uDD27\uDD2C\uDE80\uDE92]|\uD83E[\uDDAF-\uDDB3\uDDBC\uDDBD]))?|(?:\uD83C[\uDFFC-\uDFFF])\u200D\u2764\uFE0F\u200D(?:\uD83D\uDC8B\u200D\uD83D\uDC68(?:\uD83C[\uDFFB-\uDFFF])|\uD83D\uDC68(?:\uD83C[\uDFFB-\uDFFF]))|\u200D(?:\u2764\uFE0F\u200D(?:\uD83D\uDC8B\u200D)?\uD83D\uDC68|(?:\uD83D[\uDC68\uDC69])\u200D(?:\uD83D\uDC66\u200D\uD83D\uDC66|\uD83D\uDC67\u200D(?:\uD83D[\uDC66\uDC67]))|\uD83D\uDC66\u200D\uD83D\uDC66|\uD83D\uDC67\u200D(?:\uD83D[\uDC66\uDC67])|\uD83C[\uDF3E\uDF73\uDF7C\uDF93\uDFA4\uDFA8\uDFEB\uDFED]|\uD83D[\uDCBB\uDCBC\uDD27\uDD2C\uDE80\uDE92]|\uD83E[\uDDAF-\uDDB3\uDDBC\uDDBD])|\uD83C\uDFFF\u200D(?:\uD83E\uDD1D\u200D\uD83D\uDC68(?:\uD83C[\uDFFB-\uDFFE])|\uD83C[\uDF3E\uDF73\uDF7C\uDF93\uDFA4\uDFA8\uDFEB\uDFED]|\uD83D[\uDCBB\uDCBC\uDD27\uDD2C\uDE80\uDE92]|\uD83E[\uDDAF-\uDDB3\uDDBC\uDDBD])|\uD83C\uDFFE\u200D(?:\uD83E\uDD1D\u200D\uD83D\uDC68(?:\uD83C[\uDFFB-\uDFFD\uDFFF])|\uD83C[\uDF3E\uDF73\uDF7C\uDF93\uDFA4\uDFA8\uDFEB\uDFED]|\uD83D[\uDCBB\uDCBC\uDD27\uDD2C\uDE80\uDE92]|\uD83E[\uDDAF-\uDDB3\uDDBC\uDDBD])|\uD83C\uDFFD\u200D(?:\uD83E\uDD1D\u200D\uD83D\uDC68(?:\uD83C[\uDFFB\uDFFC\uDFFE\uDFFF])|\uD83C[\uDF3E\uDF73\uDF7C\uDF93\uDFA4\uDFA8\uDFEB\uDFED]|\uD83D[\uDCBB\uDCBC\uDD27\uDD2C\uDE80\uDE92]|\uD83E[\uDDAF-\uDDB3\uDDBC\uDDBD])|\uD83C\uDFFC\u200D(?:\uD83E\uDD1D\u200D\uD83D\uDC68(?:\uD83C[\uDFFB\uDFFD-\uDFFF])|\uD83C[\uDF3E\uDF73\uDF7C\uDF93\uDFA4\uDFA8\uDFEB\uDFED]|\uD83D[\uDCBB\uDCBC\uDD27\uDD2C\uDE80\uDE92]|\uD83E[\uDDAF-\uDDB3\uDDBC\uDDBD])|(?:\uD83C\uDFFF\u200D[\u2695\u2696\u2708]|\uD83C\uDFFE\u200D[\u2695\u2696\u2708]|\uD83C\uDFFD\u200D[\u2695\u2696\u2708]|\uD83C\uDFFC\u200D[\u2695\u2696\u2708]|\u200D[\u2695\u2696\u2708])\uFE0F|\u200D(?:(?:\uD83D[\uDC68\uDC69])\u200D(?:\uD83D[\uDC66\uDC67])|\uD83D[\uDC66\uDC67])|\uD83C\uDFFF|\uD83C\uDFFE|\uD83C\uDFFD|\uD83C\uDFFC)?|(?:\uD83D\uDC69(?:\uD83C\uDFFB\u200D\u2764\uFE0F\u200D(?:\uD83D\uDC8B\u200D(?:\uD83D[\uDC68\uDC69])|\uD83D[\uDC68\uDC69])|(?:\uD83C[\uDFFC-\uDFFF])\u200D\u2764\uFE0F\u200D(?:\uD83D\uDC8B\u200D(?:\uD83D[\uDC68\uDC69])|\uD83D[\uDC68\uDC69]))|\uD83E\uDDD1(?:\uD83C[\uDFFB-\uDFFF])\u200D\uD83E\uDD1D\u200D\uD83E\uDDD1)(?:\uD83C[\uDFFB-\uDFFF])|\uD83D\uDC69\u200D\uD83D\uDC69\u200D(?:\uD83D\uDC66\u200D\uD83D\uDC66|\uD83D\uDC67\u200D(?:\uD83D[\uDC66\uDC67]))|\uD83D\uDC69(?:\u200D(?:\u2764\uFE0F\u200D(?:\uD83D\uDC8B\u200D(?:\uD83D[\uDC68\uDC69])|\uD83D[\uDC68\uDC69])|\uD83C[\uDF3E\uDF73\uDF7C\uDF93\uDFA4\uDFA8\uDFEB\uDFED]|\uD83D[\uDCBB\uDCBC\uDD27\uDD2C\uDE80\uDE92]|\uD83E[\uDDAF-\uDDB3\uDDBC\uDDBD])|\uD83C\uDFFF\u200D(?:\uD83C[\uDF3E\uDF73\uDF7C\uDF93\uDFA4\uDFA8\uDFEB\uDFED]|\uD83D[\uDCBB\uDCBC\uDD27\uDD2C\uDE80\uDE92]|\uD83E[\uDDAF-\uDDB3\uDDBC\uDDBD])|\uD83C\uDFFE\u200D(?:\uD83C[\uDF3E\uDF73\uDF7C\uDF93\uDFA4\uDFA8\uDFEB\uDFED]|\uD83D[\uDCBB\uDCBC\uDD27\uDD2C\uDE80\uDE92]|\uD83E[\uDDAF-\uDDB3\uDDBC\uDDBD])|\uD83C\uDFFD\u200D(?:\uD83C[\uDF3E\uDF73\uDF7C\uDF93\uDFA4\uDFA8\uDFEB\uDFED]|\uD83D[\uDCBB\uDCBC\uDD27\uDD2C\uDE80\uDE92]|\uD83E[\uDDAF-\uDDB3\uDDBC\uDDBD])|\uD83C\uDFFC\u200D(?:\uD83C[\uDF3E\uDF73\uDF7C\uDF93\uDFA4\uDFA8\uDFEB\uDFED]|\uD83D[\uDCBB\uDCBC\uDD27\uDD2C\uDE80\uDE92]|\uD83E[\uDDAF-\uDDB3\uDDBC\uDDBD])|\uD83C\uDFFB\u200D(?:\uD83C[\uDF3E\uDF73\uDF7C\uDF93\uDFA4\uDFA8\uDFEB\uDFED]|\uD83D[\uDCBB\uDCBC\uDD27\uDD2C\uDE80\uDE92]|\uD83E[\uDDAF-\uDDB3\uDDBC\uDDBD]))|\uD83E\uDDD1(?:\u200D(?:\uD83E\uDD1D\u200D\uD83E\uDDD1|\uD83C[\uDF3E\uDF73\uDF7C\uDF84\uDF93\uDFA4\uDFA8\uDFEB\uDFED]|\uD83D[\uDCBB\uDCBC\uDD27\uDD2C\uDE80\uDE92]|\uD83E[\uDDAF-\uDDB3\uDDBC\uDDBD])|\uD83C\uDFFF\u200D(?:\uD83C[\uDF3E\uDF73\uDF7C\uDF84\uDF93\uDFA4\uDFA8\uDFEB\uDFED]|\uD83D[\uDCBB\uDCBC\uDD27\uDD2C\uDE80\uDE92]|\uD83E[\uDDAF-\uDDB3\uDDBC\uDDBD])|\uD83C\uDFFE\u200D(?:\uD83C[\uDF3E\uDF73\uDF7C\uDF84\uDF93\uDFA4\uDFA8\uDFEB\uDFED]|\uD83D[\uDCBB\uDCBC\uDD27\uDD2C\uDE80\uDE92]|\uD83E[\uDDAF-\uDDB3\uDDBC\uDDBD])|\uD83C\uDFFD\u200D(?:\uD83C[\uDF3E\uDF73\uDF7C\uDF84\uDF93\uDFA4\uDFA8\uDFEB\uDFED]|\uD83D[\uDCBB\uDCBC\uDD27\uDD2C\uDE80\uDE92]|\uD83E[\uDDAF-\uDDB3\uDDBC\uDDBD])|\uD83C\uDFFC\u200D(?:\uD83C[\uDF3E\uDF73\uDF7C\uDF84\uDF93\uDFA4\uDFA8\uDFEB\uDFED]|\uD83D[\uDCBB\uDCBC\uDD27\uDD2C\uDE80\uDE92]|\uD83E[\uDDAF-\uDDB3\uDDBC\uDDBD])|\uD83C\uDFFB\u200D(?:\uD83C[\uDF3E\uDF73\uDF7C\uDF84\uDF93\uDFA4\uDFA8\uDFEB\uDFED]|\uD83D[\uDCBB\uDCBC\uDD27\uDD2C\uDE80\uDE92]|\uD83E[\uDDAF-\uDDB3\uDDBC\uDDBD]))|\uD83D\uDC69\u200D\uD83D\uDC66\u200D\uD83D\uDC66|\uD83D\uDC69\u200D\uD83D\uDC69\u200D(?:\uD83D[\uDC66\uDC67])|\uD83D\uDC69\u200D\uD83D\uDC67\u200D(?:\uD83D[\uDC66\uDC67])|(?:\uD83D\uDC41\uFE0F\u200D\uD83D\uDDE8|\uD83E\uDDD1(?:\uD83C\uDFFF\u200D[\u2695\u2696\u2708]|\uD83C\uDFFE\u200D[\u2695\u2696\u2708]|\uD83C\uDFFD\u200D[\u2695\u2696\u2708]|\uD83C\uDFFC\u200D[\u2695\u2696\u2708]|\uD83C\uDFFB\u200D[\u2695\u2696\u2708]|\u200D[\u2695\u2696\u2708])|\uD83D\uDC69(?:\uD83C\uDFFF\u200D[\u2695\u2696\u2708]|\uD83C\uDFFE\u200D[\u2695\u2696\u2708]|\uD83C\uDFFD\u200D[\u2695\u2696\u2708]|\uD83C\uDFFC\u200D[\u2695\u2696\u2708]|\uD83C\uDFFB\u200D[\u2695\u2696\u2708]|\u200D[\u2695\u2696\u2708])|\uD83D\uDE36\u200D\uD83C\uDF2B|\uD83C\uDFF3\uFE0F\u200D\u26A7|\uD83D\uDC3B\u200D\u2744|(?:(?:\uD83C[\uDFC3\uDFC4\uDFCA]|\uD83D[\uDC6E\uDC70\uDC71\uDC73\uDC77\uDC81\uDC82\uDC86\uDC87\uDE45-\uDE47\uDE4B\uDE4D\uDE4E\uDEA3\uDEB4-\uDEB6]|\uD83E[\uDD26\uDD35\uDD37-\uDD39\uDD3D\uDD3E\uDDB8\uDDB9\uDDCD-\uDDCF\uDDD4\uDDD6-\uDDDD])(?:\uD83C[\uDFFB-\uDFFF])|\uD83D\uDC6F|\uD83E[\uDD3C\uDDDE\uDDDF])\u200D[\u2640\u2642]|(?:\u26F9|\uD83C[\uDFCB\uDFCC]|\uD83D\uDD75)(?:\uFE0F|\uD83C[\uDFFB-\uDFFF])\u200D[\u2640\u2642]|\uD83C\uDFF4\u200D\u2620|(?:\uD83C[\uDFC3\uDFC4\uDFCA]|\uD83D[\uDC6E\uDC70\uDC71\uDC73\uDC77\uDC81\uDC82\uDC86\uDC87\uDE45-\uDE47\uDE4B\uDE4D\uDE4E\uDEA3\uDEB4-\uDEB6]|\uD83E[\uDD26\uDD35\uDD37-\uDD39\uDD3D\uDD3E\uDDB8\uDDB9\uDDCD-\uDDCF\uDDD4\uDDD6-\uDDDD])\u200D[\u2640\u2642]|[\xA9\xAE\u203C\u2049\u2122\u2139\u2194-\u2199\u21A9\u21AA\u2328\u23CF\u23ED-\u23EF\u23F1\u23F2\u23F8-\u23FA\u24C2\u25AA\u25AB\u25B6\u25C0\u25FB\u25FC\u2600-\u2604\u260E\u2611\u2618\u2620\u2622\u2623\u2626\u262A\u262E\u262F\u2638-\u263A\u2640\u2642\u265F\u2660\u2663\u2665\u2666\u2668\u267B\u267E\u2692\u2694-\u2697\u2699\u269B\u269C\u26A0\u26A7\u26B0\u26B1\u26C8\u26CF\u26D1\u26D3\u26E9\u26F0\u26F1\u26F4\u26F7\u26F8\u2702\u2708\u2709\u270F\u2712\u2714\u2716\u271D\u2721\u2733\u2734\u2744\u2747\u2763\u27A1\u2934\u2935\u2B05-\u2B07\u3030\u303D\u3297\u3299]|\uD83C[\uDD70\uDD71\uDD7E\uDD7F\uDE02\uDE37\uDF21\uDF24-\uDF2C\uDF36\uDF7D\uDF96\uDF97\uDF99-\uDF9B\uDF9E\uDF9F\uDFCD\uDFCE\uDFD4-\uDFDF\uDFF5\uDFF7]|\uD83D[\uDC3F\uDCFD\uDD49\uDD4A\uDD6F\uDD70\uDD73\uDD76-\uDD79\uDD87\uDD8A-\uDD8D\uDDA5\uDDA8\uDDB1\uDDB2\uDDBC\uDDC2-\uDDC4\uDDD1-\uDDD3\uDDDC-\uDDDE\uDDE1\uDDE3\uDDE8\uDDEF\uDDF3\uDDFA\uDECB\uDECD-\uDECF\uDEE0-\uDEE5\uDEE9\uDEF0\uDEF3])\uFE0F|\uD83C\uDFF3\uFE0F\u200D\uD83C\uDF08|\uD83D\uDC69\u200D\uD83D\uDC67|\uD83D\uDC69\u200D\uD83D\uDC66|\uD83D\uDE35\u200D\uD83D\uDCAB|\uD83D\uDE2E\u200D\uD83D\uDCA8|\uD83D\uDC15\u200D\uD83E\uDDBA|\uD83E\uDDD1(?:\uD83C\uDFFF|\uD83C\uDFFE|\uD83C\uDFFD|\uD83C\uDFFC|\uD83C\uDFFB)?|\uD83D\uDC69(?:\uD83C\uDFFF|\uD83C\uDFFE|\uD83C\uDFFD|\uD83C\uDFFC|\uD83C\uDFFB)?|\uD83C\uDDFD\uD83C\uDDF0|\uD83C\uDDF6\uD83C\uDDE6|\uD83C\uDDF4\uD83C\uDDF2|\uD83D\uDC08\u200D\u2B1B|\u2764\uFE0F\u200D(?:\uD83D\uDD25|\uD83E\uDE79)|\uD83D\uDC41\uFE0F|\uD83C\uDFF3\uFE0F|\uD83C\uDDFF(?:\uD83C[\uDDE6\uDDF2\uDDFC])|\uD83C\uDDFE(?:\uD83C[\uDDEA\uDDF9])|\uD83C\uDDFC(?:\uD83C[\uDDEB\uDDF8])|\uD83C\uDDFB(?:\uD83C[\uDDE6\uDDE8\uDDEA\uDDEC\uDDEE\uDDF3\uDDFA])|\uD83C\uDDFA(?:\uD83C[\uDDE6\uDDEC\uDDF2\uDDF3\uDDF8\uDDFE\uDDFF])|\uD83C\uDDF9(?:\uD83C[\uDDE6\uDDE8\uDDE9\uDDEB-\uDDED\uDDEF-\uDDF4\uDDF7\uDDF9\uDDFB\uDDFC\uDDFF])|\uD83C\uDDF8(?:\uD83C[\uDDE6-\uDDEA\uDDEC-\uDDF4\uDDF7-\uDDF9\uDDFB\uDDFD-\uDDFF])|\uD83C\uDDF7(?:\uD83C[\uDDEA\uDDF4\uDDF8\uDDFA\uDDFC])|\uD83C\uDDF5(?:\uD83C[\uDDE6\uDDEA-\uDDED\uDDF0-\uDDF3\uDDF7-\uDDF9\uDDFC\uDDFE])|\uD83C\uDDF3(?:\uD83C[\uDDE6\uDDE8\uDDEA-\uDDEC\uDDEE\uDDF1\uDDF4\uDDF5\uDDF7\uDDFA\uDDFF])|\uD83C\uDDF2(?:\uD83C[\uDDE6\uDDE8-\uDDED\uDDF0-\uDDFF])|\uD83C\uDDF1(?:\uD83C[\uDDE6-\uDDE8\uDDEE\uDDF0\uDDF7-\uDDFB\uDDFE])|\uD83C\uDDF0(?:\uD83C[\uDDEA\uDDEC-\uDDEE\uDDF2\uDDF3\uDDF5\uDDF7\uDDFC\uDDFE\uDDFF])|\uD83C\uDDEF(?:\uD83C[\uDDEA\uDDF2\uDDF4\uDDF5])|\uD83C\uDDEE(?:\uD83C[\uDDE8-\uDDEA\uDDF1-\uDDF4\uDDF6-\uDDF9])|\uD83C\uDDED(?:\uD83C[\uDDF0\uDDF2\uDDF3\uDDF7\uDDF9\uDDFA])|\uD83C\uDDEC(?:\uD83C[\uDDE6\uDDE7\uDDE9-\uDDEE\uDDF1-\uDDF3\uDDF5-\uDDFA\uDDFC\uDDFE])|\uD83C\uDDEB(?:\uD83C[\uDDEE-\uDDF0\uDDF2\uDDF4\uDDF7])|\uD83C\uDDEA(?:\uD83C[\uDDE6\uDDE8\uDDEA\uDDEC\uDDED\uDDF7-\uDDFA])|\uD83C\uDDE9(?:\uD83C[\uDDEA\uDDEC\uDDEF\uDDF0\uDDF2\uDDF4\uDDFF])|\uD83C\uDDE8(?:\uD83C[\uDDE6\uDDE8\uDDE9\uDDEB-\uDDEE\uDDF0-\uDDF5\uDDF7\uDDFA-\uDDFF])|\uD83C\uDDE7(?:\uD83C[\uDDE6\uDDE7\uDDE9-\uDDEF\uDDF1-\uDDF4\uDDF6-\uDDF9\uDDFB\uDDFC\uDDFE\uDDFF])|\uD83C\uDDE6(?:\uD83C[\uDDE8-\uDDEC\uDDEE\uDDF1\uDDF2\uDDF4\uDDF6-\uDDFA\uDDFC\uDDFD\uDDFF])|[#\*0-9]\uFE0F\u20E3|\u2764\uFE0F|(?:\uD83C[\uDFC3\uDFC4\uDFCA]|\uD83D[\uDC6E\uDC70\uDC71\uDC73\uDC77\uDC81\uDC82\uDC86\uDC87\uDE45-\uDE47\uDE4B\uDE4D\uDE4E\uDEA3\uDEB4-\uDEB6]|\uD83E[\uDD26\uDD35\uDD37-\uDD39\uDD3D\uDD3E\uDDB8\uDDB9\uDDCD-\uDDCF\uDDD4\uDDD6-\uDDDD])(?:\uD83C[\uDFFB-\uDFFF])|(?:\u26F9|\uD83C[\uDFCB\uDFCC]|\uD83D\uDD75)(?:\uFE0F|\uD83C[\uDFFB-\uDFFF])|\uD83C\uDFF4|(?:[\u270A\u270B]|\uD83C[\uDF85\uDFC2\uDFC7]|\uD83D[\uDC42\uDC43\uDC46-\uDC50\uDC66\uDC67\uDC6B-\uDC6D\uDC72\uDC74-\uDC76\uDC78\uDC7C\uDC83\uDC85\uDC8F\uDC91\uDCAA\uDD7A\uDD95\uDD96\uDE4C\uDE4F\uDEC0\uDECC]|\uD83E[\uDD0C\uDD0F\uDD18-\uDD1C\uDD1E\uDD1F\uDD30-\uDD34\uDD36\uDD77\uDDB5\uDDB6\uDDBB\uDDD2\uDDD3\uDDD5])(?:\uD83C[\uDFFB-\uDFFF])|(?:[\u261D\u270C\u270D]|\uD83D[\uDD74\uDD90])(?:\uFE0F|\uD83C[\uDFFB-\uDFFF])|[\u270A\u270B]|\uD83C[\uDF85\uDFC2\uDFC7]|\uD83D[\uDC08\uDC15\uDC3B\uDC42\uDC43\uDC46-\uDC50\uDC66\uDC67\uDC6B-\uDC6D\uDC72\uDC74-\uDC76\uDC78\uDC7C\uDC83\uDC85\uDC8F\uDC91\uDCAA\uDD7A\uDD95\uDD96\uDE2E\uDE35\uDE36\uDE4C\uDE4F\uDEC0\uDECC]|\uD83E[\uDD0C\uDD0F\uDD18-\uDD1C\uDD1E\uDD1F\uDD30-\uDD34\uDD36\uDD77\uDDB5\uDDB6\uDDBB\uDDD2\uDDD3\uDDD5]|\uD83C[\uDFC3\uDFC4\uDFCA]|\uD83D[\uDC6E\uDC70\uDC71\uDC73\uDC77\uDC81\uDC82\uDC86\uDC87\uDE45-\uDE47\uDE4B\uDE4D\uDE4E\uDEA3\uDEB4-\uDEB6]|\uD83E[\uDD26\uDD35\uDD37-\uDD39\uDD3D\uDD3E\uDDB8\uDDB9\uDDCD-\uDDCF\uDDD4\uDDD6-\uDDDD]|\uD83D\uDC6F|\uD83E[\uDD3C\uDDDE\uDDDF]|[\u231A\u231B\u23E9-\u23EC\u23F0\u23F3\u25FD\u25FE\u2614\u2615\u2648-\u2653\u267F\u2693\u26A1\u26AA\u26AB\u26BD\u26BE\u26C4\u26C5\u26CE\u26D4\u26EA\u26F2\u26F3\u26F5\u26FA\u26FD\u2705\u2728\u274C\u274E\u2753-\u2755\u2757\u2795-\u2797\u27B0\u27BF\u2B1B\u2B1C\u2B50\u2B55]|\uD83C[\uDC04\uDCCF\uDD8E\uDD91-\uDD9A\uDE01\uDE1A\uDE2F\uDE32-\uDE36\uDE38-\uDE3A\uDE50\uDE51\uDF00-\uDF20\uDF2D-\uDF35\uDF37-\uDF7C\uDF7E-\uDF84\uDF86-\uDF93\uDFA0-\uDFC1\uDFC5\uDFC6\uDFC8\uDFC9\uDFCF-\uDFD3\uDFE0-\uDFF0\uDFF8-\uDFFF]|\uD83D[\uDC00-\uDC07\uDC09-\uDC14\uDC16-\uDC3A\uDC3C-\uDC3E\uDC40\uDC44\uDC45\uDC51-\uDC65\uDC6A\uDC79-\uDC7B\uDC7D-\uDC80\uDC84\uDC88-\uDC8E\uDC90\uDC92-\uDCA9\uDCAB-\uDCFC\uDCFF-\uDD3D\uDD4B-\uDD4E\uDD50-\uDD67\uDDA4\uDDFB-\uDE2D\uDE2F-\uDE34\uDE37-\uDE44\uDE48-\uDE4A\uDE80-\uDEA2\uDEA4-\uDEB3\uDEB7-\uDEBF\uDEC1-\uDEC5\uDED0-\uDED2\uDED5-\uDED7\uDEEB\uDEEC\uDEF4-\uDEFC\uDFE0-\uDFEB]|\uD83E[\uDD0D\uDD0E\uDD10-\uDD17\uDD1D\uDD20-\uDD25\uDD27-\uDD2F\uDD3A\uDD3F-\uDD45\uDD47-\uDD76\uDD78\uDD7A-\uDDB4\uDDB7\uDDBA\uDDBC-\uDDCB\uDDD0\uDDE0-\uDDFF\uDE70-\uDE74\uDE78-\uDE7A\uDE80-\uDE86\uDE90-\uDEA8\uDEB0-\uDEB6\uDEC0-\uDEC2\uDED0-\uDED6]|(?:[\u231A\u231B\u23E9-\u23EC\u23F0\u23F3\u25FD\u25FE\u2614\u2615\u2648-\u2653\u267F\u2693\u26A1\u26AA\u26AB\u26BD\u26BE\u26C4\u26C5\u26CE\u26D4\u26EA\u26F2\u26F3\u26F5\u26FA\u26FD\u2705\u270A\u270B\u2728\u274C\u274E\u2753-\u2755\u2757\u2795-\u2797\u27B0\u27BF\u2B1B\u2B1C\u2B50\u2B55]|\uD83C[\uDC04\uDCCF\uDD8E\uDD91-\uDD9A\uDDE6-\uDDFF\uDE01\uDE1A\uDE2F\uDE32-\uDE36\uDE38-\uDE3A\uDE50\uDE51\uDF00-\uDF20\uDF2D-\uDF35\uDF37-\uDF7C\uDF7E-\uDF93\uDFA0-\uDFCA\uDFCF-\uDFD3\uDFE0-\uDFF0\uDFF4\uDFF8-\uDFFF]|\uD83D[\uDC00-\uDC3E\uDC40\uDC42-\uDCFC\uDCFF-\uDD3D\uDD4B-\uDD4E\uDD50-\uDD67\uDD7A\uDD95\uDD96\uDDA4\uDDFB-\uDE4F\uDE80-\uDEC5\uDECC\uDED0-\uDED2\uDED5-\uDED7\uDEEB\uDEEC\uDEF4-\uDEFC\uDFE0-\uDFEB]|\uD83E[\uDD0C-\uDD3A\uDD3C-\uDD45\uDD47-\uDD78\uDD7A-\uDDCB\uDDCD-\uDDFF\uDE70-\uDE74\uDE78-\uDE7A\uDE80-\uDE86\uDE90-\uDEA8\uDEB0-\uDEB6\uDEC0-\uDEC2\uDED0-\uDED6])|(?:[#\*0-9\xA9\xAE\u203C\u2049\u2122\u2139\u2194-\u2199\u21A9\u21AA\u231A\u231B\u2328\u23CF\u23E9-\u23F3\u23F8-\u23FA\u24C2\u25AA\u25AB\u25B6\u25C0\u25FB-\u25FE\u2600-\u2604\u260E\u2611\u2614\u2615\u2618\u261D\u2620\u2622\u2623\u2626\u262A\u262E\u262F\u2638-\u263A\u2640\u2642\u2648-\u2653\u265F\u2660\u2663\u2665\u2666\u2668\u267B\u267E\u267F\u2692-\u2697\u2699\u269B\u269C\u26A0\u26A1\u26A7\u26AA\u26AB\u26B0\u26B1\u26BD\u26BE\u26C4\u26C5\u26C8\u26CE\u26CF\u26D1\u26D3\u26D4\u26E9\u26EA\u26F0-\u26F5\u26F7-\u26FA\u26FD\u2702\u2705\u2708-\u270D\u270F\u2712\u2714\u2716\u271D\u2721\u2728\u2733\u2734\u2744\u2747\u274C\u274E\u2753-\u2755\u2757\u2763\u2764\u2795-\u2797\u27A1\u27B0\u27BF\u2934\u2935\u2B05-\u2B07\u2B1B\u2B1C\u2B50\u2B55\u3030\u303D\u3297\u3299]|\uD83C[\uDC04\uDCCF\uDD70\uDD71\uDD7E\uDD7F\uDD8E\uDD91-\uDD9A\uDDE6-\uDDFF\uDE01\uDE02\uDE1A\uDE2F\uDE32-\uDE3A\uDE50\uDE51\uDF00-\uDF21\uDF24-\uDF93\uDF96\uDF97\uDF99-\uDF9B\uDF9E-\uDFF0\uDFF3-\uDFF5\uDFF7-\uDFFF]|\uD83D[\uDC00-\uDCFD\uDCFF-\uDD3D\uDD49-\uDD4E\uDD50-\uDD67\uDD6F\uDD70\uDD73-\uDD7A\uDD87\uDD8A-\uDD8D\uDD90\uDD95\uDD96\uDDA4\uDDA5\uDDA8\uDDB1\uDDB2\uDDBC\uDDC2-\uDDC4\uDDD1-\uDDD3\uDDDC-\uDDDE\uDDE1\uDDE3\uDDE8\uDDEF\uDDF3\uDDFA-\uDE4F\uDE80-\uDEC5\uDECB-\uDED2\uDED5-\uDED7\uDEE0-\uDEE5\uDEE9\uDEEB\uDEEC\uDEF0\uDEF3-\uDEFC\uDFE0-\uDFEB]|\uD83E[\uDD0C-\uDD3A\uDD3C-\uDD45\uDD47-\uDD78\uDD7A-\uDDCB\uDDCD-\uDDFF\uDE70-\uDE74\uDE78-\uDE7A\uDE80-\uDE86\uDE90-\uDEA8\uDEB0-\uDEB6\uDEC0-\uDEC2\uDED0-\uDED6])\uFE0F|(?:[\u261D\u26F9\u270A-\u270D]|\uD83C[\uDF85\uDFC2-\uDFC4\uDFC7\uDFCA-\uDFCC]|\uD83D[\uDC42\uDC43\uDC46-\uDC50\uDC66-\uDC78\uDC7C\uDC81-\uDC83\uDC85-\uDC87\uDC8F\uDC91\uDCAA\uDD74\uDD75\uDD7A\uDD90\uDD95\uDD96\uDE45-\uDE47\uDE4B-\uDE4F\uDEA3\uDEB4-\uDEB6\uDEC0\uDECC]|\uD83E[\uDD0C\uDD0F\uDD18-\uDD1F\uDD26\uDD30-\uDD39\uDD3C-\uDD3E\uDD77\uDDB5\uDDB6\uDDB8\uDDB9\uDDBB\uDDCD-\uDDCF\uDDD1-\uDDDD])/g};function c(t,u={}){if(typeof t!="string"||t.length===0||(u={ambiguousIsNarrow:!0,...u},t=$(t),t.length===0))return 0;t=t.replace(Y()," ");const F=u.ambiguousIsNarrow?1:2;let e=0;for(const s of t){const C=s.codePointAt(0);if(C<=31||C>=127&&C<=159||C>=768&&C<=879)continue;switch(K.eastAsianWidth(s)){case"F":case"W":e+=2;break;case"A":e+=F;break;default:e+=1;}}return e}const v=10,L=(t=0)=>u=>`\x1B[${u+t}m`,M=(t=0)=>u=>`\x1B[${38+t};5;${u}m`,T=(t=0)=>(u,F,e)=>`\x1B[${38+t};2;${u};${F};${e}m`,r={modifier:{reset:[0,0],bold:[1,22],dim:[2,22],italic:[3,23],underline:[4,24],overline:[53,55],inverse:[7,27],hidden:[8,28],strikethrough:[9,29]},color:{black:[30,39],red:[31,39],green:[32,39],yellow:[33,39],blue:[34,39],magenta:[35,39],cyan:[36,39],white:[37,39],blackBright:[90,39],gray:[90,39],grey:[90,39],redBright:[91,39],greenBright:[92,39],yellowBright:[93,39],blueBright:[94,39],magentaBright:[95,39],cyanBright:[96,39],whiteBright:[97,39]},bgColor:{bgBlack:[40,49],bgRed:[41,49],bgGreen:[42,49],bgYellow:[43,49],bgBlue:[44,49],bgMagenta:[45,49],bgCyan:[46,49],bgWhite:[47,49],bgBlackBright:[100,49],bgGray:[100,49],bgGrey:[100,49],bgRedBright:[101,49],bgGreenBright:[102,49],bgYellowBright:[103,49],bgBlueBright:[104,49],bgMagentaBright:[105,49],bgCyanBright:[106,49],bgWhiteBright:[107,49]}};Object.keys(r.modifier);const Z=Object.keys(r.color),H=Object.keys(r.bgColor);[...Z,...H];function U(){const t=new Map;for(const[u,F]of Object.entries(r)){for(const[e,s]of Object.entries(F))r[e]={open:`\x1B[${s[0]}m`,close:`\x1B[${s[1]}m`},F[e]=r[e],t.set(s[0],s[1]);Object.defineProperty(r,u,{value:F,enumerable:!1});}return Object.defineProperty(r,"codes",{value:t,enumerable:!1}),r.color.close="\x1B[39m",r.bgColor.close="\x1B[49m",r.color.ansi=L(),r.color.ansi256=M(),r.color.ansi16m=T(),r.bgColor.ansi=L(v),r.bgColor.ansi256=M(v),r.bgColor.ansi16m=T(v),Object.defineProperties(r,{rgbToAnsi256:{value:(u,F,e)=>u===F&&F===e?u<8?16:u>248?231:Math.round((u-8)/247*24)+232:16+36*Math.round(u/255*5)+6*Math.round(F/255*5)+Math.round(e/255*5),enumerable:!1},hexToRgb:{value:u=>{const F=/[a-f\d]{6}|[a-f\d]{3}/i.exec(u.toString(16));if(!F)return [0,0,0];let[e]=F;e.length===3&&(e=[...e].map(C=>C+C).join(""));const s=Number.parseInt(e,16);return [s>>16&255,s>>8&255,s&255]},enumerable:!1},hexToAnsi256:{value:u=>r.rgbToAnsi256(...r.hexToRgb(u)),enumerable:!1},ansi256ToAnsi:{value:u=>{if(u<8)return 30+u;if(u<16)return 90+(u-8);let F,e,s;if(u>=232)F=((u-232)*10+8)/255,e=F,s=F;else {u-=16;const i=u%36;F=Math.floor(u/36)/5,e=Math.floor(i/6)/5,s=i%6/5;}const C=Math.max(F,e,s)*2;if(C===0)return 30;let D=30+(Math.round(s)<<2|Math.round(e)<<1|Math.round(F));return C===2&&(D+=60),D},enumerable:!1},rgbToAnsi:{value:(u,F,e)=>r.ansi256ToAnsi(r.rgbToAnsi256(u,F,e)),enumerable:!1},hexToAnsi:{value:u=>r.ansi256ToAnsi(r.hexToAnsi256(u)),enumerable:!1}}),r}const q=U(),p=new Set(["\x1B","\x9B"]),J=39,b="\x07",W="[",Q="]",I="m",w=`${Q}8;;`,N=t=>`${p.values().next().value}${W}${t}${I}`,j=t=>`${p.values().next().value}${w}${t}${b}`,X=t=>t.split(" ").map(u=>c(u)),_=(t,u,F)=>{const e=[...u];let s=!1,C=!1,D=c($(t[t.length-1]));for(const[i,o]of e.entries()){const E=c(o);if(D+E<=F?t[t.length-1]+=o:(t.push(o),D=0),p.has(o)&&(s=!0,C=e.slice(i+1).join("").startsWith(w)),s){C?o===b&&(s=!1,C=!1):o===I&&(s=!1);continue}D+=E,D===F&&i0&&t.length>1&&(t[t.length-2]+=t.pop());},DD=t=>{const u=t.split(" ");let F=u.length;for(;F>0&&!(c(u[F-1])>0);)F--;return F===u.length?t:u.slice(0,F).join(" ")+u.slice(F).join("")},uD=(t,u,F={})=>{if(F.trim!==!1&&t.trim()==="")return "";let e="",s,C;const D=X(t);let i=[""];for(const[E,a]of t.split(" ").entries()){F.trim!==!1&&(i[i.length-1]=i[i.length-1].trimStart());let n=c(i[i.length-1]);if(E!==0&&(n>=u&&(F.wordWrap===!1||F.trim===!1)&&(i.push(""),n=0),(n>0||F.trim===!1)&&(i[i.length-1]+=" ",n++)),F.hard&&D[E]>u){const B=u-n,A=1+Math.floor((D[E]-B-1)/u);Math.floor((D[E]-1)/u)u&&n>0&&D[E]>0){if(F.wordWrap===!1&&nu&&F.wordWrap===!1){_(i,a,u);continue}i[i.length-1]+=a;}F.trim!==!1&&(i=i.map(E=>DD(E)));const o=[...i.join(` +`)];for(const[E,a]of o.entries()){if(e+=a,p.has(a)){const{groups:B}=new RegExp(`(?:\\${W}(?\\d+)m|\\${w}(?.*)${b})`).exec(o.slice(E).join(""))||{groups:{}};if(B.code!==void 0){const A=Number.parseFloat(B.code);s=A===J?void 0:A;}else B.uri!==void 0&&(C=B.uri.length===0?void 0:B.uri);}const n=q.codes.get(Number(s));o[E+1]===` +`?(C&&(e+=j("")),s&&n&&(e+=N(n))):a===` +`&&(s&&n&&(e+=N(s)),C&&(e+=j(C)));}return e};function P(t,u,F){return String(t).normalize().replace(/\r\n/g,` +`).split(` +`).map(e=>uD(e,u,F)).join(` +`)}function FD(t,u){if(t===u)return;const F=t.split(` +`),e=u.split(` +`),s=[];for(let C=0;C{this._track&&(this.value=this.rl.line.replace(/\t/g,""),this._cursor=this.rl.cursor,this.emit("value",this.value)),s();},this.input.pipe(u),this.rl=f.createInterface({input:this.input,output:u,tabSize:2,prompt:"",escapeCodeTimeout:50}),f.emitKeypressEvents(this.input,this.rl),this.rl.prompt(),this.opts.initialValue!==void 0&&this._track&&this.rl.write(this.opts.initialValue),this.input.on("keypress",this.onKeypress),g(this.input,!0),this.output.on("resize",this.render),this.render(),new Promise((F,e)=>{this.once("submit",()=>{this.output.write(src.cursor.show),this.output.off("resize",this.render),g(this.input,!1),F(this.value);}),this.once("cancel",()=>{this.output.write(src.cursor.show),this.output.off("resize",this.render),g(this.input,!1),F(R);});})}on(u,F){const e=this.subscribers.get(u)??[];e.push({cb:F}),this.subscribers.set(u,e);}once(u,F){const e=this.subscribers.get(u)??[];e.push({cb:F,once:!0}),this.subscribers.set(u,e);}emit(u,...F){const e=this.subscribers.get(u)??[],s=[];for(const C of e)C.cb(...F),C.once&&s.push(()=>e.splice(e.indexOf(C),1));for(const C of s)C();}unsubscribe(){this.subscribers.clear();}onKeypress(u,F){if(this.state==="error"&&(this.state="active"),F?.name&&!this._track&&V.has(F.name)&&this.emit("cursor",V.get(F.name)),F?.name&&tD.has(F.name)&&this.emit("cursor",F.name),u&&(u.toLowerCase()==="y"||u.toLowerCase()==="n")&&this.emit("confirm",u.toLowerCase()==="y"),u&&this.emit("key",u.toLowerCase()),F?.name==="return"){if(this.opts.validate){const e=this.opts.validate(this.value);e&&(this.error=e,this.state="error",this.rl.write(this.value));}this.state!=="error"&&(this.state="submit");}u===""&&(this.state="cancel"),(this.state==="submit"||this.state==="cancel")&&this.emit("finalize"),this.render(),(this.state==="submit"||this.state==="cancel")&&this.close();}close(){this.input.unpipe(),this.input.removeListener("keypress",this.onKeypress),this.output.write(` +`),g(this.input,!1),this.rl.close(),this.emit(`${this.state}`,this.value),this.unsubscribe();}restoreCursor(){const u=P(this._prevFrame,process.stdout.columns,{hard:!0}).split(` +`).length-1;this.output.write(src.cursor.move(-999,u*-1));}render(){const u=P(this._render(this)??"",process.stdout.columns,{hard:!0});if(u!==this._prevFrame){if(this.state==="initial")this.output.write(src.cursor.hide);else {const F=FD(this._prevFrame,u);if(this.restoreCursor(),F&&F?.length===1){const e=F[0];this.output.write(src.cursor.move(0,e)),this.output.write(src.erase.lines(1));const s=u.split(` +`);this.output.write(s[e]),this._prevFrame=u,this.output.write(src.cursor.move(0,s.length-e-1));return}else if(F&&F?.length>1){const e=F[0];this.output.write(src.cursor.move(0,e)),this.output.write(src.erase.down());const C=u.split(` +`).slice(e);this.output.write(C.join(` +`)),this._prevFrame=u;return}this.output.write(src.erase.down());}this.output.write(u),this.state==="initial"&&(this.state="active"),this._prevFrame=u;}}}class sD extends h{get cursor(){return this.value?0:1}get _value(){return this.cursor===0}constructor(u){super(u,!1),this.value=!!u.initialValue,this.on("value",()=>{this.value=this._value;}),this.on("confirm",F=>{this.output.write(src.cursor.move(0,-1)),this.value=F,this.state="submit",this.close();}),this.on("cursor",()=>{this.value=!this.value;});}}class iD extends h{constructor(u){super(u,!1),this.cursor=0,this.options=u.options,this.value=[...u.initialValues??[]],this.cursor=Math.max(this.options.findIndex(({value:F})=>F===u.cursorAt),0),this.on("key",F=>{F==="a"&&this.toggleAll();}),this.on("cursor",F=>{switch(F){case"left":case"up":this.cursor=this.cursor===0?this.options.length-1:this.cursor-1;break;case"down":case"right":this.cursor=this.cursor===this.options.length-1?0:this.cursor+1;break;case"space":this.toggleValue();break}});}get _value(){return this.options[this.cursor].value}toggleAll(){const u=this.value.length===this.options.length;this.value=u?[]:this.options.map(F=>F.value);}toggleValue(){const u=this.value.includes(this._value);this.value=u?this.value.filter(F=>F!==this._value):[...this.value,this._value];}}class ED extends h{constructor(u){super(u,!1),this.cursor=0,this.options=u.options,this.cursor=this.options.findIndex(({value:F})=>F===u.initialValue),this.cursor===-1&&(this.cursor=0),this.changeValue(),this.on("cursor",F=>{switch(F){case"left":case"up":this.cursor=this.cursor===0?this.options.length-1:this.cursor-1;break;case"down":case"right":this.cursor=this.cursor===this.options.length-1?0:this.cursor+1;break}this.changeValue();});}get _value(){return this.options[this.cursor]}changeValue(){this.value=this._value.value;}}class oD extends h{constructor(u){super(u),this.valueWithCursor="",this.on("finalize",()=>{this.value||(this.value=u.defaultValue),this.valueWithCursor=this.value;}),this.on("value",()=>{if(this.cursor>=this.value.length)this.valueWithCursor=`${this.value}${l.inverse(l.hidden("_"))}`;else {const F=this.value.slice(0,this.cursor),e=this.value.slice(this.cursor);this.valueWithCursor=`${F}${l.inverse(e[0])}${e.slice(1)}`;}});}get cursor(){return this._cursor}} + +const unicode = isUnicodeSupported(); +const s = (c, fallback) => unicode ? c : fallback; +const S_STEP_ACTIVE = s("\u276F", ">"); +const S_STEP_CANCEL = s("\u25A0", "x"); +const S_STEP_ERROR = s("\u25B2", "x"); +const S_STEP_SUBMIT = s("\u2714", "\u221A"); +const S_BAR = ""; +const S_BAR_END = ""; +const S_RADIO_ACTIVE = s("\u25CF", ">"); +const S_RADIO_INACTIVE = s("\u25CB", " "); +const S_CHECKBOX_ACTIVE = s("\u25FB", "[\u2022]"); +const S_CHECKBOX_SELECTED = s("\u25FC", "[+]"); +const S_CHECKBOX_INACTIVE = s("\u25FB", "[ ]"); +const symbol = (state) => { + switch (state) { + case "initial": + case "active": { + return colors.cyan(S_STEP_ACTIVE); + } + case "cancel": { + return colors.red(S_STEP_CANCEL); + } + case "error": { + return colors.yellow(S_STEP_ERROR); + } + case "submit": { + return colors.green(S_STEP_SUBMIT); + } + } +}; +const text = (opts) => { + return new oD({ + validate: opts.validate, + placeholder: opts.placeholder, + defaultValue: opts.defaultValue, + initialValue: opts.initialValue, + render() { + const title = `${colors.gray(S_BAR)} +${symbol(this.state)} ${opts.message} +`; + const placeholder = opts.placeholder ? colors.inverse(opts.placeholder[0]) + colors.dim(opts.placeholder.slice(1)) : colors.inverse(colors.hidden("_")); + const value = this.value ? this.valueWithCursor : placeholder; + switch (this.state) { + case "error": { + return `${title.trim()} +${colors.yellow( + S_BAR + )} ${value} +${colors.yellow(S_BAR_END)} ${colors.yellow( + this.error + )} +`; + } + case "submit": { + return `${title}${colors.gray(S_BAR)} ${colors.dim( + this.value || opts.placeholder + )}`; + } + case "cancel": { + return `${title}${colors.gray(S_BAR)} ${colors.strikethrough( + colors.dim(this.value ?? "") + )}${this.value?.trim() ? "\n" + colors.gray(S_BAR) : ""}`; + } + default: { + return `${title}${colors.cyan(S_BAR)} ${value} +${colors.cyan( + S_BAR_END + )} +`; + } + } + } + }).prompt(); +}; +const confirm = (opts) => { + const active = opts.active ?? "Yes"; + const inactive = opts.inactive ?? "No"; + return new sD({ + active, + inactive, + initialValue: opts.initialValue ?? true, + render() { + const title = `${colors.gray(S_BAR)} +${symbol(this.state)} ${opts.message} +`; + const value = this.value ? active : inactive; + switch (this.state) { + case "submit": { + return `${title}${colors.gray(S_BAR)} ${colors.dim(value)}`; + } + case "cancel": { + return `${title}${colors.gray(S_BAR)} ${colors.strikethrough( + colors.dim(value) + )} +${colors.gray(S_BAR)}`; + } + default: { + return `${title}${colors.cyan(S_BAR)} ${this.value ? `${colors.green(S_RADIO_ACTIVE)} ${active}` : `${colors.dim(S_RADIO_INACTIVE)} ${colors.dim(active)}`} ${colors.dim("/")} ${this.value ? `${colors.dim(S_RADIO_INACTIVE)} ${colors.dim(inactive)}` : `${colors.green(S_RADIO_ACTIVE)} ${inactive}`} +${colors.cyan(S_BAR_END)} +`; + } + } + } + }).prompt(); +}; +const select = (opts) => { + const opt = (option, state) => { + const label = option.label ?? String(option.value); + switch (state) { + case "active": { + return `${colors.green(S_RADIO_ACTIVE)} ${label} ${option.hint ? colors.dim(`(${option.hint})`) : ""}`; + } + case "selected": { + return `${colors.dim(label)}`; + } + case "cancelled": { + return `${colors.strikethrough(colors.dim(label))}`; + } + } + return `${colors.dim(S_RADIO_INACTIVE)} ${colors.dim(label)}`; + }; + return new ED({ + options: opts.options, + initialValue: opts.initialValue, + render() { + const title = `${colors.gray(S_BAR)} +${symbol(this.state)} ${opts.message} +`; + switch (this.state) { + case "submit": { + return `${title}${colors.gray(S_BAR)} ${opt( + this.options[this.cursor], + "selected" + )}`; + } + case "cancel": { + return `${title}${colors.gray(S_BAR)} ${opt( + this.options[this.cursor], + "cancelled" + )} +${colors.gray(S_BAR)}`; + } + default: { + return `${title}${colors.cyan(S_BAR)} ${this.options.map( + (option, i) => opt(option, i === this.cursor ? "active" : "inactive") + ).join(` +${colors.cyan(S_BAR)} `)} +${colors.cyan(S_BAR_END)} +`; + } + } + } + }).prompt(); +}; +const multiselect = (opts) => { + const opt = (option, state) => { + const label = option.label ?? String(option.value); + switch (state) { + case "active": { + return `${colors.cyan(S_CHECKBOX_ACTIVE)} ${label} ${option.hint ? colors.dim(`(${option.hint})`) : ""}`; + } + case "selected": { + return `${colors.green(S_CHECKBOX_SELECTED)} ${colors.dim(label)}`; + } + case "cancelled": { + return `${colors.strikethrough(colors.dim(label))}`; + } + case "active-selected": { + return `${colors.green(S_CHECKBOX_SELECTED)} ${label} ${option.hint ? colors.dim(`(${option.hint})`) : ""}`; + } + case "submitted": { + return `${colors.dim(label)}`; + } + } + return `${colors.dim(S_CHECKBOX_INACTIVE)} ${colors.dim(label)}`; + }; + return new iD({ + options: opts.options, + initialValues: opts.initialValues, + required: opts.required ?? true, + cursorAt: opts.cursorAt, + validate(selected) { + if (this.required && selected.length === 0) { + return `Please select at least one option. +${colors.reset( + colors.dim( + `Press ${colors.gray( + colors.bgWhite(colors.inverse(" space ")) + )} to select, ${colors.gray( + colors.bgWhite(colors.inverse(" enter ")) + )} to submit` + ) + )}`; + } + }, + render() { + const title = `${colors.gray(S_BAR)} +${symbol(this.state)} ${opts.message} +`; + switch (this.state) { + case "submit": { + return `${title}${colors.gray(S_BAR)} ${this.options.filter(({ value }) => this.value.includes(value)).map((option) => opt(option, "submitted")).join(colors.dim(", ")) || colors.dim("none")}`; + } + case "cancel": { + const label = this.options.filter(({ value }) => this.value.includes(value)).map((option) => opt(option, "cancelled")).join(colors.dim(", ")); + return `${title}${colors.gray(S_BAR)} ${label.trim() ? `${label} +${colors.gray(S_BAR)}` : ""}`; + } + case "error": { + const footer = this.error.split("\n").map( + (ln, i) => i === 0 ? `${colors.yellow(S_BAR_END)} ${colors.yellow(ln)}` : ` ${ln}` + ).join("\n"); + return title + colors.yellow(S_BAR) + " " + this.options.map((option, i) => { + const selected = this.value.includes(option.value); + const active = i === this.cursor; + if (active && selected) { + return opt(option, "active-selected"); + } + if (selected) { + return opt(option, "selected"); + } + return opt(option, active ? "active" : "inactive"); + }).join(` +${colors.yellow(S_BAR)} `) + "\n" + footer + "\n"; + } + default: { + return `${title}${colors.cyan(S_BAR)} ${this.options.map((option, i) => { + const selected = this.value.includes(option.value); + const active = i === this.cursor; + if (active && selected) { + return opt(option, "active-selected"); + } + if (selected) { + return opt(option, "selected"); + } + return opt(option, active ? "active" : "inactive"); + }).join(` +${colors.cyan(S_BAR)} `)} +${colors.cyan(S_BAR_END)} +`; + } + } + } + }).prompt(); +}; + +async function prompt(message, opts = {}) { + if (!opts.type || opts.type === "text") { + return await text({ + message, + defaultValue: opts.default, + placeholder: opts.placeholder, + initialValue: opts.initial + }); + } + if (opts.type === "confirm") { + return await confirm({ + message, + initialValue: opts.initial + }); + } + if (opts.type === "select") { + return await select({ + message, + options: opts.options.map( + (o) => typeof o === "string" ? { value: o, label: o } : o + ) + }); + } + if (opts.type === "multiselect") { + return await multiselect({ + message, + options: opts.options.map( + (o) => typeof o === "string" ? { value: o, label: o } : o + ), + required: opts.required + }); + } + throw new Error(`Unknown prompt type: ${opts.type}`); +} + +export { prompt }; diff --git a/.pnpm-store/v3/files/3d/2d3c15ab6149c0a115e870b0978a8cdce7d229b90ad0c4c0933a52f30beac6ceeb7f61831d67b7128e651cccdcf65a6ed69c3b25a4bf1d7fc96272814cfd17 b/.pnpm-store/v3/files/3d/2d3c15ab6149c0a115e870b0978a8cdce7d229b90ad0c4c0933a52f30beac6ceeb7f61831d67b7128e651cccdcf65a6ed69c3b25a4bf1d7fc96272814cfd17 new file mode 100644 index 0000000000000000000000000000000000000000..75816f5ea31c5619f1faf40ad7f66a09bf71b2b9 --- /dev/null +++ b/.pnpm-store/v3/files/3d/2d3c15ab6149c0a115e870b0978a8cdce7d229b90ad0c4c0933a52f30beac6ceeb7f61831d67b7128e651cccdcf65a6ed69c3b25a4bf1d7fc96272814cfd17 @@ -0,0 +1,29902 @@ +import { createServer as createServer$2 } from 'node:http'; +import { createServer as createServer$1 } from 'node:https'; +import { promisify } from 'node:util'; +import { createServer } from 'node:net'; +import os, { networkInterfaces } from 'node:os'; +import { g as getDefaultExportFromCjs, c as commonjsGlobal } from '../shared/nuxi.2155838d.mjs'; +import require$$2 from 'http'; +import require$$1 from 'https'; +import { c as consola, g as getColor, a as colors, b as d } from '../shared/nuxi.9edf0930.mjs'; +import { join } from 'node:path'; +import 'node:process'; +import 'node:tty'; +import { d as defu } from '../shared/nuxi.eaa29140.mjs'; +import childProcess from 'node:child_process'; +import fs, { statSync, readFileSync, promises, accessSync, constants } from 'node:fs'; +import require$$1$1 from 'crypto'; +import 'node:fs/promises'; +import { a as relative } from '../shared/nuxi.610c92ff.mjs'; +import 'node:url'; + +const unsafePorts = /* @__PURE__ */ new Set([ + 1, + // tcpmux + 7, + // echo + 9, + // discard + 11, + // systat + 13, + // daytime + 15, + // netstat + 17, + // qotd + 19, + // chargen + 20, + // ftp data + 21, + // ftp access + 22, + // ssh + 23, + // telnet + 25, + // smtp + 37, + // time + 42, + // name + 43, + // nicname + 53, + // domain + 69, + // tftp + 77, + // priv-rjs + 79, + // finger + 87, + // ttylink + 95, + // supdup + 101, + // hostriame + 102, + // iso-tsap + 103, + // gppitnp + 104, + // acr-nema + 109, + // pop2 + 110, + // pop3 + 111, + // sunrpc + 113, + // auth + 115, + // sftp + 117, + // uucp-path + 119, + // nntp + 123, + // NTP + 135, + // loc-srv /epmap + 137, + // netbios + 139, + // netbios + 143, + // imap2 + 161, + // snmp + 179, + // BGP + 389, + // ldap + 427, + // SLP (Also used by Apple Filing Protocol) + 465, + // smtp+ssl + 512, + // print / exec + 513, + // login + 514, + // shell + 515, + // printer + 526, + // tempo + 530, + // courier + 531, + // chat + 532, + // netnews + 540, + // uucp + 548, + // AFP (Apple Filing Protocol) + 554, + // rtsp + 556, + // remotefs + 563, + // nntp+ssl + 587, + // smtp (rfc6409) + 601, + // syslog-conn (rfc3195) + 636, + // ldap+ssl + 989, + // ftps-data + 990, + // ftps + 993, + // ldap+ssl + 995, + // pop3+ssl + 1719, + // h323gatestat + 1720, + // h323hostcall + 1723, + // pptp + 2049, + // nfs + 3659, + // apple-sasl / PasswordServer + 4045, + // lockd + 5060, + // sip + 5061, + // sips + 6e3, + // X11 + 6566, + // sane-port + 6665, + // Alternate IRC [Apple addition] + 6666, + // Alternate IRC [Apple addition] + 6667, + // Standard IRC [Apple addition] + 6668, + // Alternate IRC [Apple addition] + 6669, + // Alternate IRC [Apple addition] + 6697, + // IRC + TLS + 10080 + // Amanda +]); +function isUnsafePort(port) { + return unsafePorts.has(port); +} +function isSafePort(port) { + return !isUnsafePort(port); +} + +var __defProp$1 = Object.defineProperty; +var __defNormalProp$1 = (obj, key, value) => key in obj ? __defProp$1(obj, key, { enumerable: true, configurable: true, writable: true, value }) : obj[key] = value; +var __publicField$1 = (obj, key, value) => { + __defNormalProp$1(obj, typeof key !== "symbol" ? key + "" : key, value); + return value; +}; +class GetPortError extends Error { + constructor(message, opts) { + super(message, opts); + this.message = message; + __publicField$1(this, "name", "GetPortError"); + } +} +function _log(verbose, message) { + if (verbose) { + console.log(`[get-port] ${message}`); + } +} +function _generateRange(from, to) { + if (to < from) { + return []; + } + const r = []; + for (let index = from; index <= to; index++) { + r.push(index); + } + return r; +} +function _tryPort(port, host) { + return new Promise((resolve) => { + const server = createServer(); + server.unref(); + server.on("error", () => { + resolve(false); + }); + server.listen({ port, host }, () => { + const { port: port2 } = server.address(); + server.close(() => { + resolve(isSafePort(port2) && port2); + }); + }); + }); +} +function _getLocalHosts(additional) { + const hosts = new Set(additional); + for (const _interface of Object.values(networkInterfaces())) { + for (const config of _interface || []) { + if (config.address && !config.internal && !config.address.startsWith("fe80::")) { + hosts.add(config.address); + } + } + } + return [...hosts]; +} +async function _findPort(ports, host) { + for (const port of ports) { + const r = await _tryPort(port, host); + if (r) { + return r; + } + } +} +function _fmtOnHost(hostname) { + return hostname ? `on host ${JSON.stringify(hostname)}` : "on any host"; +} +const HOSTNAME_RE$1 = /^(?!-)[\d.:A-Za-z-]{1,63}(? { + if (!port) { + return false; + } + if (!isSafePort(port)) { + _log(options.verbose, `Ignoring unsafe port: ${port}`); + return false; + } + return true; + }); + if (portsToCheck.length === 0) { + portsToCheck.push(3e3); + } + let availablePort = await _findPort(portsToCheck, options.host); + if (!availablePort && options.alternativePortRange.length > 0) { + availablePort = await _findPort( + _generateRange(...options.alternativePortRange), + options.host + ); + if (portsToCheck.length > 0) { + let message = `Unable to find an available port (tried ${portsToCheck.join( + "-" + )} ${_fmtOnHost(options.host)}).`; + if (availablePort) { + message += ` Using alternative port ${availablePort}.`; + } + _log(options.verbose, message); + } + } + if (!availablePort && _userOptions.random !== false) { + availablePort = await getRandomPort(options.host); + if (availablePort) { + _log(options.verbose, `Using random port ${availablePort}`); + } + } + if (!availablePort) { + const triedRanges = [ + options.port, + options.portRange.join("-"), + options.alternativePortRange.join("-") + ].filter(Boolean).join(", "); + throw new GetPortError( + `Unable to find an available port ${_fmtOnHost( + options.host + )} (tried ${triedRanges})` + ); + } + return availablePort; +} +async function getRandomPort(host) { + const port = await checkPort(0, host); + if (port === false) { + throw new GetPortError(`Unable to find a random port ${_fmtOnHost(host)}`); + } + return port; +} +async function checkPort(port, host = process.env.HOST, verbose) { + if (!host) { + host = _getLocalHosts([void 0, "0.0.0.0"]); + } + if (!Array.isArray(host)) { + return _tryPort(port, host); + } + for (const _host of host) { + const _port = await _tryPort(port, _host); + if (_port === false) { + if (port < 1024 && verbose) { + _log( + verbose, + `Unable to listen to the privileged port ${port} ${_fmtOnHost( + _host + )}` + ); + } + return false; + } + if (port === 0 && _port !== 0) { + port = _port; + } + } + return port; +} + +var httpShutdown = {exports: {}}; + +(function (module, exports) { + var http = require$$2; + var https = require$$1; + + /** + * Expose `addShutdown`. + */ + exports = module.exports = addShutdown; + + /** + * Adds shutdown functionaility to the `http.Server` object + * @param {http.Server} server The server to add shutdown functionaility to + */ + function addShutdown(server) { + var connections = {}; + var isShuttingDown = false; + var connectionCounter = 0; + + function destroy(socket, force) { + if (force || (socket._isIdle && isShuttingDown)) { + socket.destroy(); + delete connections[socket._connectionId]; + } + } + function onConnection(socket) { + var id = connectionCounter++; + socket._isIdle = true; + socket._connectionId = id; + connections[id] = socket; + + socket.on('close', function() { + delete connections[id]; + }); + } + server.on('request', function(req, res) { + req.socket._isIdle = false; + + res.on('finish', function() { + req.socket._isIdle = true; + destroy(req.socket); + }); + }); + + server.on('connection', onConnection); + server.on('secureConnection', onConnection); + + function shutdown(force, cb) { + isShuttingDown = true; + server.close(function(err) { + if (cb) { + process.nextTick(function() { cb(err); }); + } + }); + + Object.keys(connections).forEach(function(key) { + destroy(connections[key], force); + }); + } + server.shutdown = function(cb) { + shutdown(false, cb); + }; + + server.forceShutdown = function(cb) { + shutdown(true, cb); + }; + + return server; + } + /** + * Extends the {http.Server} object with shutdown functionaility. + * @return {http.Server} The decorated server object + */ + exports.extend = function() { + http.Server.prototype.withShutdown = function() { + return addShutdown(this); + }; + + https.Server.prototype.withShutdown = function() { + return addShutdown(this); + }; + }; +} (httpShutdown, httpShutdown.exports)); + +var httpShutdownExports = httpShutdown.exports; +const addShutdown = /*@__PURE__*/getDefaultExportFromCjs(httpShutdownExports); + +var QrCodeDataType = /* @__PURE__ */ ((QrCodeDataType2) => { + QrCodeDataType2[QrCodeDataType2["Border"] = -1] = "Border"; + QrCodeDataType2[QrCodeDataType2["Data"] = 0] = "Data"; + QrCodeDataType2[QrCodeDataType2["Function"] = 1] = "Function"; + QrCodeDataType2[QrCodeDataType2["Position"] = 2] = "Position"; + QrCodeDataType2[QrCodeDataType2["Timing"] = 3] = "Timing"; + QrCodeDataType2[QrCodeDataType2["Alignment"] = 4] = "Alignment"; + return QrCodeDataType2; +})(QrCodeDataType || {}); + +var __defProp = Object.defineProperty; +var __defNormalProp = (obj, key, value) => key in obj ? __defProp(obj, key, { enumerable: true, configurable: true, writable: true, value }) : obj[key] = value; +var __publicField = (obj, key, value) => { + __defNormalProp(obj, typeof key !== "symbol" ? key + "" : key, value); + return value; +}; +const LOW = [0, 1]; +const MEDIUM = [1, 0]; +const QUARTILE = [2, 3]; +const HIGH = [3, 2]; +const EccMap = { + L: LOW, + M: MEDIUM, + Q: QUARTILE, + H: HIGH +}; +const NUMERIC_REGEX = /^[0-9]*$/; +const ALPHANUMERIC_REGEX = /^[A-Z0-9 $%*+.\/:-]*$/; +const ALPHANUMERIC_CHARSET = "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ $%*+-./:"; +const MIN_VERSION = 1; +const MAX_VERSION = 40; +const PENALTY_N1 = 3; +const PENALTY_N2 = 3; +const PENALTY_N3 = 40; +const PENALTY_N4 = 10; +const ECC_CODEWORDS_PER_BLOCK = [ + // Version: (note that index 0 is for padding, and is set to an illegal value) + // 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40 Error correction level + [-1, 7, 10, 15, 20, 26, 18, 20, 24, 30, 18, 20, 24, 26, 30, 22, 24, 28, 30, 28, 28, 28, 28, 30, 30, 26, 28, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30], + // Low + [-1, 10, 16, 26, 18, 24, 16, 18, 22, 22, 26, 30, 22, 22, 24, 24, 28, 28, 26, 26, 26, 26, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28], + // Medium + [-1, 13, 22, 18, 26, 18, 24, 18, 22, 20, 24, 28, 26, 24, 20, 30, 24, 28, 28, 26, 30, 28, 30, 30, 30, 30, 28, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30], + // Quartile + [-1, 17, 28, 22, 16, 22, 28, 26, 26, 24, 28, 24, 28, 22, 24, 24, 30, 28, 28, 26, 28, 30, 24, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30] + // High +]; +const NUM_ERROR_CORRECTION_BLOCKS = [ + // Version: (note that index 0 is for padding, and is set to an illegal value) + // 0, 1, 2, 3, 4, 5, 6, 7, 8, 9,10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40 Error correction level + [-1, 1, 1, 1, 1, 1, 2, 2, 2, 2, 4, 4, 4, 4, 4, 6, 6, 6, 6, 7, 8, 8, 9, 9, 10, 12, 12, 12, 13, 14, 15, 16, 17, 18, 19, 19, 20, 21, 22, 24, 25], + // Low + [-1, 1, 1, 1, 2, 2, 4, 4, 4, 5, 5, 5, 8, 9, 9, 10, 10, 11, 13, 14, 16, 17, 17, 18, 20, 21, 23, 25, 26, 28, 29, 31, 33, 35, 37, 38, 40, 43, 45, 47, 49], + // Medium + [-1, 1, 1, 2, 2, 4, 4, 6, 6, 8, 8, 8, 10, 12, 16, 12, 17, 16, 18, 21, 20, 23, 23, 25, 27, 29, 34, 34, 35, 38, 40, 43, 45, 48, 51, 53, 56, 59, 62, 65, 68], + // Quartile + [-1, 1, 1, 2, 4, 4, 4, 5, 6, 8, 8, 11, 11, 16, 16, 18, 16, 19, 21, 25, 25, 25, 34, 30, 32, 35, 37, 40, 42, 45, 48, 51, 54, 57, 60, 63, 66, 70, 74, 77, 81] + // High +]; +class QrCode { + /* -- Constructor (low level) and fields -- */ + // Creates a new QR Code with the given version number, + // error correction level, data codeword bytes, and mask number. + // This is a low-level API that most users should not use directly. + // A mid-level API is the encodeSegments() function. + constructor(version, ecc, dataCodewords, msk) { + this.version = version; + this.ecc = ecc; + /* -- Fields -- */ + // The width and height of this QR Code, measured in modules, between + // 21 and 177 (inclusive). This is equal to version * 4 + 17. + __publicField(this, "size"); + // The index of the mask pattern used in this QR Code, which is between 0 and 7 (inclusive). + // Even if a QR Code is created with automatic masking requested (mask = -1), + // the resulting object still has a mask value between 0 and 7. + __publicField(this, "mask"); + // The modules of this QR Code (false = light, true = dark). + // Immutable after constructor finishes. Accessed through getModule(). + __publicField(this, "modules", []); + __publicField(this, "types", []); + if (version < MIN_VERSION || version > MAX_VERSION) + throw new RangeError("Version value out of range"); + if (msk < -1 || msk > 7) + throw new RangeError("Mask value out of range"); + this.size = version * 4 + 17; + const row = Array.from({ length: this.size }, () => false); + for (let i = 0; i < this.size; i++) { + this.modules.push(row.slice()); + this.types.push(row.map(() => 0)); + } + this.drawFunctionPatterns(); + const allCodewords = this.addEccAndInterleave(dataCodewords); + this.drawCodewords(allCodewords); + if (msk === -1) { + let minPenalty = 1e9; + for (let i = 0; i < 8; i++) { + this.applyMask(i); + this.drawFormatBits(i); + const penalty = this.getPenaltyScore(); + if (penalty < minPenalty) { + msk = i; + minPenalty = penalty; + } + this.applyMask(i); + } + } + this.mask = msk; + this.applyMask(msk); + this.drawFormatBits(msk); + } + /* -- Accessor methods -- */ + // Returns the color of the module (pixel) at the given coordinates, which is false + // for light or true for dark. The top left corner has the coordinates (x=0, y=0). + // If the given coordinates are out of bounds, then false (light) is returned. + getModule(x, y) { + return x >= 0 && x < this.size && y >= 0 && y < this.size && this.modules[y][x]; + } + /* -- Private helper methods for constructor: Drawing function modules -- */ + // Reads this object's version field, and draws and marks all function modules. + drawFunctionPatterns() { + for (let i = 0; i < this.size; i++) { + this.setFunctionModule(6, i, i % 2 === 0, QrCodeDataType.Timing); + this.setFunctionModule(i, 6, i % 2 === 0, QrCodeDataType.Timing); + } + this.drawFinderPattern(3, 3); + this.drawFinderPattern(this.size - 4, 3); + this.drawFinderPattern(3, this.size - 4); + const alignPatPos = this.getAlignmentPatternPositions(); + const numAlign = alignPatPos.length; + for (let i = 0; i < numAlign; i++) { + for (let j = 0; j < numAlign; j++) { + if (!(i === 0 && j === 0 || i === 0 && j === numAlign - 1 || i === numAlign - 1 && j === 0)) + this.drawAlignmentPattern(alignPatPos[i], alignPatPos[j]); + } + } + this.drawFormatBits(0); + this.drawVersion(); + } + // Draws two copies of the format bits (with its own error correction code) + // based on the given mask and this object's error correction level field. + drawFormatBits(mask) { + const data = this.ecc[1] << 3 | mask; + let rem = data; + for (let i = 0; i < 10; i++) + rem = rem << 1 ^ (rem >>> 9) * 1335; + const bits = (data << 10 | rem) ^ 21522; + for (let i = 0; i <= 5; i++) + this.setFunctionModule(8, i, getBit(bits, i)); + this.setFunctionModule(8, 7, getBit(bits, 6)); + this.setFunctionModule(8, 8, getBit(bits, 7)); + this.setFunctionModule(7, 8, getBit(bits, 8)); + for (let i = 9; i < 15; i++) + this.setFunctionModule(14 - i, 8, getBit(bits, i)); + for (let i = 0; i < 8; i++) + this.setFunctionModule(this.size - 1 - i, 8, getBit(bits, i)); + for (let i = 8; i < 15; i++) + this.setFunctionModule(8, this.size - 15 + i, getBit(bits, i)); + this.setFunctionModule(8, this.size - 8, true); + } + // Draws two copies of the version bits (with its own error correction code), + // based on this object's version field, iff 7 <= version <= 40. + drawVersion() { + if (this.version < 7) + return; + let rem = this.version; + for (let i = 0; i < 12; i++) + rem = rem << 1 ^ (rem >>> 11) * 7973; + const bits = this.version << 12 | rem; + for (let i = 0; i < 18; i++) { + const color = getBit(bits, i); + const a = this.size - 11 + i % 3; + const b = Math.floor(i / 3); + this.setFunctionModule(a, b, color); + this.setFunctionModule(b, a, color); + } + } + // Draws a 9*9 finder pattern including the border separator, + // with the center module at (x, y). Modules can be out of bounds. + drawFinderPattern(x, y) { + for (let dy = -4; dy <= 4; dy++) { + for (let dx = -4; dx <= 4; dx++) { + const dist = Math.max(Math.abs(dx), Math.abs(dy)); + const xx = x + dx; + const yy = y + dy; + if (xx >= 0 && xx < this.size && yy >= 0 && yy < this.size) + this.setFunctionModule(xx, yy, dist !== 2 && dist !== 4, QrCodeDataType.Position); + } + } + } + // Draws a 5*5 alignment pattern, with the center module + // at (x, y). All modules must be in bounds. + drawAlignmentPattern(x, y) { + for (let dy = -2; dy <= 2; dy++) { + for (let dx = -2; dx <= 2; dx++) { + this.setFunctionModule( + x + dx, + y + dy, + Math.max(Math.abs(dx), Math.abs(dy)) !== 1, + QrCodeDataType.Alignment + ); + } + } + } + // Sets the color of a module and marks it as a function module. + // Only used by the constructor. Coordinates must be in bounds. + setFunctionModule(x, y, isDark, type = QrCodeDataType.Function) { + this.modules[y][x] = isDark; + this.types[y][x] = type; + } + /* -- Private helper methods for constructor: Codewords and masking -- */ + // Returns a new byte string representing the given data with the appropriate error correction + // codewords appended to it, based on this object's version and error correction level. + addEccAndInterleave(data) { + const ver = this.version; + const ecl = this.ecc; + if (data.length !== getNumDataCodewords(ver, ecl)) + throw new RangeError("Invalid argument"); + const numBlocks = NUM_ERROR_CORRECTION_BLOCKS[ecl[0]][ver]; + const blockEccLen = ECC_CODEWORDS_PER_BLOCK[ecl[0]][ver]; + const rawCodewords = Math.floor(getNumRawDataModules(ver) / 8); + const numShortBlocks = numBlocks - rawCodewords % numBlocks; + const shortBlockLen = Math.floor(rawCodewords / numBlocks); + const blocks = []; + const rsDiv = reedSolomonComputeDivisor(blockEccLen); + for (let i = 0, k = 0; i < numBlocks; i++) { + const dat = data.slice(k, k + shortBlockLen - blockEccLen + (i < numShortBlocks ? 0 : 1)); + k += dat.length; + const ecc = reedSolomonComputeRemainder(dat, rsDiv); + if (i < numShortBlocks) + dat.push(0); + blocks.push(dat.concat(ecc)); + } + const result = []; + for (let i = 0; i < blocks[0].length; i++) { + blocks.forEach((block, j) => { + if (i !== shortBlockLen - blockEccLen || j >= numShortBlocks) + result.push(block[i]); + }); + } + return result; + } + // Draws the given sequence of 8-bit codewords (data and error correction) onto the entire + // data area of this QR Code. Function modules need to be marked off before this is called. + drawCodewords(data) { + if (data.length !== Math.floor(getNumRawDataModules(this.version) / 8)) + throw new RangeError("Invalid argument"); + let i = 0; + for (let right = this.size - 1; right >= 1; right -= 2) { + if (right === 6) + right = 5; + for (let vert = 0; vert < this.size; vert++) { + for (let j = 0; j < 2; j++) { + const x = right - j; + const upward = (right + 1 & 2) === 0; + const y = upward ? this.size - 1 - vert : vert; + if (!this.types[y][x] && i < data.length * 8) { + this.modules[y][x] = getBit(data[i >>> 3], 7 - (i & 7)); + i++; + } + } + } + } + } + // XORs the codeword modules in this QR Code with the given mask pattern. + // The function modules must be marked and the codeword bits must be drawn + // before masking. Due to the arithmetic of XOR, calling applyMask() with + // the same mask value a second time will undo the mask. A final well-formed + // QR Code needs exactly one (not zero, two, etc.) mask applied. + applyMask(mask) { + if (mask < 0 || mask > 7) + throw new RangeError("Mask value out of range"); + for (let y = 0; y < this.size; y++) { + for (let x = 0; x < this.size; x++) { + let invert; + switch (mask) { + case 0: + invert = (x + y) % 2 === 0; + break; + case 1: + invert = y % 2 === 0; + break; + case 2: + invert = x % 3 === 0; + break; + case 3: + invert = (x + y) % 3 === 0; + break; + case 4: + invert = (Math.floor(x / 3) + Math.floor(y / 2)) % 2 === 0; + break; + case 5: + invert = x * y % 2 + x * y % 3 === 0; + break; + case 6: + invert = (x * y % 2 + x * y % 3) % 2 === 0; + break; + case 7: + invert = ((x + y) % 2 + x * y % 3) % 2 === 0; + break; + default: + throw new Error("Unreachable"); + } + if (!this.types[y][x] && invert) + this.modules[y][x] = !this.modules[y][x]; + } + } + } + // Calculates and returns the penalty score based on state of this QR Code's current modules. + // This is used by the automatic mask choice algorithm to find the mask pattern that yields the lowest score. + getPenaltyScore() { + let result = 0; + for (let y = 0; y < this.size; y++) { + let runColor = false; + let runX = 0; + const runHistory = [0, 0, 0, 0, 0, 0, 0]; + for (let x = 0; x < this.size; x++) { + if (this.modules[y][x] === runColor) { + runX++; + if (runX === 5) + result += PENALTY_N1; + else if (runX > 5) + result++; + } else { + this.finderPenaltyAddHistory(runX, runHistory); + if (!runColor) + result += this.finderPenaltyCountPatterns(runHistory) * PENALTY_N3; + runColor = this.modules[y][x]; + runX = 1; + } + } + result += this.finderPenaltyTerminateAndCount(runColor, runX, runHistory) * PENALTY_N3; + } + for (let x = 0; x < this.size; x++) { + let runColor = false; + let runY = 0; + const runHistory = [0, 0, 0, 0, 0, 0, 0]; + for (let y = 0; y < this.size; y++) { + if (this.modules[y][x] === runColor) { + runY++; + if (runY === 5) + result += PENALTY_N1; + else if (runY > 5) + result++; + } else { + this.finderPenaltyAddHistory(runY, runHistory); + if (!runColor) + result += this.finderPenaltyCountPatterns(runHistory) * PENALTY_N3; + runColor = this.modules[y][x]; + runY = 1; + } + } + result += this.finderPenaltyTerminateAndCount(runColor, runY, runHistory) * PENALTY_N3; + } + for (let y = 0; y < this.size - 1; y++) { + for (let x = 0; x < this.size - 1; x++) { + const color = this.modules[y][x]; + if (color === this.modules[y][x + 1] && color === this.modules[y + 1][x] && color === this.modules[y + 1][x + 1]) + result += PENALTY_N2; + } + } + let dark = 0; + for (const row of this.modules) + dark = row.reduce((sum, color) => sum + (color ? 1 : 0), dark); + const total = this.size * this.size; + const k = Math.ceil(Math.abs(dark * 20 - total * 10) / total) - 1; + result += k * PENALTY_N4; + return result; + } + /* -- Private helper functions -- */ + // Returns an ascending list of positions of alignment patterns for this version number. + // Each position is in the range [0,177), and are used on both the x and y axes. + // This could be implemented as lookup table of 40 variable-length lists of integers. + getAlignmentPatternPositions() { + if (this.version === 1) { + return []; + } else { + const numAlign = Math.floor(this.version / 7) + 2; + const step = this.version === 32 ? 26 : Math.ceil((this.version * 4 + 4) / (numAlign * 2 - 2)) * 2; + const result = [6]; + for (let pos = this.size - 7; result.length < numAlign; pos -= step) + result.splice(1, 0, pos); + return result; + } + } + // Can only be called immediately after a light run is added, and + // returns either 0, 1, or 2. A helper function for getPenaltyScore(). + finderPenaltyCountPatterns(runHistory) { + const n = runHistory[1]; + const core = n > 0 && runHistory[2] === n && runHistory[3] === n * 3 && runHistory[4] === n && runHistory[5] === n; + return (core && runHistory[0] >= n * 4 && runHistory[6] >= n ? 1 : 0) + (core && runHistory[6] >= n * 4 && runHistory[0] >= n ? 1 : 0); + } + // Must be called at the end of a line (row or column) of modules. A helper function for getPenaltyScore(). + finderPenaltyTerminateAndCount(currentRunColor, currentRunLength, runHistory) { + if (currentRunColor) { + this.finderPenaltyAddHistory(currentRunLength, runHistory); + currentRunLength = 0; + } + currentRunLength += this.size; + this.finderPenaltyAddHistory(currentRunLength, runHistory); + return this.finderPenaltyCountPatterns(runHistory); + } + // Pushes the given value to the front and drops the last value. A helper function for getPenaltyScore(). + finderPenaltyAddHistory(currentRunLength, runHistory) { + if (runHistory[0] === 0) + currentRunLength += this.size; + runHistory.pop(); + runHistory.unshift(currentRunLength); + } +} +function appendBits(val, len, bb) { + if (len < 0 || len > 31 || val >>> len !== 0) + throw new RangeError("Value out of range"); + for (let i = len - 1; i >= 0; i--) + bb.push(val >>> i & 1); +} +function getBit(x, i) { + return (x >>> i & 1) !== 0; +} +class QrSegment { + // Creates a new QR Code segment with the given attributes and data. + // The character count (numChars) must agree with the mode and the bit buffer length, + // but the constraint isn't checked. The given bit buffer is cloned and stored. + constructor(mode, numChars, bitData) { + this.mode = mode; + this.numChars = numChars; + this.bitData = bitData; + if (numChars < 0) + throw new RangeError("Invalid argument"); + this.bitData = bitData.slice(); + } + /* -- Methods -- */ + // Returns a new copy of the data bits of this segment. + getData() { + return this.bitData.slice(); + } +} +const MODE_NUMERIC = [1, 10, 12, 14]; +const MODE_ALPHANUMERIC = [2, 9, 11, 13]; +const MODE_BYTE = [4, 8, 16, 16]; +function numCharCountBits(mode, ver) { + return mode[Math.floor((ver + 7) / 17) + 1]; +} +function makeBytes(data) { + const bb = []; + for (const b of data) + appendBits(b, 8, bb); + return new QrSegment(MODE_BYTE, data.length, bb); +} +function makeNumeric(digits) { + if (!isNumeric(digits)) + throw new RangeError("String contains non-numeric characters"); + const bb = []; + for (let i = 0; i < digits.length; ) { + const n = Math.min(digits.length - i, 3); + appendBits(Number.parseInt(digits.substring(i, i + n), 10), n * 3 + 1, bb); + i += n; + } + return new QrSegment(MODE_NUMERIC, digits.length, bb); +} +function makeAlphanumeric(text) { + if (!isAlphanumeric(text)) + throw new RangeError("String contains unencodable characters in alphanumeric mode"); + const bb = []; + let i; + for (i = 0; i + 2 <= text.length; i += 2) { + let temp = ALPHANUMERIC_CHARSET.indexOf(text.charAt(i)) * 45; + temp += ALPHANUMERIC_CHARSET.indexOf(text.charAt(i + 1)); + appendBits(temp, 11, bb); + } + if (i < text.length) + appendBits(ALPHANUMERIC_CHARSET.indexOf(text.charAt(i)), 6, bb); + return new QrSegment(MODE_ALPHANUMERIC, text.length, bb); +} +function makeSegments(text) { + if (text === "") + return []; + else if (isNumeric(text)) + return [makeNumeric(text)]; + else if (isAlphanumeric(text)) + return [makeAlphanumeric(text)]; + else + return [makeBytes(toUtf8ByteArray(text))]; +} +function isNumeric(text) { + return NUMERIC_REGEX.test(text); +} +function isAlphanumeric(text) { + return ALPHANUMERIC_REGEX.test(text); +} +function getTotalBits(segs, version) { + let result = 0; + for (const seg of segs) { + const ccbits = numCharCountBits(seg.mode, version); + if (seg.numChars >= 1 << ccbits) + return Number.POSITIVE_INFINITY; + result += 4 + ccbits + seg.bitData.length; + } + return result; +} +function toUtf8ByteArray(str) { + str = encodeURI(str); + const result = []; + for (let i = 0; i < str.length; i++) { + if (str.charAt(i) !== "%") { + result.push(str.charCodeAt(i)); + } else { + result.push(Number.parseInt(str.substring(i + 1, i + 3), 16)); + i += 2; + } + } + return result; +} +function getNumRawDataModules(ver) { + if (ver < MIN_VERSION || ver > MAX_VERSION) + throw new RangeError("Version number out of range"); + let result = (16 * ver + 128) * ver + 64; + if (ver >= 2) { + const numAlign = Math.floor(ver / 7) + 2; + result -= (25 * numAlign - 10) * numAlign - 55; + if (ver >= 7) + result -= 36; + } + return result; +} +function getNumDataCodewords(ver, ecl) { + return Math.floor(getNumRawDataModules(ver) / 8) - ECC_CODEWORDS_PER_BLOCK[ecl[0]][ver] * NUM_ERROR_CORRECTION_BLOCKS[ecl[0]][ver]; +} +function reedSolomonComputeDivisor(degree) { + if (degree < 1 || degree > 255) + throw new RangeError("Degree out of range"); + const result = []; + for (let i = 0; i < degree - 1; i++) + result.push(0); + result.push(1); + let root = 1; + for (let i = 0; i < degree; i++) { + for (let j = 0; j < result.length; j++) { + result[j] = reedSolomonMultiply(result[j], root); + if (j + 1 < result.length) + result[j] ^= result[j + 1]; + } + root = reedSolomonMultiply(root, 2); + } + return result; +} +function reedSolomonComputeRemainder(data, divisor) { + const result = divisor.map((_) => 0); + for (const b of data) { + const factor = b ^ result.shift(); + result.push(0); + divisor.forEach((coef, i) => result[i] ^= reedSolomonMultiply(coef, factor)); + } + return result; +} +function reedSolomonMultiply(x, y) { + if (x >>> 8 !== 0 || y >>> 8 !== 0) + throw new RangeError("Byte out of range"); + let z = 0; + for (let i = 7; i >= 0; i--) { + z = z << 1 ^ (z >>> 7) * 285; + z ^= (y >>> i & 1) * x; + } + return z; +} +function encodeSegments(segs, ecl, minVersion = 1, maxVersion = 40, mask = -1, boostEcl = true) { + if (!(MIN_VERSION <= minVersion && minVersion <= maxVersion && maxVersion <= MAX_VERSION) || mask < -1 || mask > 7) + throw new RangeError("Invalid value"); + let version; + let dataUsedBits; + for (version = minVersion; ; version++) { + const dataCapacityBits2 = getNumDataCodewords(version, ecl) * 8; + const usedBits = getTotalBits(segs, version); + if (usedBits <= dataCapacityBits2) { + dataUsedBits = usedBits; + break; + } + if (version >= maxVersion) + throw new RangeError("Data too long"); + } + for (const newEcl of [MEDIUM, QUARTILE, HIGH]) { + if (boostEcl && dataUsedBits <= getNumDataCodewords(version, newEcl) * 8) + ecl = newEcl; + } + const bb = []; + for (const seg of segs) { + appendBits(seg.mode[0], 4, bb); + appendBits(seg.numChars, numCharCountBits(seg.mode, version), bb); + for (const b of seg.getData()) + bb.push(b); + } + const dataCapacityBits = getNumDataCodewords(version, ecl) * 8; + appendBits(0, Math.min(4, dataCapacityBits - bb.length), bb); + appendBits(0, (8 - bb.length % 8) % 8, bb); + for (let padByte = 236; bb.length < dataCapacityBits; padByte ^= 236 ^ 17) + appendBits(padByte, 8, bb); + const dataCodewords = Array.from({ length: Math.ceil(bb.length / 8) }, () => 0); + bb.forEach((b, i) => dataCodewords[i >>> 3] |= b << 7 - (i & 7)); + return new QrCode(version, ecl, dataCodewords, mask); +} + +function encode(data, options) { + const { + ecc = "L", + boostEcc = false, + minVersion = 1, + maxVersion = 40, + maskPattern = -1, + border = 1 + } = options || {}; + const segment = typeof data === "string" ? makeSegments(data) : Array.isArray(data) ? [makeBytes(data)] : void 0; + if (!segment) + throw new Error(`uqr only supports encoding string and binary data, but got: ${typeof data}`); + const qr = encodeSegments( + segment, + EccMap[ecc], + minVersion, + maxVersion, + maskPattern, + boostEcc + ); + const result = addBorder({ + version: qr.version, + maskPattern: qr.mask, + size: qr.size, + data: qr.modules, + types: qr.types + }, border); + if (options?.invert) + result.data = result.data.map((row) => row.map((mod) => !mod)); + options?.onEncoded?.(result); + return result; +} +function addBorder(input, border = 1) { + if (!border) + return input; + const { size } = input; + const newSize = size + border * 2; + input.size = newSize; + input.data.forEach((row) => { + for (let i = 0; i < border; i++) { + row.unshift(false); + row.push(false); + } + }); + for (let i = 0; i < border; i++) { + input.data.unshift(Array.from({ length: newSize }, (_) => false)); + input.data.push(Array.from({ length: newSize }, (_) => false)); + } + const b = QrCodeDataType.Border; + input.types.forEach((row) => { + for (let i = 0; i < border; i++) { + row.unshift(b); + row.push(b); + } + }); + for (let i = 0; i < border; i++) { + input.types.unshift(Array.from({ length: newSize }, (_) => b)); + input.types.push(Array.from({ length: newSize }, (_) => b)); + } + return input; +} +function getDataAt(data, x, y, defaults = false) { + if (x < 0 || y < 0 || x >= data.length || y >= data.length) + return defaults; + return data[y][x]; +} +function renderUnicodeCompact(data, options = {}) { + const platte = { + WHITE_ALL: "\u2588", + WHITE_BLACK: "\u2580", + BLACK_WHITE: "\u2584", + BLACK_ALL: " " + }; + const result = encode(data, options); + const WHITE = false; + const BLACK = true; + const at = (x, y) => getDataAt(result.data, x, y, true); + const lines = []; + let line = ""; + for (let row = 0; row < result.size; row += 2) { + for (let col = 0; col < result.size; col++) { + if (at(col, row) === WHITE && at(col, row + 1) === WHITE) + line += platte.WHITE_ALL; + else if (at(col, row) === WHITE && at(col, row + 1) === BLACK) + line += platte.WHITE_BLACK; + else if (at(col, row) === BLACK && at(col, row + 1) === WHITE) + line += platte.BLACK_WHITE; + else + line += platte.BLACK_ALL; + } + lines.push(line); + line = ""; + } + return lines.join("\n"); +} + +/** + * Node.js module for Forge. + * + * @author Dave Longley + * + * Copyright 2011-2016 Digital Bazaar, Inc. + */ + +var forge$D = { + // default options + options: { + usePureJavaScript: false + } +}; + +/** + * Base-N/Base-X encoding/decoding functions. + * + * Original implementation from base-x: + * https://github.com/cryptocoinjs/base-x + * + * Which is MIT licensed: + * + * The MIT License (MIT) + * + * Copyright base-x contributors (c) 2016 + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER + * DEALINGS IN THE SOFTWARE. + */ + +var api = {}; +var baseN$1 = api; + +// baseN alphabet indexes +var _reverseAlphabets = {}; + +/** + * BaseN-encodes a Uint8Array using the given alphabet. + * + * @param input the Uint8Array to encode. + * @param maxline the maximum number of encoded characters per line to use, + * defaults to none. + * + * @return the baseN-encoded output string. + */ +api.encode = function(input, alphabet, maxline) { + if(typeof alphabet !== 'string') { + throw new TypeError('"alphabet" must be a string.'); + } + if(maxline !== undefined && typeof maxline !== 'number') { + throw new TypeError('"maxline" must be a number.'); + } + + var output = ''; + + if(!(input instanceof Uint8Array)) { + // assume forge byte buffer + output = _encodeWithByteBuffer(input, alphabet); + } else { + var i = 0; + var base = alphabet.length; + var first = alphabet.charAt(0); + var digits = [0]; + for(i = 0; i < input.length; ++i) { + for(var j = 0, carry = input[i]; j < digits.length; ++j) { + carry += digits[j] << 8; + digits[j] = carry % base; + carry = (carry / base) | 0; + } + + while(carry > 0) { + digits.push(carry % base); + carry = (carry / base) | 0; + } + } + + // deal with leading zeros + for(i = 0; input[i] === 0 && i < input.length - 1; ++i) { + output += first; + } + // convert digits to a string + for(i = digits.length - 1; i >= 0; --i) { + output += alphabet[digits[i]]; + } + } + + if(maxline) { + var regex = new RegExp('.{1,' + maxline + '}', 'g'); + output = output.match(regex).join('\r\n'); + } + + return output; +}; + +/** + * Decodes a baseN-encoded (using the given alphabet) string to a + * Uint8Array. + * + * @param input the baseN-encoded input string. + * + * @return the Uint8Array. + */ +api.decode = function(input, alphabet) { + if(typeof input !== 'string') { + throw new TypeError('"input" must be a string.'); + } + if(typeof alphabet !== 'string') { + throw new TypeError('"alphabet" must be a string.'); + } + + var table = _reverseAlphabets[alphabet]; + if(!table) { + // compute reverse alphabet + table = _reverseAlphabets[alphabet] = []; + for(var i = 0; i < alphabet.length; ++i) { + table[alphabet.charCodeAt(i)] = i; + } + } + + // remove whitespace characters + input = input.replace(/\s/g, ''); + + var base = alphabet.length; + var first = alphabet.charAt(0); + var bytes = [0]; + for(var i = 0; i < input.length; i++) { + var value = table[input.charCodeAt(i)]; + if(value === undefined) { + return; + } + + for(var j = 0, carry = value; j < bytes.length; ++j) { + carry += bytes[j] * base; + bytes[j] = carry & 0xff; + carry >>= 8; + } + + while(carry > 0) { + bytes.push(carry & 0xff); + carry >>= 8; + } + } + + // deal with leading zeros + for(var k = 0; input[k] === first && k < input.length - 1; ++k) { + bytes.push(0); + } + + if(typeof Buffer !== 'undefined') { + return Buffer.from(bytes.reverse()); + } + + return new Uint8Array(bytes.reverse()); +}; + +function _encodeWithByteBuffer(input, alphabet) { + var i = 0; + var base = alphabet.length; + var first = alphabet.charAt(0); + var digits = [0]; + for(i = 0; i < input.length(); ++i) { + for(var j = 0, carry = input.at(i); j < digits.length; ++j) { + carry += digits[j] << 8; + digits[j] = carry % base; + carry = (carry / base) | 0; + } + + while(carry > 0) { + digits.push(carry % base); + carry = (carry / base) | 0; + } + } + + var output = ''; + + // deal with leading zeros + for(i = 0; input.at(i) === 0 && i < input.length() - 1; ++i) { + output += first; + } + // convert digits to a string + for(i = digits.length - 1; i >= 0; --i) { + output += alphabet[digits[i]]; + } + + return output; +} + +/** + * Utility functions for web applications. + * + * @author Dave Longley + * + * Copyright (c) 2010-2018 Digital Bazaar, Inc. + */ + +var forge$C = forge$D; +var baseN = baseN$1; + +/* Utilities API */ +var util$1 = forge$C.util = forge$C.util || {}; + +// define setImmediate and nextTick +(function() { + // use native nextTick (unless we're in webpack) + // webpack (or better node-libs-browser polyfill) sets process.browser. + // this way we can detect webpack properly + if(typeof process !== 'undefined' && process.nextTick && !process.browser) { + util$1.nextTick = process.nextTick; + if(typeof setImmediate === 'function') { + util$1.setImmediate = setImmediate; + } else { + // polyfill setImmediate with nextTick, older versions of node + // (those w/o setImmediate) won't totally starve IO + util$1.setImmediate = util$1.nextTick; + } + return; + } + + // polyfill nextTick with native setImmediate + if(typeof setImmediate === 'function') { + util$1.setImmediate = function() { return setImmediate.apply(undefined, arguments); }; + util$1.nextTick = function(callback) { + return setImmediate(callback); + }; + return; + } + + /* Note: A polyfill upgrade pattern is used here to allow combining + polyfills. For example, MutationObserver is fast, but blocks UI updates, + so it needs to allow UI updates periodically, so it falls back on + postMessage or setTimeout. */ + + // polyfill with setTimeout + util$1.setImmediate = function(callback) { + setTimeout(callback, 0); + }; + + // upgrade polyfill to use postMessage + if(typeof window !== 'undefined' && + typeof window.postMessage === 'function') { + var msg = 'forge.setImmediate'; + var callbacks = []; + util$1.setImmediate = function(callback) { + callbacks.push(callback); + // only send message when one hasn't been sent in + // the current turn of the event loop + if(callbacks.length === 1) { + window.postMessage(msg, '*'); + } + }; + function handler(event) { + if(event.source === window && event.data === msg) { + event.stopPropagation(); + var copy = callbacks.slice(); + callbacks.length = 0; + copy.forEach(function(callback) { + callback(); + }); + } + } + window.addEventListener('message', handler, true); + } + + // upgrade polyfill to use MutationObserver + if(typeof MutationObserver !== 'undefined') { + // polyfill with MutationObserver + var now = Date.now(); + var attr = true; + var div = document.createElement('div'); + var callbacks = []; + new MutationObserver(function() { + var copy = callbacks.slice(); + callbacks.length = 0; + copy.forEach(function(callback) { + callback(); + }); + }).observe(div, {attributes: true}); + var oldSetImmediate = util$1.setImmediate; + util$1.setImmediate = function(callback) { + if(Date.now() - now > 15) { + now = Date.now(); + oldSetImmediate(callback); + } else { + callbacks.push(callback); + // only trigger observer when it hasn't been triggered in + // the current turn of the event loop + if(callbacks.length === 1) { + div.setAttribute('a', attr = !attr); + } + } + }; + } + + util$1.nextTick = util$1.setImmediate; +})(); + +// check if running under Node.js +util$1.isNodejs = + typeof process !== 'undefined' && process.versions && process.versions.node; + + +// 'self' will also work in Web Workers (instance of WorkerGlobalScope) while +// it will point to `window` in the main thread. +// To remain compatible with older browsers, we fall back to 'window' if 'self' +// is not available. +util$1.globalScope = (function() { + if(util$1.isNodejs) { + return commonjsGlobal; + } + + return typeof self === 'undefined' ? window : self; +})(); + +// define isArray +util$1.isArray = Array.isArray || function(x) { + return Object.prototype.toString.call(x) === '[object Array]'; +}; + +// define isArrayBuffer +util$1.isArrayBuffer = function(x) { + return typeof ArrayBuffer !== 'undefined' && x instanceof ArrayBuffer; +}; + +// define isArrayBufferView +util$1.isArrayBufferView = function(x) { + return x && util$1.isArrayBuffer(x.buffer) && x.byteLength !== undefined; +}; + +/** + * Ensure a bits param is 8, 16, 24, or 32. Used to validate input for + * algorithms where bit manipulation, JavaScript limitations, and/or algorithm + * design only allow for byte operations of a limited size. + * + * @param n number of bits. + * + * Throw Error if n invalid. + */ +function _checkBitsParam(n) { + if(!(n === 8 || n === 16 || n === 24 || n === 32)) { + throw new Error('Only 8, 16, 24, or 32 bits supported: ' + n); + } +} + +// TODO: set ByteBuffer to best available backing +util$1.ByteBuffer = ByteStringBuffer; + +/** Buffer w/BinaryString backing */ + +/** + * Constructor for a binary string backed byte buffer. + * + * @param [b] the bytes to wrap (either encoded as string, one byte per + * character, or as an ArrayBuffer or Typed Array). + */ +function ByteStringBuffer(b) { + // TODO: update to match DataBuffer API + + // the data in this buffer + this.data = ''; + // the pointer for reading from this buffer + this.read = 0; + + if(typeof b === 'string') { + this.data = b; + } else if(util$1.isArrayBuffer(b) || util$1.isArrayBufferView(b)) { + if(typeof Buffer !== 'undefined' && b instanceof Buffer) { + this.data = b.toString('binary'); + } else { + // convert native buffer to forge buffer + // FIXME: support native buffers internally instead + var arr = new Uint8Array(b); + try { + this.data = String.fromCharCode.apply(null, arr); + } catch(e) { + for(var i = 0; i < arr.length; ++i) { + this.putByte(arr[i]); + } + } + } + } else if(b instanceof ByteStringBuffer || + (typeof b === 'object' && typeof b.data === 'string' && + typeof b.read === 'number')) { + // copy existing buffer + this.data = b.data; + this.read = b.read; + } + + // used for v8 optimization + this._constructedStringLength = 0; +} +util$1.ByteStringBuffer = ByteStringBuffer; + +/* Note: This is an optimization for V8-based browsers. When V8 concatenates + a string, the strings are only joined logically using a "cons string" or + "constructed/concatenated string". These containers keep references to one + another and can result in very large memory usage. For example, if a 2MB + string is constructed by concatenating 4 bytes together at a time, the + memory usage will be ~44MB; so ~22x increase. The strings are only joined + together when an operation requiring their joining takes place, such as + substr(). This function is called when adding data to this buffer to ensure + these types of strings are periodically joined to reduce the memory + footprint. */ +var _MAX_CONSTRUCTED_STRING_LENGTH = 4096; +util$1.ByteStringBuffer.prototype._optimizeConstructedString = function(x) { + this._constructedStringLength += x; + if(this._constructedStringLength > _MAX_CONSTRUCTED_STRING_LENGTH) { + // this substr() should cause the constructed string to join + this.data.substr(0, 1); + this._constructedStringLength = 0; + } +}; + +/** + * Gets the number of bytes in this buffer. + * + * @return the number of bytes in this buffer. + */ +util$1.ByteStringBuffer.prototype.length = function() { + return this.data.length - this.read; +}; + +/** + * Gets whether or not this buffer is empty. + * + * @return true if this buffer is empty, false if not. + */ +util$1.ByteStringBuffer.prototype.isEmpty = function() { + return this.length() <= 0; +}; + +/** + * Puts a byte in this buffer. + * + * @param b the byte to put. + * + * @return this buffer. + */ +util$1.ByteStringBuffer.prototype.putByte = function(b) { + return this.putBytes(String.fromCharCode(b)); +}; + +/** + * Puts a byte in this buffer N times. + * + * @param b the byte to put. + * @param n the number of bytes of value b to put. + * + * @return this buffer. + */ +util$1.ByteStringBuffer.prototype.fillWithByte = function(b, n) { + b = String.fromCharCode(b); + var d = this.data; + while(n > 0) { + if(n & 1) { + d += b; + } + n >>>= 1; + if(n > 0) { + b += b; + } + } + this.data = d; + this._optimizeConstructedString(n); + return this; +}; + +/** + * Puts bytes in this buffer. + * + * @param bytes the bytes (as a binary encoded string) to put. + * + * @return this buffer. + */ +util$1.ByteStringBuffer.prototype.putBytes = function(bytes) { + this.data += bytes; + this._optimizeConstructedString(bytes.length); + return this; +}; + +/** + * Puts a UTF-16 encoded string into this buffer. + * + * @param str the string to put. + * + * @return this buffer. + */ +util$1.ByteStringBuffer.prototype.putString = function(str) { + return this.putBytes(util$1.encodeUtf8(str)); +}; + +/** + * Puts a 16-bit integer in this buffer in big-endian order. + * + * @param i the 16-bit integer. + * + * @return this buffer. + */ +util$1.ByteStringBuffer.prototype.putInt16 = function(i) { + return this.putBytes( + String.fromCharCode(i >> 8 & 0xFF) + + String.fromCharCode(i & 0xFF)); +}; + +/** + * Puts a 24-bit integer in this buffer in big-endian order. + * + * @param i the 24-bit integer. + * + * @return this buffer. + */ +util$1.ByteStringBuffer.prototype.putInt24 = function(i) { + return this.putBytes( + String.fromCharCode(i >> 16 & 0xFF) + + String.fromCharCode(i >> 8 & 0xFF) + + String.fromCharCode(i & 0xFF)); +}; + +/** + * Puts a 32-bit integer in this buffer in big-endian order. + * + * @param i the 32-bit integer. + * + * @return this buffer. + */ +util$1.ByteStringBuffer.prototype.putInt32 = function(i) { + return this.putBytes( + String.fromCharCode(i >> 24 & 0xFF) + + String.fromCharCode(i >> 16 & 0xFF) + + String.fromCharCode(i >> 8 & 0xFF) + + String.fromCharCode(i & 0xFF)); +}; + +/** + * Puts a 16-bit integer in this buffer in little-endian order. + * + * @param i the 16-bit integer. + * + * @return this buffer. + */ +util$1.ByteStringBuffer.prototype.putInt16Le = function(i) { + return this.putBytes( + String.fromCharCode(i & 0xFF) + + String.fromCharCode(i >> 8 & 0xFF)); +}; + +/** + * Puts a 24-bit integer in this buffer in little-endian order. + * + * @param i the 24-bit integer. + * + * @return this buffer. + */ +util$1.ByteStringBuffer.prototype.putInt24Le = function(i) { + return this.putBytes( + String.fromCharCode(i & 0xFF) + + String.fromCharCode(i >> 8 & 0xFF) + + String.fromCharCode(i >> 16 & 0xFF)); +}; + +/** + * Puts a 32-bit integer in this buffer in little-endian order. + * + * @param i the 32-bit integer. + * + * @return this buffer. + */ +util$1.ByteStringBuffer.prototype.putInt32Le = function(i) { + return this.putBytes( + String.fromCharCode(i & 0xFF) + + String.fromCharCode(i >> 8 & 0xFF) + + String.fromCharCode(i >> 16 & 0xFF) + + String.fromCharCode(i >> 24 & 0xFF)); +}; + +/** + * Puts an n-bit integer in this buffer in big-endian order. + * + * @param i the n-bit integer. + * @param n the number of bits in the integer (8, 16, 24, or 32). + * + * @return this buffer. + */ +util$1.ByteStringBuffer.prototype.putInt = function(i, n) { + _checkBitsParam(n); + var bytes = ''; + do { + n -= 8; + bytes += String.fromCharCode((i >> n) & 0xFF); + } while(n > 0); + return this.putBytes(bytes); +}; + +/** + * Puts a signed n-bit integer in this buffer in big-endian order. Two's + * complement representation is used. + * + * @param i the n-bit integer. + * @param n the number of bits in the integer (8, 16, 24, or 32). + * + * @return this buffer. + */ +util$1.ByteStringBuffer.prototype.putSignedInt = function(i, n) { + // putInt checks n + if(i < 0) { + i += 2 << (n - 1); + } + return this.putInt(i, n); +}; + +/** + * Puts the given buffer into this buffer. + * + * @param buffer the buffer to put into this one. + * + * @return this buffer. + */ +util$1.ByteStringBuffer.prototype.putBuffer = function(buffer) { + return this.putBytes(buffer.getBytes()); +}; + +/** + * Gets a byte from this buffer and advances the read pointer by 1. + * + * @return the byte. + */ +util$1.ByteStringBuffer.prototype.getByte = function() { + return this.data.charCodeAt(this.read++); +}; + +/** + * Gets a uint16 from this buffer in big-endian order and advances the read + * pointer by 2. + * + * @return the uint16. + */ +util$1.ByteStringBuffer.prototype.getInt16 = function() { + var rval = ( + this.data.charCodeAt(this.read) << 8 ^ + this.data.charCodeAt(this.read + 1)); + this.read += 2; + return rval; +}; + +/** + * Gets a uint24 from this buffer in big-endian order and advances the read + * pointer by 3. + * + * @return the uint24. + */ +util$1.ByteStringBuffer.prototype.getInt24 = function() { + var rval = ( + this.data.charCodeAt(this.read) << 16 ^ + this.data.charCodeAt(this.read + 1) << 8 ^ + this.data.charCodeAt(this.read + 2)); + this.read += 3; + return rval; +}; + +/** + * Gets a uint32 from this buffer in big-endian order and advances the read + * pointer by 4. + * + * @return the word. + */ +util$1.ByteStringBuffer.prototype.getInt32 = function() { + var rval = ( + this.data.charCodeAt(this.read) << 24 ^ + this.data.charCodeAt(this.read + 1) << 16 ^ + this.data.charCodeAt(this.read + 2) << 8 ^ + this.data.charCodeAt(this.read + 3)); + this.read += 4; + return rval; +}; + +/** + * Gets a uint16 from this buffer in little-endian order and advances the read + * pointer by 2. + * + * @return the uint16. + */ +util$1.ByteStringBuffer.prototype.getInt16Le = function() { + var rval = ( + this.data.charCodeAt(this.read) ^ + this.data.charCodeAt(this.read + 1) << 8); + this.read += 2; + return rval; +}; + +/** + * Gets a uint24 from this buffer in little-endian order and advances the read + * pointer by 3. + * + * @return the uint24. + */ +util$1.ByteStringBuffer.prototype.getInt24Le = function() { + var rval = ( + this.data.charCodeAt(this.read) ^ + this.data.charCodeAt(this.read + 1) << 8 ^ + this.data.charCodeAt(this.read + 2) << 16); + this.read += 3; + return rval; +}; + +/** + * Gets a uint32 from this buffer in little-endian order and advances the read + * pointer by 4. + * + * @return the word. + */ +util$1.ByteStringBuffer.prototype.getInt32Le = function() { + var rval = ( + this.data.charCodeAt(this.read) ^ + this.data.charCodeAt(this.read + 1) << 8 ^ + this.data.charCodeAt(this.read + 2) << 16 ^ + this.data.charCodeAt(this.read + 3) << 24); + this.read += 4; + return rval; +}; + +/** + * Gets an n-bit integer from this buffer in big-endian order and advances the + * read pointer by ceil(n/8). + * + * @param n the number of bits in the integer (8, 16, 24, or 32). + * + * @return the integer. + */ +util$1.ByteStringBuffer.prototype.getInt = function(n) { + _checkBitsParam(n); + var rval = 0; + do { + // TODO: Use (rval * 0x100) if adding support for 33 to 53 bits. + rval = (rval << 8) + this.data.charCodeAt(this.read++); + n -= 8; + } while(n > 0); + return rval; +}; + +/** + * Gets a signed n-bit integer from this buffer in big-endian order, using + * two's complement, and advances the read pointer by n/8. + * + * @param n the number of bits in the integer (8, 16, 24, or 32). + * + * @return the integer. + */ +util$1.ByteStringBuffer.prototype.getSignedInt = function(n) { + // getInt checks n + var x = this.getInt(n); + var max = 2 << (n - 2); + if(x >= max) { + x -= max << 1; + } + return x; +}; + +/** + * Reads bytes out as a binary encoded string and clears them from the + * buffer. Note that the resulting string is binary encoded (in node.js this + * encoding is referred to as `binary`, it is *not* `utf8`). + * + * @param count the number of bytes to read, undefined or null for all. + * + * @return a binary encoded string of bytes. + */ +util$1.ByteStringBuffer.prototype.getBytes = function(count) { + var rval; + if(count) { + // read count bytes + count = Math.min(this.length(), count); + rval = this.data.slice(this.read, this.read + count); + this.read += count; + } else if(count === 0) { + rval = ''; + } else { + // read all bytes, optimize to only copy when needed + rval = (this.read === 0) ? this.data : this.data.slice(this.read); + this.clear(); + } + return rval; +}; + +/** + * Gets a binary encoded string of the bytes from this buffer without + * modifying the read pointer. + * + * @param count the number of bytes to get, omit to get all. + * + * @return a string full of binary encoded characters. + */ +util$1.ByteStringBuffer.prototype.bytes = function(count) { + return (typeof(count) === 'undefined' ? + this.data.slice(this.read) : + this.data.slice(this.read, this.read + count)); +}; + +/** + * Gets a byte at the given index without modifying the read pointer. + * + * @param i the byte index. + * + * @return the byte. + */ +util$1.ByteStringBuffer.prototype.at = function(i) { + return this.data.charCodeAt(this.read + i); +}; + +/** + * Puts a byte at the given index without modifying the read pointer. + * + * @param i the byte index. + * @param b the byte to put. + * + * @return this buffer. + */ +util$1.ByteStringBuffer.prototype.setAt = function(i, b) { + this.data = this.data.substr(0, this.read + i) + + String.fromCharCode(b) + + this.data.substr(this.read + i + 1); + return this; +}; + +/** + * Gets the last byte without modifying the read pointer. + * + * @return the last byte. + */ +util$1.ByteStringBuffer.prototype.last = function() { + return this.data.charCodeAt(this.data.length - 1); +}; + +/** + * Creates a copy of this buffer. + * + * @return the copy. + */ +util$1.ByteStringBuffer.prototype.copy = function() { + var c = util$1.createBuffer(this.data); + c.read = this.read; + return c; +}; + +/** + * Compacts this buffer. + * + * @return this buffer. + */ +util$1.ByteStringBuffer.prototype.compact = function() { + if(this.read > 0) { + this.data = this.data.slice(this.read); + this.read = 0; + } + return this; +}; + +/** + * Clears this buffer. + * + * @return this buffer. + */ +util$1.ByteStringBuffer.prototype.clear = function() { + this.data = ''; + this.read = 0; + return this; +}; + +/** + * Shortens this buffer by triming bytes off of the end of this buffer. + * + * @param count the number of bytes to trim off. + * + * @return this buffer. + */ +util$1.ByteStringBuffer.prototype.truncate = function(count) { + var len = Math.max(0, this.length() - count); + this.data = this.data.substr(this.read, len); + this.read = 0; + return this; +}; + +/** + * Converts this buffer to a hexadecimal string. + * + * @return a hexadecimal string. + */ +util$1.ByteStringBuffer.prototype.toHex = function() { + var rval = ''; + for(var i = this.read; i < this.data.length; ++i) { + var b = this.data.charCodeAt(i); + if(b < 16) { + rval += '0'; + } + rval += b.toString(16); + } + return rval; +}; + +/** + * Converts this buffer to a UTF-16 string (standard JavaScript string). + * + * @return a UTF-16 string. + */ +util$1.ByteStringBuffer.prototype.toString = function() { + return util$1.decodeUtf8(this.bytes()); +}; + +/** End Buffer w/BinaryString backing */ + +/** Buffer w/UInt8Array backing */ + +/** + * FIXME: Experimental. Do not use yet. + * + * Constructor for an ArrayBuffer-backed byte buffer. + * + * The buffer may be constructed from a string, an ArrayBuffer, DataView, or a + * TypedArray. + * + * If a string is given, its encoding should be provided as an option, + * otherwise it will default to 'binary'. A 'binary' string is encoded such + * that each character is one byte in length and size. + * + * If an ArrayBuffer, DataView, or TypedArray is given, it will be used + * *directly* without any copying. Note that, if a write to the buffer requires + * more space, the buffer will allocate a new backing ArrayBuffer to + * accommodate. The starting read and write offsets for the buffer may be + * given as options. + * + * @param [b] the initial bytes for this buffer. + * @param options the options to use: + * [readOffset] the starting read offset to use (default: 0). + * [writeOffset] the starting write offset to use (default: the + * length of the first parameter). + * [growSize] the minimum amount, in bytes, to grow the buffer by to + * accommodate writes (default: 1024). + * [encoding] the encoding ('binary', 'utf8', 'utf16', 'hex') for the + * first parameter, if it is a string (default: 'binary'). + */ +function DataBuffer(b, options) { + // default options + options = options || {}; + + // pointers for read from/write to buffer + this.read = options.readOffset || 0; + this.growSize = options.growSize || 1024; + + var isArrayBuffer = util$1.isArrayBuffer(b); + var isArrayBufferView = util$1.isArrayBufferView(b); + if(isArrayBuffer || isArrayBufferView) { + // use ArrayBuffer directly + if(isArrayBuffer) { + this.data = new DataView(b); + } else { + // TODO: adjust read/write offset based on the type of view + // or specify that this must be done in the options ... that the + // offsets are byte-based + this.data = new DataView(b.buffer, b.byteOffset, b.byteLength); + } + this.write = ('writeOffset' in options ? + options.writeOffset : this.data.byteLength); + return; + } + + // initialize to empty array buffer and add any given bytes using putBytes + this.data = new DataView(new ArrayBuffer(0)); + this.write = 0; + + if(b !== null && b !== undefined) { + this.putBytes(b); + } + + if('writeOffset' in options) { + this.write = options.writeOffset; + } +} +util$1.DataBuffer = DataBuffer; + +/** + * Gets the number of bytes in this buffer. + * + * @return the number of bytes in this buffer. + */ +util$1.DataBuffer.prototype.length = function() { + return this.write - this.read; +}; + +/** + * Gets whether or not this buffer is empty. + * + * @return true if this buffer is empty, false if not. + */ +util$1.DataBuffer.prototype.isEmpty = function() { + return this.length() <= 0; +}; + +/** + * Ensures this buffer has enough empty space to accommodate the given number + * of bytes. An optional parameter may be given that indicates a minimum + * amount to grow the buffer if necessary. If the parameter is not given, + * the buffer will be grown by some previously-specified default amount + * or heuristic. + * + * @param amount the number of bytes to accommodate. + * @param [growSize] the minimum amount, in bytes, to grow the buffer by if + * necessary. + */ +util$1.DataBuffer.prototype.accommodate = function(amount, growSize) { + if(this.length() >= amount) { + return this; + } + growSize = Math.max(growSize || this.growSize, amount); + + // grow buffer + var src = new Uint8Array( + this.data.buffer, this.data.byteOffset, this.data.byteLength); + var dst = new Uint8Array(this.length() + growSize); + dst.set(src); + this.data = new DataView(dst.buffer); + + return this; +}; + +/** + * Puts a byte in this buffer. + * + * @param b the byte to put. + * + * @return this buffer. + */ +util$1.DataBuffer.prototype.putByte = function(b) { + this.accommodate(1); + this.data.setUint8(this.write++, b); + return this; +}; + +/** + * Puts a byte in this buffer N times. + * + * @param b the byte to put. + * @param n the number of bytes of value b to put. + * + * @return this buffer. + */ +util$1.DataBuffer.prototype.fillWithByte = function(b, n) { + this.accommodate(n); + for(var i = 0; i < n; ++i) { + this.data.setUint8(b); + } + return this; +}; + +/** + * Puts bytes in this buffer. The bytes may be given as a string, an + * ArrayBuffer, a DataView, or a TypedArray. + * + * @param bytes the bytes to put. + * @param [encoding] the encoding for the first parameter ('binary', 'utf8', + * 'utf16', 'hex'), if it is a string (default: 'binary'). + * + * @return this buffer. + */ +util$1.DataBuffer.prototype.putBytes = function(bytes, encoding) { + if(util$1.isArrayBufferView(bytes)) { + var src = new Uint8Array(bytes.buffer, bytes.byteOffset, bytes.byteLength); + var len = src.byteLength - src.byteOffset; + this.accommodate(len); + var dst = new Uint8Array(this.data.buffer, this.write); + dst.set(src); + this.write += len; + return this; + } + + if(util$1.isArrayBuffer(bytes)) { + var src = new Uint8Array(bytes); + this.accommodate(src.byteLength); + var dst = new Uint8Array(this.data.buffer); + dst.set(src, this.write); + this.write += src.byteLength; + return this; + } + + // bytes is a util.DataBuffer or equivalent + if(bytes instanceof util$1.DataBuffer || + (typeof bytes === 'object' && + typeof bytes.read === 'number' && typeof bytes.write === 'number' && + util$1.isArrayBufferView(bytes.data))) { + var src = new Uint8Array(bytes.data.byteLength, bytes.read, bytes.length()); + this.accommodate(src.byteLength); + var dst = new Uint8Array(bytes.data.byteLength, this.write); + dst.set(src); + this.write += src.byteLength; + return this; + } + + if(bytes instanceof util$1.ByteStringBuffer) { + // copy binary string and process as the same as a string parameter below + bytes = bytes.data; + encoding = 'binary'; + } + + // string conversion + encoding = encoding || 'binary'; + if(typeof bytes === 'string') { + var view; + + // decode from string + if(encoding === 'hex') { + this.accommodate(Math.ceil(bytes.length / 2)); + view = new Uint8Array(this.data.buffer, this.write); + this.write += util$1.binary.hex.decode(bytes, view, this.write); + return this; + } + if(encoding === 'base64') { + this.accommodate(Math.ceil(bytes.length / 4) * 3); + view = new Uint8Array(this.data.buffer, this.write); + this.write += util$1.binary.base64.decode(bytes, view, this.write); + return this; + } + + // encode text as UTF-8 bytes + if(encoding === 'utf8') { + // encode as UTF-8 then decode string as raw binary + bytes = util$1.encodeUtf8(bytes); + encoding = 'binary'; + } + + // decode string as raw binary + if(encoding === 'binary' || encoding === 'raw') { + // one byte per character + this.accommodate(bytes.length); + view = new Uint8Array(this.data.buffer, this.write); + this.write += util$1.binary.raw.decode(view); + return this; + } + + // encode text as UTF-16 bytes + if(encoding === 'utf16') { + // two bytes per character + this.accommodate(bytes.length * 2); + view = new Uint16Array(this.data.buffer, this.write); + this.write += util$1.text.utf16.encode(view); + return this; + } + + throw new Error('Invalid encoding: ' + encoding); + } + + throw Error('Invalid parameter: ' + bytes); +}; + +/** + * Puts the given buffer into this buffer. + * + * @param buffer the buffer to put into this one. + * + * @return this buffer. + */ +util$1.DataBuffer.prototype.putBuffer = function(buffer) { + this.putBytes(buffer); + buffer.clear(); + return this; +}; + +/** + * Puts a string into this buffer. + * + * @param str the string to put. + * @param [encoding] the encoding for the string (default: 'utf16'). + * + * @return this buffer. + */ +util$1.DataBuffer.prototype.putString = function(str) { + return this.putBytes(str, 'utf16'); +}; + +/** + * Puts a 16-bit integer in this buffer in big-endian order. + * + * @param i the 16-bit integer. + * + * @return this buffer. + */ +util$1.DataBuffer.prototype.putInt16 = function(i) { + this.accommodate(2); + this.data.setInt16(this.write, i); + this.write += 2; + return this; +}; + +/** + * Puts a 24-bit integer in this buffer in big-endian order. + * + * @param i the 24-bit integer. + * + * @return this buffer. + */ +util$1.DataBuffer.prototype.putInt24 = function(i) { + this.accommodate(3); + this.data.setInt16(this.write, i >> 8 & 0xFFFF); + this.data.setInt8(this.write, i >> 16 & 0xFF); + this.write += 3; + return this; +}; + +/** + * Puts a 32-bit integer in this buffer in big-endian order. + * + * @param i the 32-bit integer. + * + * @return this buffer. + */ +util$1.DataBuffer.prototype.putInt32 = function(i) { + this.accommodate(4); + this.data.setInt32(this.write, i); + this.write += 4; + return this; +}; + +/** + * Puts a 16-bit integer in this buffer in little-endian order. + * + * @param i the 16-bit integer. + * + * @return this buffer. + */ +util$1.DataBuffer.prototype.putInt16Le = function(i) { + this.accommodate(2); + this.data.setInt16(this.write, i, true); + this.write += 2; + return this; +}; + +/** + * Puts a 24-bit integer in this buffer in little-endian order. + * + * @param i the 24-bit integer. + * + * @return this buffer. + */ +util$1.DataBuffer.prototype.putInt24Le = function(i) { + this.accommodate(3); + this.data.setInt8(this.write, i >> 16 & 0xFF); + this.data.setInt16(this.write, i >> 8 & 0xFFFF, true); + this.write += 3; + return this; +}; + +/** + * Puts a 32-bit integer in this buffer in little-endian order. + * + * @param i the 32-bit integer. + * + * @return this buffer. + */ +util$1.DataBuffer.prototype.putInt32Le = function(i) { + this.accommodate(4); + this.data.setInt32(this.write, i, true); + this.write += 4; + return this; +}; + +/** + * Puts an n-bit integer in this buffer in big-endian order. + * + * @param i the n-bit integer. + * @param n the number of bits in the integer (8, 16, 24, or 32). + * + * @return this buffer. + */ +util$1.DataBuffer.prototype.putInt = function(i, n) { + _checkBitsParam(n); + this.accommodate(n / 8); + do { + n -= 8; + this.data.setInt8(this.write++, (i >> n) & 0xFF); + } while(n > 0); + return this; +}; + +/** + * Puts a signed n-bit integer in this buffer in big-endian order. Two's + * complement representation is used. + * + * @param i the n-bit integer. + * @param n the number of bits in the integer. + * + * @return this buffer. + */ +util$1.DataBuffer.prototype.putSignedInt = function(i, n) { + _checkBitsParam(n); + this.accommodate(n / 8); + if(i < 0) { + i += 2 << (n - 1); + } + return this.putInt(i, n); +}; + +/** + * Gets a byte from this buffer and advances the read pointer by 1. + * + * @return the byte. + */ +util$1.DataBuffer.prototype.getByte = function() { + return this.data.getInt8(this.read++); +}; + +/** + * Gets a uint16 from this buffer in big-endian order and advances the read + * pointer by 2. + * + * @return the uint16. + */ +util$1.DataBuffer.prototype.getInt16 = function() { + var rval = this.data.getInt16(this.read); + this.read += 2; + return rval; +}; + +/** + * Gets a uint24 from this buffer in big-endian order and advances the read + * pointer by 3. + * + * @return the uint24. + */ +util$1.DataBuffer.prototype.getInt24 = function() { + var rval = ( + this.data.getInt16(this.read) << 8 ^ + this.data.getInt8(this.read + 2)); + this.read += 3; + return rval; +}; + +/** + * Gets a uint32 from this buffer in big-endian order and advances the read + * pointer by 4. + * + * @return the word. + */ +util$1.DataBuffer.prototype.getInt32 = function() { + var rval = this.data.getInt32(this.read); + this.read += 4; + return rval; +}; + +/** + * Gets a uint16 from this buffer in little-endian order and advances the read + * pointer by 2. + * + * @return the uint16. + */ +util$1.DataBuffer.prototype.getInt16Le = function() { + var rval = this.data.getInt16(this.read, true); + this.read += 2; + return rval; +}; + +/** + * Gets a uint24 from this buffer in little-endian order and advances the read + * pointer by 3. + * + * @return the uint24. + */ +util$1.DataBuffer.prototype.getInt24Le = function() { + var rval = ( + this.data.getInt8(this.read) ^ + this.data.getInt16(this.read + 1, true) << 8); + this.read += 3; + return rval; +}; + +/** + * Gets a uint32 from this buffer in little-endian order and advances the read + * pointer by 4. + * + * @return the word. + */ +util$1.DataBuffer.prototype.getInt32Le = function() { + var rval = this.data.getInt32(this.read, true); + this.read += 4; + return rval; +}; + +/** + * Gets an n-bit integer from this buffer in big-endian order and advances the + * read pointer by n/8. + * + * @param n the number of bits in the integer (8, 16, 24, or 32). + * + * @return the integer. + */ +util$1.DataBuffer.prototype.getInt = function(n) { + _checkBitsParam(n); + var rval = 0; + do { + // TODO: Use (rval * 0x100) if adding support for 33 to 53 bits. + rval = (rval << 8) + this.data.getInt8(this.read++); + n -= 8; + } while(n > 0); + return rval; +}; + +/** + * Gets a signed n-bit integer from this buffer in big-endian order, using + * two's complement, and advances the read pointer by n/8. + * + * @param n the number of bits in the integer (8, 16, 24, or 32). + * + * @return the integer. + */ +util$1.DataBuffer.prototype.getSignedInt = function(n) { + // getInt checks n + var x = this.getInt(n); + var max = 2 << (n - 2); + if(x >= max) { + x -= max << 1; + } + return x; +}; + +/** + * Reads bytes out as a binary encoded string and clears them from the + * buffer. + * + * @param count the number of bytes to read, undefined or null for all. + * + * @return a binary encoded string of bytes. + */ +util$1.DataBuffer.prototype.getBytes = function(count) { + // TODO: deprecate this method, it is poorly named and + // this.toString('binary') replaces it + // add a toTypedArray()/toArrayBuffer() function + var rval; + if(count) { + // read count bytes + count = Math.min(this.length(), count); + rval = this.data.slice(this.read, this.read + count); + this.read += count; + } else if(count === 0) { + rval = ''; + } else { + // read all bytes, optimize to only copy when needed + rval = (this.read === 0) ? this.data : this.data.slice(this.read); + this.clear(); + } + return rval; +}; + +/** + * Gets a binary encoded string of the bytes from this buffer without + * modifying the read pointer. + * + * @param count the number of bytes to get, omit to get all. + * + * @return a string full of binary encoded characters. + */ +util$1.DataBuffer.prototype.bytes = function(count) { + // TODO: deprecate this method, it is poorly named, add "getString()" + return (typeof(count) === 'undefined' ? + this.data.slice(this.read) : + this.data.slice(this.read, this.read + count)); +}; + +/** + * Gets a byte at the given index without modifying the read pointer. + * + * @param i the byte index. + * + * @return the byte. + */ +util$1.DataBuffer.prototype.at = function(i) { + return this.data.getUint8(this.read + i); +}; + +/** + * Puts a byte at the given index without modifying the read pointer. + * + * @param i the byte index. + * @param b the byte to put. + * + * @return this buffer. + */ +util$1.DataBuffer.prototype.setAt = function(i, b) { + this.data.setUint8(i, b); + return this; +}; + +/** + * Gets the last byte without modifying the read pointer. + * + * @return the last byte. + */ +util$1.DataBuffer.prototype.last = function() { + return this.data.getUint8(this.write - 1); +}; + +/** + * Creates a copy of this buffer. + * + * @return the copy. + */ +util$1.DataBuffer.prototype.copy = function() { + return new util$1.DataBuffer(this); +}; + +/** + * Compacts this buffer. + * + * @return this buffer. + */ +util$1.DataBuffer.prototype.compact = function() { + if(this.read > 0) { + var src = new Uint8Array(this.data.buffer, this.read); + var dst = new Uint8Array(src.byteLength); + dst.set(src); + this.data = new DataView(dst); + this.write -= this.read; + this.read = 0; + } + return this; +}; + +/** + * Clears this buffer. + * + * @return this buffer. + */ +util$1.DataBuffer.prototype.clear = function() { + this.data = new DataView(new ArrayBuffer(0)); + this.read = this.write = 0; + return this; +}; + +/** + * Shortens this buffer by triming bytes off of the end of this buffer. + * + * @param count the number of bytes to trim off. + * + * @return this buffer. + */ +util$1.DataBuffer.prototype.truncate = function(count) { + this.write = Math.max(0, this.length() - count); + this.read = Math.min(this.read, this.write); + return this; +}; + +/** + * Converts this buffer to a hexadecimal string. + * + * @return a hexadecimal string. + */ +util$1.DataBuffer.prototype.toHex = function() { + var rval = ''; + for(var i = this.read; i < this.data.byteLength; ++i) { + var b = this.data.getUint8(i); + if(b < 16) { + rval += '0'; + } + rval += b.toString(16); + } + return rval; +}; + +/** + * Converts this buffer to a string, using the given encoding. If no + * encoding is given, 'utf8' (UTF-8) is used. + * + * @param [encoding] the encoding to use: 'binary', 'utf8', 'utf16', 'hex', + * 'base64' (default: 'utf8'). + * + * @return a string representation of the bytes in this buffer. + */ +util$1.DataBuffer.prototype.toString = function(encoding) { + var view = new Uint8Array(this.data, this.read, this.length()); + encoding = encoding || 'utf8'; + + // encode to string + if(encoding === 'binary' || encoding === 'raw') { + return util$1.binary.raw.encode(view); + } + if(encoding === 'hex') { + return util$1.binary.hex.encode(view); + } + if(encoding === 'base64') { + return util$1.binary.base64.encode(view); + } + + // decode to text + if(encoding === 'utf8') { + return util$1.text.utf8.decode(view); + } + if(encoding === 'utf16') { + return util$1.text.utf16.decode(view); + } + + throw new Error('Invalid encoding: ' + encoding); +}; + +/** End Buffer w/UInt8Array backing */ + +/** + * Creates a buffer that stores bytes. A value may be given to populate the + * buffer with data. This value can either be string of encoded bytes or a + * regular string of characters. When passing a string of binary encoded + * bytes, the encoding `raw` should be given. This is also the default. When + * passing a string of characters, the encoding `utf8` should be given. + * + * @param [input] a string with encoded bytes to store in the buffer. + * @param [encoding] (default: 'raw', other: 'utf8'). + */ +util$1.createBuffer = function(input, encoding) { + // TODO: deprecate, use new ByteBuffer() instead + encoding = encoding || 'raw'; + if(input !== undefined && encoding === 'utf8') { + input = util$1.encodeUtf8(input); + } + return new util$1.ByteBuffer(input); +}; + +/** + * Fills a string with a particular value. If you want the string to be a byte + * string, pass in String.fromCharCode(theByte). + * + * @param c the character to fill the string with, use String.fromCharCode + * to fill the string with a byte value. + * @param n the number of characters of value c to fill with. + * + * @return the filled string. + */ +util$1.fillString = function(c, n) { + var s = ''; + while(n > 0) { + if(n & 1) { + s += c; + } + n >>>= 1; + if(n > 0) { + c += c; + } + } + return s; +}; + +/** + * Performs a per byte XOR between two byte strings and returns the result as a + * string of bytes. + * + * @param s1 first string of bytes. + * @param s2 second string of bytes. + * @param n the number of bytes to XOR. + * + * @return the XOR'd result. + */ +util$1.xorBytes = function(s1, s2, n) { + var s3 = ''; + var b = ''; + var t = ''; + var i = 0; + var c = 0; + for(; n > 0; --n, ++i) { + b = s1.charCodeAt(i) ^ s2.charCodeAt(i); + if(c >= 10) { + s3 += t; + t = ''; + c = 0; + } + t += String.fromCharCode(b); + ++c; + } + s3 += t; + return s3; +}; + +/** + * Converts a hex string into a 'binary' encoded string of bytes. + * + * @param hex the hexadecimal string to convert. + * + * @return the binary-encoded string of bytes. + */ +util$1.hexToBytes = function(hex) { + // TODO: deprecate: "Deprecated. Use util.binary.hex.decode instead." + var rval = ''; + var i = 0; + if(hex.length & 1 == 1) { + // odd number of characters, convert first character alone + i = 1; + rval += String.fromCharCode(parseInt(hex[0], 16)); + } + // convert 2 characters (1 byte) at a time + for(; i < hex.length; i += 2) { + rval += String.fromCharCode(parseInt(hex.substr(i, 2), 16)); + } + return rval; +}; + +/** + * Converts a 'binary' encoded string of bytes to hex. + * + * @param bytes the byte string to convert. + * + * @return the string of hexadecimal characters. + */ +util$1.bytesToHex = function(bytes) { + // TODO: deprecate: "Deprecated. Use util.binary.hex.encode instead." + return util$1.createBuffer(bytes).toHex(); +}; + +/** + * Converts an 32-bit integer to 4-big-endian byte string. + * + * @param i the integer. + * + * @return the byte string. + */ +util$1.int32ToBytes = function(i) { + return ( + String.fromCharCode(i >> 24 & 0xFF) + + String.fromCharCode(i >> 16 & 0xFF) + + String.fromCharCode(i >> 8 & 0xFF) + + String.fromCharCode(i & 0xFF)); +}; + +// base64 characters, reverse mapping +var _base64 = + 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/='; +var _base64Idx = [ +/*43 -43 = 0*/ +/*'+', 1, 2, 3,'/' */ + 62, -1, -1, -1, 63, + +/*'0','1','2','3','4','5','6','7','8','9' */ + 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, + +/*15, 16, 17,'=', 19, 20, 21 */ + -1, -1, -1, 64, -1, -1, -1, + +/*65 - 43 = 22*/ +/*'A','B','C','D','E','F','G','H','I','J','K','L','M', */ + 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, + +/*'N','O','P','Q','R','S','T','U','V','W','X','Y','Z' */ + 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, + +/*91 - 43 = 48 */ +/*48, 49, 50, 51, 52, 53 */ + -1, -1, -1, -1, -1, -1, + +/*97 - 43 = 54*/ +/*'a','b','c','d','e','f','g','h','i','j','k','l','m' */ + 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, + +/*'n','o','p','q','r','s','t','u','v','w','x','y','z' */ + 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51 +]; + +// base58 characters (Bitcoin alphabet) +var _base58 = '123456789ABCDEFGHJKLMNPQRSTUVWXYZabcdefghijkmnopqrstuvwxyz'; + +/** + * Base64 encodes a 'binary' encoded string of bytes. + * + * @param input the binary encoded string of bytes to base64-encode. + * @param maxline the maximum number of encoded characters per line to use, + * defaults to none. + * + * @return the base64-encoded output. + */ +util$1.encode64 = function(input, maxline) { + // TODO: deprecate: "Deprecated. Use util.binary.base64.encode instead." + var line = ''; + var output = ''; + var chr1, chr2, chr3; + var i = 0; + while(i < input.length) { + chr1 = input.charCodeAt(i++); + chr2 = input.charCodeAt(i++); + chr3 = input.charCodeAt(i++); + + // encode 4 character group + line += _base64.charAt(chr1 >> 2); + line += _base64.charAt(((chr1 & 3) << 4) | (chr2 >> 4)); + if(isNaN(chr2)) { + line += '=='; + } else { + line += _base64.charAt(((chr2 & 15) << 2) | (chr3 >> 6)); + line += isNaN(chr3) ? '=' : _base64.charAt(chr3 & 63); + } + + if(maxline && line.length > maxline) { + output += line.substr(0, maxline) + '\r\n'; + line = line.substr(maxline); + } + } + output += line; + return output; +}; + +/** + * Base64 decodes a string into a 'binary' encoded string of bytes. + * + * @param input the base64-encoded input. + * + * @return the binary encoded string. + */ +util$1.decode64 = function(input) { + // TODO: deprecate: "Deprecated. Use util.binary.base64.decode instead." + + // remove all non-base64 characters + input = input.replace(/[^A-Za-z0-9\+\/\=]/g, ''); + + var output = ''; + var enc1, enc2, enc3, enc4; + var i = 0; + + while(i < input.length) { + enc1 = _base64Idx[input.charCodeAt(i++) - 43]; + enc2 = _base64Idx[input.charCodeAt(i++) - 43]; + enc3 = _base64Idx[input.charCodeAt(i++) - 43]; + enc4 = _base64Idx[input.charCodeAt(i++) - 43]; + + output += String.fromCharCode((enc1 << 2) | (enc2 >> 4)); + if(enc3 !== 64) { + // decoded at least 2 bytes + output += String.fromCharCode(((enc2 & 15) << 4) | (enc3 >> 2)); + if(enc4 !== 64) { + // decoded 3 bytes + output += String.fromCharCode(((enc3 & 3) << 6) | enc4); + } + } + } + + return output; +}; + +/** + * Encodes the given string of characters (a standard JavaScript + * string) as a binary encoded string where the bytes represent + * a UTF-8 encoded string of characters. Non-ASCII characters will be + * encoded as multiple bytes according to UTF-8. + * + * @param str a standard string of characters to encode. + * + * @return the binary encoded string. + */ +util$1.encodeUtf8 = function(str) { + return unescape(encodeURIComponent(str)); +}; + +/** + * Decodes a binary encoded string that contains bytes that + * represent a UTF-8 encoded string of characters -- into a + * string of characters (a standard JavaScript string). + * + * @param str the binary encoded string to decode. + * + * @return the resulting standard string of characters. + */ +util$1.decodeUtf8 = function(str) { + return decodeURIComponent(escape(str)); +}; + +// binary encoding/decoding tools +// FIXME: Experimental. Do not use yet. +util$1.binary = { + raw: {}, + hex: {}, + base64: {}, + base58: {}, + baseN : { + encode: baseN.encode, + decode: baseN.decode + } +}; + +/** + * Encodes a Uint8Array as a binary-encoded string. This encoding uses + * a value between 0 and 255 for each character. + * + * @param bytes the Uint8Array to encode. + * + * @return the binary-encoded string. + */ +util$1.binary.raw.encode = function(bytes) { + return String.fromCharCode.apply(null, bytes); +}; + +/** + * Decodes a binary-encoded string to a Uint8Array. This encoding uses + * a value between 0 and 255 for each character. + * + * @param str the binary-encoded string to decode. + * @param [output] an optional Uint8Array to write the output to; if it + * is too small, an exception will be thrown. + * @param [offset] the start offset for writing to the output (default: 0). + * + * @return the Uint8Array or the number of bytes written if output was given. + */ +util$1.binary.raw.decode = function(str, output, offset) { + var out = output; + if(!out) { + out = new Uint8Array(str.length); + } + offset = offset || 0; + var j = offset; + for(var i = 0; i < str.length; ++i) { + out[j++] = str.charCodeAt(i); + } + return output ? (j - offset) : out; +}; + +/** + * Encodes a 'binary' string, ArrayBuffer, DataView, TypedArray, or + * ByteBuffer as a string of hexadecimal characters. + * + * @param bytes the bytes to convert. + * + * @return the string of hexadecimal characters. + */ +util$1.binary.hex.encode = util$1.bytesToHex; + +/** + * Decodes a hex-encoded string to a Uint8Array. + * + * @param hex the hexadecimal string to convert. + * @param [output] an optional Uint8Array to write the output to; if it + * is too small, an exception will be thrown. + * @param [offset] the start offset for writing to the output (default: 0). + * + * @return the Uint8Array or the number of bytes written if output was given. + */ +util$1.binary.hex.decode = function(hex, output, offset) { + var out = output; + if(!out) { + out = new Uint8Array(Math.ceil(hex.length / 2)); + } + offset = offset || 0; + var i = 0, j = offset; + if(hex.length & 1) { + // odd number of characters, convert first character alone + i = 1; + out[j++] = parseInt(hex[0], 16); + } + // convert 2 characters (1 byte) at a time + for(; i < hex.length; i += 2) { + out[j++] = parseInt(hex.substr(i, 2), 16); + } + return output ? (j - offset) : out; +}; + +/** + * Base64-encodes a Uint8Array. + * + * @param input the Uint8Array to encode. + * @param maxline the maximum number of encoded characters per line to use, + * defaults to none. + * + * @return the base64-encoded output string. + */ +util$1.binary.base64.encode = function(input, maxline) { + var line = ''; + var output = ''; + var chr1, chr2, chr3; + var i = 0; + while(i < input.byteLength) { + chr1 = input[i++]; + chr2 = input[i++]; + chr3 = input[i++]; + + // encode 4 character group + line += _base64.charAt(chr1 >> 2); + line += _base64.charAt(((chr1 & 3) << 4) | (chr2 >> 4)); + if(isNaN(chr2)) { + line += '=='; + } else { + line += _base64.charAt(((chr2 & 15) << 2) | (chr3 >> 6)); + line += isNaN(chr3) ? '=' : _base64.charAt(chr3 & 63); + } + + if(maxline && line.length > maxline) { + output += line.substr(0, maxline) + '\r\n'; + line = line.substr(maxline); + } + } + output += line; + return output; +}; + +/** + * Decodes a base64-encoded string to a Uint8Array. + * + * @param input the base64-encoded input string. + * @param [output] an optional Uint8Array to write the output to; if it + * is too small, an exception will be thrown. + * @param [offset] the start offset for writing to the output (default: 0). + * + * @return the Uint8Array or the number of bytes written if output was given. + */ +util$1.binary.base64.decode = function(input, output, offset) { + var out = output; + if(!out) { + out = new Uint8Array(Math.ceil(input.length / 4) * 3); + } + + // remove all non-base64 characters + input = input.replace(/[^A-Za-z0-9\+\/\=]/g, ''); + + offset = offset || 0; + var enc1, enc2, enc3, enc4; + var i = 0, j = offset; + + while(i < input.length) { + enc1 = _base64Idx[input.charCodeAt(i++) - 43]; + enc2 = _base64Idx[input.charCodeAt(i++) - 43]; + enc3 = _base64Idx[input.charCodeAt(i++) - 43]; + enc4 = _base64Idx[input.charCodeAt(i++) - 43]; + + out[j++] = (enc1 << 2) | (enc2 >> 4); + if(enc3 !== 64) { + // decoded at least 2 bytes + out[j++] = ((enc2 & 15) << 4) | (enc3 >> 2); + if(enc4 !== 64) { + // decoded 3 bytes + out[j++] = ((enc3 & 3) << 6) | enc4; + } + } + } + + // make sure result is the exact decoded length + return output ? (j - offset) : out.subarray(0, j); +}; + +// add support for base58 encoding/decoding with Bitcoin alphabet +util$1.binary.base58.encode = function(input, maxline) { + return util$1.binary.baseN.encode(input, _base58, maxline); +}; +util$1.binary.base58.decode = function(input, maxline) { + return util$1.binary.baseN.decode(input, _base58, maxline); +}; + +// text encoding/decoding tools +// FIXME: Experimental. Do not use yet. +util$1.text = { + utf8: {}, + utf16: {} +}; + +/** + * Encodes the given string as UTF-8 in a Uint8Array. + * + * @param str the string to encode. + * @param [output] an optional Uint8Array to write the output to; if it + * is too small, an exception will be thrown. + * @param [offset] the start offset for writing to the output (default: 0). + * + * @return the Uint8Array or the number of bytes written if output was given. + */ +util$1.text.utf8.encode = function(str, output, offset) { + str = util$1.encodeUtf8(str); + var out = output; + if(!out) { + out = new Uint8Array(str.length); + } + offset = offset || 0; + var j = offset; + for(var i = 0; i < str.length; ++i) { + out[j++] = str.charCodeAt(i); + } + return output ? (j - offset) : out; +}; + +/** + * Decodes the UTF-8 contents from a Uint8Array. + * + * @param bytes the Uint8Array to decode. + * + * @return the resulting string. + */ +util$1.text.utf8.decode = function(bytes) { + return util$1.decodeUtf8(String.fromCharCode.apply(null, bytes)); +}; + +/** + * Encodes the given string as UTF-16 in a Uint8Array. + * + * @param str the string to encode. + * @param [output] an optional Uint8Array to write the output to; if it + * is too small, an exception will be thrown. + * @param [offset] the start offset for writing to the output (default: 0). + * + * @return the Uint8Array or the number of bytes written if output was given. + */ +util$1.text.utf16.encode = function(str, output, offset) { + var out = output; + if(!out) { + out = new Uint8Array(str.length * 2); + } + var view = new Uint16Array(out.buffer); + offset = offset || 0; + var j = offset; + var k = offset; + for(var i = 0; i < str.length; ++i) { + view[k++] = str.charCodeAt(i); + j += 2; + } + return output ? (j - offset) : out; +}; + +/** + * Decodes the UTF-16 contents from a Uint8Array. + * + * @param bytes the Uint8Array to decode. + * + * @return the resulting string. + */ +util$1.text.utf16.decode = function(bytes) { + return String.fromCharCode.apply(null, new Uint16Array(bytes.buffer)); +}; + +/** + * Deflates the given data using a flash interface. + * + * @param api the flash interface. + * @param bytes the data. + * @param raw true to return only raw deflate data, false to include zlib + * header and trailer. + * + * @return the deflated data as a string. + */ +util$1.deflate = function(api, bytes, raw) { + bytes = util$1.decode64(api.deflate(util$1.encode64(bytes)).rval); + + // strip zlib header and trailer if necessary + if(raw) { + // zlib header is 2 bytes (CMF,FLG) where FLG indicates that + // there is a 4-byte DICT (alder-32) block before the data if + // its 5th bit is set + var start = 2; + var flg = bytes.charCodeAt(1); + if(flg & 0x20) { + start = 6; + } + // zlib trailer is 4 bytes of adler-32 + bytes = bytes.substring(start, bytes.length - 4); + } + + return bytes; +}; + +/** + * Inflates the given data using a flash interface. + * + * @param api the flash interface. + * @param bytes the data. + * @param raw true if the incoming data has no zlib header or trailer and is + * raw DEFLATE data. + * + * @return the inflated data as a string, null on error. + */ +util$1.inflate = function(api, bytes, raw) { + // TODO: add zlib header and trailer if necessary/possible + var rval = api.inflate(util$1.encode64(bytes)).rval; + return (rval === null) ? null : util$1.decode64(rval); +}; + +/** + * Sets a storage object. + * + * @param api the storage interface. + * @param id the storage ID to use. + * @param obj the storage object, null to remove. + */ +var _setStorageObject = function(api, id, obj) { + if(!api) { + throw new Error('WebStorage not available.'); + } + + var rval; + if(obj === null) { + rval = api.removeItem(id); + } else { + // json-encode and base64-encode object + obj = util$1.encode64(JSON.stringify(obj)); + rval = api.setItem(id, obj); + } + + // handle potential flash error + if(typeof(rval) !== 'undefined' && rval.rval !== true) { + var error = new Error(rval.error.message); + error.id = rval.error.id; + error.name = rval.error.name; + throw error; + } +}; + +/** + * Gets a storage object. + * + * @param api the storage interface. + * @param id the storage ID to use. + * + * @return the storage object entry or null if none exists. + */ +var _getStorageObject = function(api, id) { + if(!api) { + throw new Error('WebStorage not available.'); + } + + // get the existing entry + var rval = api.getItem(id); + + /* Note: We check api.init because we can't do (api == localStorage) + on IE because of "Class doesn't support Automation" exception. Only + the flash api has an init method so this works too, but we need a + better solution in the future. */ + + // flash returns item wrapped in an object, handle special case + if(api.init) { + if(rval.rval === null) { + if(rval.error) { + var error = new Error(rval.error.message); + error.id = rval.error.id; + error.name = rval.error.name; + throw error; + } + // no error, but also no item + rval = null; + } else { + rval = rval.rval; + } + } + + // handle decoding + if(rval !== null) { + // base64-decode and json-decode data + rval = JSON.parse(util$1.decode64(rval)); + } + + return rval; +}; + +/** + * Stores an item in local storage. + * + * @param api the storage interface. + * @param id the storage ID to use. + * @param key the key for the item. + * @param data the data for the item (any javascript object/primitive). + */ +var _setItem = function(api, id, key, data) { + // get storage object + var obj = _getStorageObject(api, id); + if(obj === null) { + // create a new storage object + obj = {}; + } + // update key + obj[key] = data; + + // set storage object + _setStorageObject(api, id, obj); +}; + +/** + * Gets an item from local storage. + * + * @param api the storage interface. + * @param id the storage ID to use. + * @param key the key for the item. + * + * @return the item. + */ +var _getItem = function(api, id, key) { + // get storage object + var rval = _getStorageObject(api, id); + if(rval !== null) { + // return data at key + rval = (key in rval) ? rval[key] : null; + } + + return rval; +}; + +/** + * Removes an item from local storage. + * + * @param api the storage interface. + * @param id the storage ID to use. + * @param key the key for the item. + */ +var _removeItem = function(api, id, key) { + // get storage object + var obj = _getStorageObject(api, id); + if(obj !== null && key in obj) { + // remove key + delete obj[key]; + + // see if entry has no keys remaining + var empty = true; + for(var prop in obj) { + empty = false; + break; + } + if(empty) { + // remove entry entirely if no keys are left + obj = null; + } + + // set storage object + _setStorageObject(api, id, obj); + } +}; + +/** + * Clears the local disk storage identified by the given ID. + * + * @param api the storage interface. + * @param id the storage ID to use. + */ +var _clearItems = function(api, id) { + _setStorageObject(api, id, null); +}; + +/** + * Calls a storage function. + * + * @param func the function to call. + * @param args the arguments for the function. + * @param location the location argument. + * + * @return the return value from the function. + */ +var _callStorageFunction = function(func, args, location) { + var rval = null; + + // default storage types + if(typeof(location) === 'undefined') { + location = ['web', 'flash']; + } + + // apply storage types in order of preference + var type; + var done = false; + var exception = null; + for(var idx in location) { + type = location[idx]; + try { + if(type === 'flash' || type === 'both') { + if(args[0] === null) { + throw new Error('Flash local storage not available.'); + } + rval = func.apply(this, args); + done = (type === 'flash'); + } + if(type === 'web' || type === 'both') { + args[0] = localStorage; + rval = func.apply(this, args); + done = true; + } + } catch(ex) { + exception = ex; + } + if(done) { + break; + } + } + + if(!done) { + throw exception; + } + + return rval; +}; + +/** + * Stores an item on local disk. + * + * The available types of local storage include 'flash', 'web', and 'both'. + * + * The type 'flash' refers to flash local storage (SharedObject). In order + * to use flash local storage, the 'api' parameter must be valid. The type + * 'web' refers to WebStorage, if supported by the browser. The type 'both' + * refers to storing using both 'flash' and 'web', not just one or the + * other. + * + * The location array should list the storage types to use in order of + * preference: + * + * ['flash']: flash only storage + * ['web']: web only storage + * ['both']: try to store in both + * ['flash','web']: store in flash first, but if not available, 'web' + * ['web','flash']: store in web first, but if not available, 'flash' + * + * The location array defaults to: ['web', 'flash'] + * + * @param api the flash interface, null to use only WebStorage. + * @param id the storage ID to use. + * @param key the key for the item. + * @param data the data for the item (any javascript object/primitive). + * @param location an array with the preferred types of storage to use. + */ +util$1.setItem = function(api, id, key, data, location) { + _callStorageFunction(_setItem, arguments, location); +}; + +/** + * Gets an item on local disk. + * + * Set setItem() for details on storage types. + * + * @param api the flash interface, null to use only WebStorage. + * @param id the storage ID to use. + * @param key the key for the item. + * @param location an array with the preferred types of storage to use. + * + * @return the item. + */ +util$1.getItem = function(api, id, key, location) { + return _callStorageFunction(_getItem, arguments, location); +}; + +/** + * Removes an item on local disk. + * + * Set setItem() for details on storage types. + * + * @param api the flash interface. + * @param id the storage ID to use. + * @param key the key for the item. + * @param location an array with the preferred types of storage to use. + */ +util$1.removeItem = function(api, id, key, location) { + _callStorageFunction(_removeItem, arguments, location); +}; + +/** + * Clears the local disk storage identified by the given ID. + * + * Set setItem() for details on storage types. + * + * @param api the flash interface if flash is available. + * @param id the storage ID to use. + * @param location an array with the preferred types of storage to use. + */ +util$1.clearItems = function(api, id, location) { + _callStorageFunction(_clearItems, arguments, location); +}; + +/** + * Check if an object is empty. + * + * Taken from: + * http://stackoverflow.com/questions/679915/how-do-i-test-for-an-empty-javascript-object-from-json/679937#679937 + * + * @param object the object to check. + */ +util$1.isEmpty = function(obj) { + for(var prop in obj) { + if(obj.hasOwnProperty(prop)) { + return false; + } + } + return true; +}; + +/** + * Format with simple printf-style interpolation. + * + * %%: literal '%' + * %s,%o: convert next argument into a string. + * + * @param format the string to format. + * @param ... arguments to interpolate into the format string. + */ +util$1.format = function(format) { + var re = /%./g; + // current match + var match; + // current part + var part; + // current arg index + var argi = 0; + // collected parts to recombine later + var parts = []; + // last index found + var last = 0; + // loop while matches remain + while((match = re.exec(format))) { + part = format.substring(last, re.lastIndex - 2); + // don't add empty strings (ie, parts between %s%s) + if(part.length > 0) { + parts.push(part); + } + last = re.lastIndex; + // switch on % code + var code = match[0][1]; + switch(code) { + case 's': + case 'o': + // check if enough arguments were given + if(argi < arguments.length) { + parts.push(arguments[argi++ + 1]); + } else { + parts.push(''); + } + break; + // FIXME: do proper formating for numbers, etc + //case 'f': + //case 'd': + case '%': + parts.push('%'); + break; + default: + parts.push('<%' + code + '?>'); + } + } + // add trailing part of format string + parts.push(format.substring(last)); + return parts.join(''); +}; + +/** + * Formats a number. + * + * http://snipplr.com/view/5945/javascript-numberformat--ported-from-php/ + */ +util$1.formatNumber = function(number, decimals, dec_point, thousands_sep) { + // http://kevin.vanzonneveld.net + // + original by: Jonas Raoni Soares Silva (http://www.jsfromhell.com) + // + improved by: Kevin van Zonneveld (http://kevin.vanzonneveld.net) + // + bugfix by: Michael White (http://crestidg.com) + // + bugfix by: Benjamin Lupton + // + bugfix by: Allan Jensen (http://www.winternet.no) + // + revised by: Jonas Raoni Soares Silva (http://www.jsfromhell.com) + // * example 1: number_format(1234.5678, 2, '.', ''); + // * returns 1: 1234.57 + + var n = number, c = isNaN(decimals = Math.abs(decimals)) ? 2 : decimals; + var d = dec_point === undefined ? ',' : dec_point; + var t = thousands_sep === undefined ? + '.' : thousands_sep, s = n < 0 ? '-' : ''; + var i = parseInt((n = Math.abs(+n || 0).toFixed(c)), 10) + ''; + var j = (i.length > 3) ? i.length % 3 : 0; + return s + (j ? i.substr(0, j) + t : '') + + i.substr(j).replace(/(\d{3})(?=\d)/g, '$1' + t) + + (c ? d + Math.abs(n - i).toFixed(c).slice(2) : ''); +}; + +/** + * Formats a byte size. + * + * http://snipplr.com/view/5949/format-humanize-file-byte-size-presentation-in-javascript/ + */ +util$1.formatSize = function(size) { + if(size >= 1073741824) { + size = util$1.formatNumber(size / 1073741824, 2, '.', '') + ' GiB'; + } else if(size >= 1048576) { + size = util$1.formatNumber(size / 1048576, 2, '.', '') + ' MiB'; + } else if(size >= 1024) { + size = util$1.formatNumber(size / 1024, 0) + ' KiB'; + } else { + size = util$1.formatNumber(size, 0) + ' bytes'; + } + return size; +}; + +/** + * Converts an IPv4 or IPv6 string representation into bytes (in network order). + * + * @param ip the IPv4 or IPv6 address to convert. + * + * @return the 4-byte IPv6 or 16-byte IPv6 address or null if the address can't + * be parsed. + */ +util$1.bytesFromIP = function(ip) { + if(ip.indexOf('.') !== -1) { + return util$1.bytesFromIPv4(ip); + } + if(ip.indexOf(':') !== -1) { + return util$1.bytesFromIPv6(ip); + } + return null; +}; + +/** + * Converts an IPv4 string representation into bytes (in network order). + * + * @param ip the IPv4 address to convert. + * + * @return the 4-byte address or null if the address can't be parsed. + */ +util$1.bytesFromIPv4 = function(ip) { + ip = ip.split('.'); + if(ip.length !== 4) { + return null; + } + var b = util$1.createBuffer(); + for(var i = 0; i < ip.length; ++i) { + var num = parseInt(ip[i], 10); + if(isNaN(num)) { + return null; + } + b.putByte(num); + } + return b.getBytes(); +}; + +/** + * Converts an IPv6 string representation into bytes (in network order). + * + * @param ip the IPv6 address to convert. + * + * @return the 16-byte address or null if the address can't be parsed. + */ +util$1.bytesFromIPv6 = function(ip) { + var blanks = 0; + ip = ip.split(':').filter(function(e) { + if(e.length === 0) ++blanks; + return true; + }); + var zeros = (8 - ip.length + blanks) * 2; + var b = util$1.createBuffer(); + for(var i = 0; i < 8; ++i) { + if(!ip[i] || ip[i].length === 0) { + b.fillWithByte(0, zeros); + zeros = 0; + continue; + } + var bytes = util$1.hexToBytes(ip[i]); + if(bytes.length < 2) { + b.putByte(0); + } + b.putBytes(bytes); + } + return b.getBytes(); +}; + +/** + * Converts 4-bytes into an IPv4 string representation or 16-bytes into + * an IPv6 string representation. The bytes must be in network order. + * + * @param bytes the bytes to convert. + * + * @return the IPv4 or IPv6 string representation if 4 or 16 bytes, + * respectively, are given, otherwise null. + */ +util$1.bytesToIP = function(bytes) { + if(bytes.length === 4) { + return util$1.bytesToIPv4(bytes); + } + if(bytes.length === 16) { + return util$1.bytesToIPv6(bytes); + } + return null; +}; + +/** + * Converts 4-bytes into an IPv4 string representation. The bytes must be + * in network order. + * + * @param bytes the bytes to convert. + * + * @return the IPv4 string representation or null for an invalid # of bytes. + */ +util$1.bytesToIPv4 = function(bytes) { + if(bytes.length !== 4) { + return null; + } + var ip = []; + for(var i = 0; i < bytes.length; ++i) { + ip.push(bytes.charCodeAt(i)); + } + return ip.join('.'); +}; + +/** + * Converts 16-bytes into an IPv16 string representation. The bytes must be + * in network order. + * + * @param bytes the bytes to convert. + * + * @return the IPv16 string representation or null for an invalid # of bytes. + */ +util$1.bytesToIPv6 = function(bytes) { + if(bytes.length !== 16) { + return null; + } + var ip = []; + var zeroGroups = []; + var zeroMaxGroup = 0; + for(var i = 0; i < bytes.length; i += 2) { + var hex = util$1.bytesToHex(bytes[i] + bytes[i + 1]); + // canonicalize zero representation + while(hex[0] === '0' && hex !== '0') { + hex = hex.substr(1); + } + if(hex === '0') { + var last = zeroGroups[zeroGroups.length - 1]; + var idx = ip.length; + if(!last || idx !== last.end + 1) { + zeroGroups.push({start: idx, end: idx}); + } else { + last.end = idx; + if((last.end - last.start) > + (zeroGroups[zeroMaxGroup].end - zeroGroups[zeroMaxGroup].start)) { + zeroMaxGroup = zeroGroups.length - 1; + } + } + } + ip.push(hex); + } + if(zeroGroups.length > 0) { + var group = zeroGroups[zeroMaxGroup]; + // only shorten group of length > 0 + if(group.end - group.start > 0) { + ip.splice(group.start, group.end - group.start + 1, ''); + if(group.start === 0) { + ip.unshift(''); + } + if(group.end === 7) { + ip.push(''); + } + } + } + return ip.join(':'); +}; + +/** + * Estimates the number of processes that can be run concurrently. If + * creating Web Workers, keep in mind that the main JavaScript process needs + * its own core. + * + * @param options the options to use: + * update true to force an update (not use the cached value). + * @param callback(err, max) called once the operation completes. + */ +util$1.estimateCores = function(options, callback) { + if(typeof options === 'function') { + callback = options; + options = {}; + } + options = options || {}; + if('cores' in util$1 && !options.update) { + return callback(null, util$1.cores); + } + if(typeof navigator !== 'undefined' && + 'hardwareConcurrency' in navigator && + navigator.hardwareConcurrency > 0) { + util$1.cores = navigator.hardwareConcurrency; + return callback(null, util$1.cores); + } + if(typeof Worker === 'undefined') { + // workers not available + util$1.cores = 1; + return callback(null, util$1.cores); + } + if(typeof Blob === 'undefined') { + // can't estimate, default to 2 + util$1.cores = 2; + return callback(null, util$1.cores); + } + + // create worker concurrency estimation code as blob + var blobUrl = URL.createObjectURL(new Blob(['(', + function() { + self.addEventListener('message', function(e) { + // run worker for 4 ms + var st = Date.now(); + var et = st + 4; + self.postMessage({st: st, et: et}); + }); + }.toString(), + ')()'], {type: 'application/javascript'})); + + // take 5 samples using 16 workers + sample([], 5, 16); + + function sample(max, samples, numWorkers) { + if(samples === 0) { + // get overlap average + var avg = Math.floor(max.reduce(function(avg, x) { + return avg + x; + }, 0) / max.length); + util$1.cores = Math.max(1, avg); + URL.revokeObjectURL(blobUrl); + return callback(null, util$1.cores); + } + map(numWorkers, function(err, results) { + max.push(reduce(numWorkers, results)); + sample(max, samples - 1, numWorkers); + }); + } + + function map(numWorkers, callback) { + var workers = []; + var results = []; + for(var i = 0; i < numWorkers; ++i) { + var worker = new Worker(blobUrl); + worker.addEventListener('message', function(e) { + results.push(e.data); + if(results.length === numWorkers) { + for(var i = 0; i < numWorkers; ++i) { + workers[i].terminate(); + } + callback(null, results); + } + }); + workers.push(worker); + } + for(var i = 0; i < numWorkers; ++i) { + workers[i].postMessage(i); + } + } + + function reduce(numWorkers, results) { + // find overlapping time windows + var overlaps = []; + for(var n = 0; n < numWorkers; ++n) { + var r1 = results[n]; + var overlap = overlaps[n] = []; + for(var i = 0; i < numWorkers; ++i) { + if(n === i) { + continue; + } + var r2 = results[i]; + if((r1.st > r2.st && r1.st < r2.et) || + (r2.st > r1.st && r2.st < r1.et)) { + overlap.push(i); + } + } + } + // get maximum overlaps ... don't include overlapping worker itself + // as the main JS process was also being scheduled during the work and + // would have to be subtracted from the estimate anyway + return overlaps.reduce(function(max, overlap) { + return Math.max(max, overlap.length); + }, 0); + } +}; + +/** + * Cipher base API. + * + * @author Dave Longley + * + * Copyright (c) 2010-2014 Digital Bazaar, Inc. + */ + +var forge$B = forge$D; + + +forge$B.cipher = forge$B.cipher || {}; + +// registered algorithms +forge$B.cipher.algorithms = forge$B.cipher.algorithms || {}; + +/** + * Creates a cipher object that can be used to encrypt data using the given + * algorithm and key. The algorithm may be provided as a string value for a + * previously registered algorithm or it may be given as a cipher algorithm + * API object. + * + * @param algorithm the algorithm to use, either a string or an algorithm API + * object. + * @param key the key to use, as a binary-encoded string of bytes or a + * byte buffer. + * + * @return the cipher. + */ +forge$B.cipher.createCipher = function(algorithm, key) { + var api = algorithm; + if(typeof api === 'string') { + api = forge$B.cipher.getAlgorithm(api); + if(api) { + api = api(); + } + } + if(!api) { + throw new Error('Unsupported algorithm: ' + algorithm); + } + + // assume block cipher + return new forge$B.cipher.BlockCipher({ + algorithm: api, + key: key, + decrypt: false + }); +}; + +/** + * Creates a decipher object that can be used to decrypt data using the given + * algorithm and key. The algorithm may be provided as a string value for a + * previously registered algorithm or it may be given as a cipher algorithm + * API object. + * + * @param algorithm the algorithm to use, either a string or an algorithm API + * object. + * @param key the key to use, as a binary-encoded string of bytes or a + * byte buffer. + * + * @return the cipher. + */ +forge$B.cipher.createDecipher = function(algorithm, key) { + var api = algorithm; + if(typeof api === 'string') { + api = forge$B.cipher.getAlgorithm(api); + if(api) { + api = api(); + } + } + if(!api) { + throw new Error('Unsupported algorithm: ' + algorithm); + } + + // assume block cipher + return new forge$B.cipher.BlockCipher({ + algorithm: api, + key: key, + decrypt: true + }); +}; + +/** + * Registers an algorithm by name. If the name was already registered, the + * algorithm API object will be overwritten. + * + * @param name the name of the algorithm. + * @param algorithm the algorithm API object. + */ +forge$B.cipher.registerAlgorithm = function(name, algorithm) { + name = name.toUpperCase(); + forge$B.cipher.algorithms[name] = algorithm; +}; + +/** + * Gets a registered algorithm by name. + * + * @param name the name of the algorithm. + * + * @return the algorithm, if found, null if not. + */ +forge$B.cipher.getAlgorithm = function(name) { + name = name.toUpperCase(); + if(name in forge$B.cipher.algorithms) { + return forge$B.cipher.algorithms[name]; + } + return null; +}; + +var BlockCipher = forge$B.cipher.BlockCipher = function(options) { + this.algorithm = options.algorithm; + this.mode = this.algorithm.mode; + this.blockSize = this.mode.blockSize; + this._finish = false; + this._input = null; + this.output = null; + this._op = options.decrypt ? this.mode.decrypt : this.mode.encrypt; + this._decrypt = options.decrypt; + this.algorithm.initialize(options); +}; + +/** + * Starts or restarts the encryption or decryption process, whichever + * was previously configured. + * + * For non-GCM mode, the IV may be a binary-encoded string of bytes, an array + * of bytes, a byte buffer, or an array of 32-bit integers. If the IV is in + * bytes, then it must be Nb (16) bytes in length. If the IV is given in as + * 32-bit integers, then it must be 4 integers long. + * + * Note: an IV is not required or used in ECB mode. + * + * For GCM-mode, the IV must be given as a binary-encoded string of bytes or + * a byte buffer. The number of bytes should be 12 (96 bits) as recommended + * by NIST SP-800-38D but another length may be given. + * + * @param options the options to use: + * iv the initialization vector to use as a binary-encoded string of + * bytes, null to reuse the last ciphered block from a previous + * update() (this "residue" method is for legacy support only). + * additionalData additional authentication data as a binary-encoded + * string of bytes, for 'GCM' mode, (default: none). + * tagLength desired length of authentication tag, in bits, for + * 'GCM' mode (0-128, default: 128). + * tag the authentication tag to check if decrypting, as a + * binary-encoded string of bytes. + * output the output the buffer to write to, null to create one. + */ +BlockCipher.prototype.start = function(options) { + options = options || {}; + var opts = {}; + for(var key in options) { + opts[key] = options[key]; + } + opts.decrypt = this._decrypt; + this._finish = false; + this._input = forge$B.util.createBuffer(); + this.output = options.output || forge$B.util.createBuffer(); + this.mode.start(opts); +}; + +/** + * Updates the next block according to the cipher mode. + * + * @param input the buffer to read from. + */ +BlockCipher.prototype.update = function(input) { + if(input) { + // input given, so empty it into the input buffer + this._input.putBuffer(input); + } + + // do cipher operation until it needs more input and not finished + while(!this._op.call(this.mode, this._input, this.output, this._finish) && + !this._finish) {} + + // free consumed memory from input buffer + this._input.compact(); +}; + +/** + * Finishes encrypting or decrypting. + * + * @param pad a padding function to use in CBC mode, null for default, + * signature(blockSize, buffer, decrypt). + * + * @return true if successful, false on error. + */ +BlockCipher.prototype.finish = function(pad) { + // backwards-compatibility w/deprecated padding API + // Note: will overwrite padding functions even after another start() call + if(pad && (this.mode.name === 'ECB' || this.mode.name === 'CBC')) { + this.mode.pad = function(input) { + return pad(this.blockSize, input, false); + }; + this.mode.unpad = function(output) { + return pad(this.blockSize, output, true); + }; + } + + // build options for padding and afterFinish functions + var options = {}; + options.decrypt = this._decrypt; + + // get # of bytes that won't fill a block + options.overflow = this._input.length() % this.blockSize; + + if(!this._decrypt && this.mode.pad) { + if(!this.mode.pad(this._input, options)) { + return false; + } + } + + // do final update + this._finish = true; + this.update(); + + if(this._decrypt && this.mode.unpad) { + if(!this.mode.unpad(this.output, options)) { + return false; + } + } + + if(this.mode.afterFinish) { + if(!this.mode.afterFinish(this.output, options)) { + return false; + } + } + + return true; +}; + +/** + * Supported cipher modes. + * + * @author Dave Longley + * + * Copyright (c) 2010-2014 Digital Bazaar, Inc. + */ + +var forge$A = forge$D; + + +forge$A.cipher = forge$A.cipher || {}; + +// supported cipher modes +var modes = forge$A.cipher.modes = forge$A.cipher.modes || {}; + +/** Electronic codebook (ECB) (Don't use this; it's not secure) **/ + +modes.ecb = function(options) { + options = options || {}; + this.name = 'ECB'; + this.cipher = options.cipher; + this.blockSize = options.blockSize || 16; + this._ints = this.blockSize / 4; + this._inBlock = new Array(this._ints); + this._outBlock = new Array(this._ints); +}; + +modes.ecb.prototype.start = function(options) {}; + +modes.ecb.prototype.encrypt = function(input, output, finish) { + // not enough input to encrypt + if(input.length() < this.blockSize && !(finish && input.length() > 0)) { + return true; + } + + // get next block + for(var i = 0; i < this._ints; ++i) { + this._inBlock[i] = input.getInt32(); + } + + // encrypt block + this.cipher.encrypt(this._inBlock, this._outBlock); + + // write output + for(var i = 0; i < this._ints; ++i) { + output.putInt32(this._outBlock[i]); + } +}; + +modes.ecb.prototype.decrypt = function(input, output, finish) { + // not enough input to decrypt + if(input.length() < this.blockSize && !(finish && input.length() > 0)) { + return true; + } + + // get next block + for(var i = 0; i < this._ints; ++i) { + this._inBlock[i] = input.getInt32(); + } + + // decrypt block + this.cipher.decrypt(this._inBlock, this._outBlock); + + // write output + for(var i = 0; i < this._ints; ++i) { + output.putInt32(this._outBlock[i]); + } +}; + +modes.ecb.prototype.pad = function(input, options) { + // add PKCS#7 padding to block (each pad byte is the + // value of the number of pad bytes) + var padding = (input.length() === this.blockSize ? + this.blockSize : (this.blockSize - input.length())); + input.fillWithByte(padding, padding); + return true; +}; + +modes.ecb.prototype.unpad = function(output, options) { + // check for error: input data not a multiple of blockSize + if(options.overflow > 0) { + return false; + } + + // ensure padding byte count is valid + var len = output.length(); + var count = output.at(len - 1); + if(count > (this.blockSize << 2)) { + return false; + } + + // trim off padding bytes + output.truncate(count); + return true; +}; + +/** Cipher-block Chaining (CBC) **/ + +modes.cbc = function(options) { + options = options || {}; + this.name = 'CBC'; + this.cipher = options.cipher; + this.blockSize = options.blockSize || 16; + this._ints = this.blockSize / 4; + this._inBlock = new Array(this._ints); + this._outBlock = new Array(this._ints); +}; + +modes.cbc.prototype.start = function(options) { + // Note: legacy support for using IV residue (has security flaws) + // if IV is null, reuse block from previous processing + if(options.iv === null) { + // must have a previous block + if(!this._prev) { + throw new Error('Invalid IV parameter.'); + } + this._iv = this._prev.slice(0); + } else if(!('iv' in options)) { + throw new Error('Invalid IV parameter.'); + } else { + // save IV as "previous" block + this._iv = transformIV(options.iv, this.blockSize); + this._prev = this._iv.slice(0); + } +}; + +modes.cbc.prototype.encrypt = function(input, output, finish) { + // not enough input to encrypt + if(input.length() < this.blockSize && !(finish && input.length() > 0)) { + return true; + } + + // get next block + // CBC XOR's IV (or previous block) with plaintext + for(var i = 0; i < this._ints; ++i) { + this._inBlock[i] = this._prev[i] ^ input.getInt32(); + } + + // encrypt block + this.cipher.encrypt(this._inBlock, this._outBlock); + + // write output, save previous block + for(var i = 0; i < this._ints; ++i) { + output.putInt32(this._outBlock[i]); + } + this._prev = this._outBlock; +}; + +modes.cbc.prototype.decrypt = function(input, output, finish) { + // not enough input to decrypt + if(input.length() < this.blockSize && !(finish && input.length() > 0)) { + return true; + } + + // get next block + for(var i = 0; i < this._ints; ++i) { + this._inBlock[i] = input.getInt32(); + } + + // decrypt block + this.cipher.decrypt(this._inBlock, this._outBlock); + + // write output, save previous ciphered block + // CBC XOR's IV (or previous block) with ciphertext + for(var i = 0; i < this._ints; ++i) { + output.putInt32(this._prev[i] ^ this._outBlock[i]); + } + this._prev = this._inBlock.slice(0); +}; + +modes.cbc.prototype.pad = function(input, options) { + // add PKCS#7 padding to block (each pad byte is the + // value of the number of pad bytes) + var padding = (input.length() === this.blockSize ? + this.blockSize : (this.blockSize - input.length())); + input.fillWithByte(padding, padding); + return true; +}; + +modes.cbc.prototype.unpad = function(output, options) { + // check for error: input data not a multiple of blockSize + if(options.overflow > 0) { + return false; + } + + // ensure padding byte count is valid + var len = output.length(); + var count = output.at(len - 1); + if(count > (this.blockSize << 2)) { + return false; + } + + // trim off padding bytes + output.truncate(count); + return true; +}; + +/** Cipher feedback (CFB) **/ + +modes.cfb = function(options) { + options = options || {}; + this.name = 'CFB'; + this.cipher = options.cipher; + this.blockSize = options.blockSize || 16; + this._ints = this.blockSize / 4; + this._inBlock = null; + this._outBlock = new Array(this._ints); + this._partialBlock = new Array(this._ints); + this._partialOutput = forge$A.util.createBuffer(); + this._partialBytes = 0; +}; + +modes.cfb.prototype.start = function(options) { + if(!('iv' in options)) { + throw new Error('Invalid IV parameter.'); + } + // use IV as first input + this._iv = transformIV(options.iv, this.blockSize); + this._inBlock = this._iv.slice(0); + this._partialBytes = 0; +}; + +modes.cfb.prototype.encrypt = function(input, output, finish) { + // not enough input to encrypt + var inputLength = input.length(); + if(inputLength === 0) { + return true; + } + + // encrypt block + this.cipher.encrypt(this._inBlock, this._outBlock); + + // handle full block + if(this._partialBytes === 0 && inputLength >= this.blockSize) { + // XOR input with output, write input as output + for(var i = 0; i < this._ints; ++i) { + this._inBlock[i] = input.getInt32() ^ this._outBlock[i]; + output.putInt32(this._inBlock[i]); + } + return; + } + + // handle partial block + var partialBytes = (this.blockSize - inputLength) % this.blockSize; + if(partialBytes > 0) { + partialBytes = this.blockSize - partialBytes; + } + + // XOR input with output, write input as partial output + this._partialOutput.clear(); + for(var i = 0; i < this._ints; ++i) { + this._partialBlock[i] = input.getInt32() ^ this._outBlock[i]; + this._partialOutput.putInt32(this._partialBlock[i]); + } + + if(partialBytes > 0) { + // block still incomplete, restore input buffer + input.read -= this.blockSize; + } else { + // block complete, update input block + for(var i = 0; i < this._ints; ++i) { + this._inBlock[i] = this._partialBlock[i]; + } + } + + // skip any previous partial bytes + if(this._partialBytes > 0) { + this._partialOutput.getBytes(this._partialBytes); + } + + if(partialBytes > 0 && !finish) { + output.putBytes(this._partialOutput.getBytes( + partialBytes - this._partialBytes)); + this._partialBytes = partialBytes; + return true; + } + + output.putBytes(this._partialOutput.getBytes( + inputLength - this._partialBytes)); + this._partialBytes = 0; +}; + +modes.cfb.prototype.decrypt = function(input, output, finish) { + // not enough input to decrypt + var inputLength = input.length(); + if(inputLength === 0) { + return true; + } + + // encrypt block (CFB always uses encryption mode) + this.cipher.encrypt(this._inBlock, this._outBlock); + + // handle full block + if(this._partialBytes === 0 && inputLength >= this.blockSize) { + // XOR input with output, write input as output + for(var i = 0; i < this._ints; ++i) { + this._inBlock[i] = input.getInt32(); + output.putInt32(this._inBlock[i] ^ this._outBlock[i]); + } + return; + } + + // handle partial block + var partialBytes = (this.blockSize - inputLength) % this.blockSize; + if(partialBytes > 0) { + partialBytes = this.blockSize - partialBytes; + } + + // XOR input with output, write input as partial output + this._partialOutput.clear(); + for(var i = 0; i < this._ints; ++i) { + this._partialBlock[i] = input.getInt32(); + this._partialOutput.putInt32(this._partialBlock[i] ^ this._outBlock[i]); + } + + if(partialBytes > 0) { + // block still incomplete, restore input buffer + input.read -= this.blockSize; + } else { + // block complete, update input block + for(var i = 0; i < this._ints; ++i) { + this._inBlock[i] = this._partialBlock[i]; + } + } + + // skip any previous partial bytes + if(this._partialBytes > 0) { + this._partialOutput.getBytes(this._partialBytes); + } + + if(partialBytes > 0 && !finish) { + output.putBytes(this._partialOutput.getBytes( + partialBytes - this._partialBytes)); + this._partialBytes = partialBytes; + return true; + } + + output.putBytes(this._partialOutput.getBytes( + inputLength - this._partialBytes)); + this._partialBytes = 0; +}; + +/** Output feedback (OFB) **/ + +modes.ofb = function(options) { + options = options || {}; + this.name = 'OFB'; + this.cipher = options.cipher; + this.blockSize = options.blockSize || 16; + this._ints = this.blockSize / 4; + this._inBlock = null; + this._outBlock = new Array(this._ints); + this._partialOutput = forge$A.util.createBuffer(); + this._partialBytes = 0; +}; + +modes.ofb.prototype.start = function(options) { + if(!('iv' in options)) { + throw new Error('Invalid IV parameter.'); + } + // use IV as first input + this._iv = transformIV(options.iv, this.blockSize); + this._inBlock = this._iv.slice(0); + this._partialBytes = 0; +}; + +modes.ofb.prototype.encrypt = function(input, output, finish) { + // not enough input to encrypt + var inputLength = input.length(); + if(input.length() === 0) { + return true; + } + + // encrypt block (OFB always uses encryption mode) + this.cipher.encrypt(this._inBlock, this._outBlock); + + // handle full block + if(this._partialBytes === 0 && inputLength >= this.blockSize) { + // XOR input with output and update next input + for(var i = 0; i < this._ints; ++i) { + output.putInt32(input.getInt32() ^ this._outBlock[i]); + this._inBlock[i] = this._outBlock[i]; + } + return; + } + + // handle partial block + var partialBytes = (this.blockSize - inputLength) % this.blockSize; + if(partialBytes > 0) { + partialBytes = this.blockSize - partialBytes; + } + + // XOR input with output + this._partialOutput.clear(); + for(var i = 0; i < this._ints; ++i) { + this._partialOutput.putInt32(input.getInt32() ^ this._outBlock[i]); + } + + if(partialBytes > 0) { + // block still incomplete, restore input buffer + input.read -= this.blockSize; + } else { + // block complete, update input block + for(var i = 0; i < this._ints; ++i) { + this._inBlock[i] = this._outBlock[i]; + } + } + + // skip any previous partial bytes + if(this._partialBytes > 0) { + this._partialOutput.getBytes(this._partialBytes); + } + + if(partialBytes > 0 && !finish) { + output.putBytes(this._partialOutput.getBytes( + partialBytes - this._partialBytes)); + this._partialBytes = partialBytes; + return true; + } + + output.putBytes(this._partialOutput.getBytes( + inputLength - this._partialBytes)); + this._partialBytes = 0; +}; + +modes.ofb.prototype.decrypt = modes.ofb.prototype.encrypt; + +/** Counter (CTR) **/ + +modes.ctr = function(options) { + options = options || {}; + this.name = 'CTR'; + this.cipher = options.cipher; + this.blockSize = options.blockSize || 16; + this._ints = this.blockSize / 4; + this._inBlock = null; + this._outBlock = new Array(this._ints); + this._partialOutput = forge$A.util.createBuffer(); + this._partialBytes = 0; +}; + +modes.ctr.prototype.start = function(options) { + if(!('iv' in options)) { + throw new Error('Invalid IV parameter.'); + } + // use IV as first input + this._iv = transformIV(options.iv, this.blockSize); + this._inBlock = this._iv.slice(0); + this._partialBytes = 0; +}; + +modes.ctr.prototype.encrypt = function(input, output, finish) { + // not enough input to encrypt + var inputLength = input.length(); + if(inputLength === 0) { + return true; + } + + // encrypt block (CTR always uses encryption mode) + this.cipher.encrypt(this._inBlock, this._outBlock); + + // handle full block + if(this._partialBytes === 0 && inputLength >= this.blockSize) { + // XOR input with output + for(var i = 0; i < this._ints; ++i) { + output.putInt32(input.getInt32() ^ this._outBlock[i]); + } + } else { + // handle partial block + var partialBytes = (this.blockSize - inputLength) % this.blockSize; + if(partialBytes > 0) { + partialBytes = this.blockSize - partialBytes; + } + + // XOR input with output + this._partialOutput.clear(); + for(var i = 0; i < this._ints; ++i) { + this._partialOutput.putInt32(input.getInt32() ^ this._outBlock[i]); + } + + if(partialBytes > 0) { + // block still incomplete, restore input buffer + input.read -= this.blockSize; + } + + // skip any previous partial bytes + if(this._partialBytes > 0) { + this._partialOutput.getBytes(this._partialBytes); + } + + if(partialBytes > 0 && !finish) { + output.putBytes(this._partialOutput.getBytes( + partialBytes - this._partialBytes)); + this._partialBytes = partialBytes; + return true; + } + + output.putBytes(this._partialOutput.getBytes( + inputLength - this._partialBytes)); + this._partialBytes = 0; + } + + // block complete, increment counter (input block) + inc32(this._inBlock); +}; + +modes.ctr.prototype.decrypt = modes.ctr.prototype.encrypt; + +/** Galois/Counter Mode (GCM) **/ + +modes.gcm = function(options) { + options = options || {}; + this.name = 'GCM'; + this.cipher = options.cipher; + this.blockSize = options.blockSize || 16; + this._ints = this.blockSize / 4; + this._inBlock = new Array(this._ints); + this._outBlock = new Array(this._ints); + this._partialOutput = forge$A.util.createBuffer(); + this._partialBytes = 0; + + // R is actually this value concatenated with 120 more zero bits, but + // we only XOR against R so the other zeros have no effect -- we just + // apply this value to the first integer in a block + this._R = 0xE1000000; +}; + +modes.gcm.prototype.start = function(options) { + if(!('iv' in options)) { + throw new Error('Invalid IV parameter.'); + } + // ensure IV is a byte buffer + var iv = forge$A.util.createBuffer(options.iv); + + // no ciphered data processed yet + this._cipherLength = 0; + + // default additional data is none + var additionalData; + if('additionalData' in options) { + additionalData = forge$A.util.createBuffer(options.additionalData); + } else { + additionalData = forge$A.util.createBuffer(); + } + + // default tag length is 128 bits + if('tagLength' in options) { + this._tagLength = options.tagLength; + } else { + this._tagLength = 128; + } + + // if tag is given, ensure tag matches tag length + this._tag = null; + if(options.decrypt) { + // save tag to check later + this._tag = forge$A.util.createBuffer(options.tag).getBytes(); + if(this._tag.length !== (this._tagLength / 8)) { + throw new Error('Authentication tag does not match tag length.'); + } + } + + // create tmp storage for hash calculation + this._hashBlock = new Array(this._ints); + + // no tag generated yet + this.tag = null; + + // generate hash subkey + // (apply block cipher to "zero" block) + this._hashSubkey = new Array(this._ints); + this.cipher.encrypt([0, 0, 0, 0], this._hashSubkey); + + // generate table M + // use 4-bit tables (32 component decomposition of a 16 byte value) + // 8-bit tables take more space and are known to have security + // vulnerabilities (in native implementations) + this.componentBits = 4; + this._m = this.generateHashTable(this._hashSubkey, this.componentBits); + + // Note: support IV length different from 96 bits? (only supporting + // 96 bits is recommended by NIST SP-800-38D) + // generate J_0 + var ivLength = iv.length(); + if(ivLength === 12) { + // 96-bit IV + this._j0 = [iv.getInt32(), iv.getInt32(), iv.getInt32(), 1]; + } else { + // IV is NOT 96-bits + this._j0 = [0, 0, 0, 0]; + while(iv.length() > 0) { + this._j0 = this.ghash( + this._hashSubkey, this._j0, + [iv.getInt32(), iv.getInt32(), iv.getInt32(), iv.getInt32()]); + } + this._j0 = this.ghash( + this._hashSubkey, this._j0, [0, 0].concat(from64To32(ivLength * 8))); + } + + // generate ICB (initial counter block) + this._inBlock = this._j0.slice(0); + inc32(this._inBlock); + this._partialBytes = 0; + + // consume authentication data + additionalData = forge$A.util.createBuffer(additionalData); + // save additional data length as a BE 64-bit number + this._aDataLength = from64To32(additionalData.length() * 8); + // pad additional data to 128 bit (16 byte) block size + var overflow = additionalData.length() % this.blockSize; + if(overflow) { + additionalData.fillWithByte(0, this.blockSize - overflow); + } + this._s = [0, 0, 0, 0]; + while(additionalData.length() > 0) { + this._s = this.ghash(this._hashSubkey, this._s, [ + additionalData.getInt32(), + additionalData.getInt32(), + additionalData.getInt32(), + additionalData.getInt32() + ]); + } +}; + +modes.gcm.prototype.encrypt = function(input, output, finish) { + // not enough input to encrypt + var inputLength = input.length(); + if(inputLength === 0) { + return true; + } + + // encrypt block + this.cipher.encrypt(this._inBlock, this._outBlock); + + // handle full block + if(this._partialBytes === 0 && inputLength >= this.blockSize) { + // XOR input with output + for(var i = 0; i < this._ints; ++i) { + output.putInt32(this._outBlock[i] ^= input.getInt32()); + } + this._cipherLength += this.blockSize; + } else { + // handle partial block + var partialBytes = (this.blockSize - inputLength) % this.blockSize; + if(partialBytes > 0) { + partialBytes = this.blockSize - partialBytes; + } + + // XOR input with output + this._partialOutput.clear(); + for(var i = 0; i < this._ints; ++i) { + this._partialOutput.putInt32(input.getInt32() ^ this._outBlock[i]); + } + + if(partialBytes <= 0 || finish) { + // handle overflow prior to hashing + if(finish) { + // get block overflow + var overflow = inputLength % this.blockSize; + this._cipherLength += overflow; + // truncate for hash function + this._partialOutput.truncate(this.blockSize - overflow); + } else { + this._cipherLength += this.blockSize; + } + + // get output block for hashing + for(var i = 0; i < this._ints; ++i) { + this._outBlock[i] = this._partialOutput.getInt32(); + } + this._partialOutput.read -= this.blockSize; + } + + // skip any previous partial bytes + if(this._partialBytes > 0) { + this._partialOutput.getBytes(this._partialBytes); + } + + if(partialBytes > 0 && !finish) { + // block still incomplete, restore input buffer, get partial output, + // and return early + input.read -= this.blockSize; + output.putBytes(this._partialOutput.getBytes( + partialBytes - this._partialBytes)); + this._partialBytes = partialBytes; + return true; + } + + output.putBytes(this._partialOutput.getBytes( + inputLength - this._partialBytes)); + this._partialBytes = 0; + } + + // update hash block S + this._s = this.ghash(this._hashSubkey, this._s, this._outBlock); + + // increment counter (input block) + inc32(this._inBlock); +}; + +modes.gcm.prototype.decrypt = function(input, output, finish) { + // not enough input to decrypt + var inputLength = input.length(); + if(inputLength < this.blockSize && !(finish && inputLength > 0)) { + return true; + } + + // encrypt block (GCM always uses encryption mode) + this.cipher.encrypt(this._inBlock, this._outBlock); + + // increment counter (input block) + inc32(this._inBlock); + + // update hash block S + this._hashBlock[0] = input.getInt32(); + this._hashBlock[1] = input.getInt32(); + this._hashBlock[2] = input.getInt32(); + this._hashBlock[3] = input.getInt32(); + this._s = this.ghash(this._hashSubkey, this._s, this._hashBlock); + + // XOR hash input with output + for(var i = 0; i < this._ints; ++i) { + output.putInt32(this._outBlock[i] ^ this._hashBlock[i]); + } + + // increment cipher data length + if(inputLength < this.blockSize) { + this._cipherLength += inputLength % this.blockSize; + } else { + this._cipherLength += this.blockSize; + } +}; + +modes.gcm.prototype.afterFinish = function(output, options) { + var rval = true; + + // handle overflow + if(options.decrypt && options.overflow) { + output.truncate(this.blockSize - options.overflow); + } + + // handle authentication tag + this.tag = forge$A.util.createBuffer(); + + // concatenate additional data length with cipher length + var lengths = this._aDataLength.concat(from64To32(this._cipherLength * 8)); + + // include lengths in hash + this._s = this.ghash(this._hashSubkey, this._s, lengths); + + // do GCTR(J_0, S) + var tag = []; + this.cipher.encrypt(this._j0, tag); + for(var i = 0; i < this._ints; ++i) { + this.tag.putInt32(this._s[i] ^ tag[i]); + } + + // trim tag to length + this.tag.truncate(this.tag.length() % (this._tagLength / 8)); + + // check authentication tag + if(options.decrypt && this.tag.bytes() !== this._tag) { + rval = false; + } + + return rval; +}; + +/** + * See NIST SP-800-38D 6.3 (Algorithm 1). This function performs Galois + * field multiplication. The field, GF(2^128), is defined by the polynomial: + * + * x^128 + x^7 + x^2 + x + 1 + * + * Which is represented in little-endian binary form as: 11100001 (0xe1). When + * the value of a coefficient is 1, a bit is set. The value R, is the + * concatenation of this value and 120 zero bits, yielding a 128-bit value + * which matches the block size. + * + * This function will multiply two elements (vectors of bytes), X and Y, in + * the field GF(2^128). The result is initialized to zero. For each bit of + * X (out of 128), x_i, if x_i is set, then the result is multiplied (XOR'd) + * by the current value of Y. For each bit, the value of Y will be raised by + * a power of x (multiplied by the polynomial x). This can be achieved by + * shifting Y once to the right. If the current value of Y, prior to being + * multiplied by x, has 0 as its LSB, then it is a 127th degree polynomial. + * Otherwise, we must divide by R after shifting to find the remainder. + * + * @param x the first block to multiply by the second. + * @param y the second block to multiply by the first. + * + * @return the block result of the multiplication. + */ +modes.gcm.prototype.multiply = function(x, y) { + var z_i = [0, 0, 0, 0]; + var v_i = y.slice(0); + + // calculate Z_128 (block has 128 bits) + for(var i = 0; i < 128; ++i) { + // if x_i is 0, Z_{i+1} = Z_i (unchanged) + // else Z_{i+1} = Z_i ^ V_i + // get x_i by finding 32-bit int position, then left shift 1 by remainder + var x_i = x[(i / 32) | 0] & (1 << (31 - i % 32)); + if(x_i) { + z_i[0] ^= v_i[0]; + z_i[1] ^= v_i[1]; + z_i[2] ^= v_i[2]; + z_i[3] ^= v_i[3]; + } + + // if LSB(V_i) is 1, V_i = V_i >> 1 + // else V_i = (V_i >> 1) ^ R + this.pow(v_i, v_i); + } + + return z_i; +}; + +modes.gcm.prototype.pow = function(x, out) { + // if LSB(x) is 1, x = x >>> 1 + // else x = (x >>> 1) ^ R + var lsb = x[3] & 1; + + // always do x >>> 1: + // starting with the rightmost integer, shift each integer to the right + // one bit, pulling in the bit from the integer to the left as its top + // most bit (do this for the last 3 integers) + for(var i = 3; i > 0; --i) { + out[i] = (x[i] >>> 1) | ((x[i - 1] & 1) << 31); + } + // shift the first integer normally + out[0] = x[0] >>> 1; + + // if lsb was not set, then polynomial had a degree of 127 and doesn't + // need to divided; otherwise, XOR with R to find the remainder; we only + // need to XOR the first integer since R technically ends w/120 zero bits + if(lsb) { + out[0] ^= this._R; + } +}; + +modes.gcm.prototype.tableMultiply = function(x) { + // assumes 4-bit tables are used + var z = [0, 0, 0, 0]; + for(var i = 0; i < 32; ++i) { + var idx = (i / 8) | 0; + var x_i = (x[idx] >>> ((7 - (i % 8)) * 4)) & 0xF; + var ah = this._m[i][x_i]; + z[0] ^= ah[0]; + z[1] ^= ah[1]; + z[2] ^= ah[2]; + z[3] ^= ah[3]; + } + return z; +}; + +/** + * A continuing version of the GHASH algorithm that operates on a single + * block. The hash block, last hash value (Ym) and the new block to hash + * are given. + * + * @param h the hash block. + * @param y the previous value for Ym, use [0, 0, 0, 0] for a new hash. + * @param x the block to hash. + * + * @return the hashed value (Ym). + */ +modes.gcm.prototype.ghash = function(h, y, x) { + y[0] ^= x[0]; + y[1] ^= x[1]; + y[2] ^= x[2]; + y[3] ^= x[3]; + return this.tableMultiply(y); + //return this.multiply(y, h); +}; + +/** + * Precomputes a table for multiplying against the hash subkey. This + * mechanism provides a substantial speed increase over multiplication + * performed without a table. The table-based multiplication this table is + * for solves X * H by multiplying each component of X by H and then + * composing the results together using XOR. + * + * This function can be used to generate tables with different bit sizes + * for the components, however, this implementation assumes there are + * 32 components of X (which is a 16 byte vector), therefore each component + * takes 4-bits (so the table is constructed with bits=4). + * + * @param h the hash subkey. + * @param bits the bit size for a component. + */ +modes.gcm.prototype.generateHashTable = function(h, bits) { + // TODO: There are further optimizations that would use only the + // first table M_0 (or some variant) along with a remainder table; + // this can be explored in the future + var multiplier = 8 / bits; + var perInt = 4 * multiplier; + var size = 16 * multiplier; + var m = new Array(size); + for(var i = 0; i < size; ++i) { + var tmp = [0, 0, 0, 0]; + var idx = (i / perInt) | 0; + var shft = ((perInt - 1 - (i % perInt)) * bits); + tmp[idx] = (1 << (bits - 1)) << shft; + m[i] = this.generateSubHashTable(this.multiply(tmp, h), bits); + } + return m; +}; + +/** + * Generates a table for multiplying against the hash subkey for one + * particular component (out of all possible component values). + * + * @param mid the pre-multiplied value for the middle key of the table. + * @param bits the bit size for a component. + */ +modes.gcm.prototype.generateSubHashTable = function(mid, bits) { + // compute the table quickly by minimizing the number of + // POW operations -- they only need to be performed for powers of 2, + // all other entries can be composed from those powers using XOR + var size = 1 << bits; + var half = size >>> 1; + var m = new Array(size); + m[half] = mid.slice(0); + var i = half >>> 1; + while(i > 0) { + // raise m0[2 * i] and store in m0[i] + this.pow(m[2 * i], m[i] = []); + i >>= 1; + } + i = 2; + while(i < half) { + for(var j = 1; j < i; ++j) { + var m_i = m[i]; + var m_j = m[j]; + m[i + j] = [ + m_i[0] ^ m_j[0], + m_i[1] ^ m_j[1], + m_i[2] ^ m_j[2], + m_i[3] ^ m_j[3] + ]; + } + i *= 2; + } + m[0] = [0, 0, 0, 0]; + /* Note: We could avoid storing these by doing composition during multiply + calculate top half using composition by speed is preferred. */ + for(i = half + 1; i < size; ++i) { + var c = m[i ^ half]; + m[i] = [mid[0] ^ c[0], mid[1] ^ c[1], mid[2] ^ c[2], mid[3] ^ c[3]]; + } + return m; +}; + +/** Utility functions */ + +function transformIV(iv, blockSize) { + if(typeof iv === 'string') { + // convert iv string into byte buffer + iv = forge$A.util.createBuffer(iv); + } + + if(forge$A.util.isArray(iv) && iv.length > 4) { + // convert iv byte array into byte buffer + var tmp = iv; + iv = forge$A.util.createBuffer(); + for(var i = 0; i < tmp.length; ++i) { + iv.putByte(tmp[i]); + } + } + + if(iv.length() < blockSize) { + throw new Error( + 'Invalid IV length; got ' + iv.length() + + ' bytes and expected ' + blockSize + ' bytes.'); + } + + if(!forge$A.util.isArray(iv)) { + // convert iv byte buffer into 32-bit integer array + var ints = []; + var blocks = blockSize / 4; + for(var i = 0; i < blocks; ++i) { + ints.push(iv.getInt32()); + } + iv = ints; + } + + return iv; +} + +function inc32(block) { + // increment last 32 bits of block only + block[block.length - 1] = (block[block.length - 1] + 1) & 0xFFFFFFFF; +} + +function from64To32(num) { + // convert 64-bit number to two BE Int32s + return [(num / 0x100000000) | 0, num & 0xFFFFFFFF]; +} + +/** + * Advanced Encryption Standard (AES) implementation. + * + * This implementation is based on the public domain library 'jscrypto' which + * was written by: + * + * Emily Stark (estark@stanford.edu) + * Mike Hamburg (mhamburg@stanford.edu) + * Dan Boneh (dabo@cs.stanford.edu) + * + * Parts of this code are based on the OpenSSL implementation of AES: + * http://www.openssl.org + * + * @author Dave Longley + * + * Copyright (c) 2010-2014 Digital Bazaar, Inc. + */ + +var forge$z = forge$D; + + + + +/* AES API */ +forge$z.aes = forge$z.aes || {}; + +/** + * Deprecated. Instead, use: + * + * var cipher = forge.cipher.createCipher('AES-', key); + * cipher.start({iv: iv}); + * + * Creates an AES cipher object to encrypt data using the given symmetric key. + * The output will be stored in the 'output' member of the returned cipher. + * + * The key and iv may be given as a string of bytes, an array of bytes, + * a byte buffer, or an array of 32-bit words. + * + * @param key the symmetric key to use. + * @param iv the initialization vector to use. + * @param output the buffer to write to, null to create one. + * @param mode the cipher mode to use (default: 'CBC'). + * + * @return the cipher. + */ +forge$z.aes.startEncrypting = function(key, iv, output, mode) { + var cipher = _createCipher$1({ + key: key, + output: output, + decrypt: false, + mode: mode + }); + cipher.start(iv); + return cipher; +}; + +/** + * Deprecated. Instead, use: + * + * var cipher = forge.cipher.createCipher('AES-', key); + * + * Creates an AES cipher object to encrypt data using the given symmetric key. + * + * The key may be given as a string of bytes, an array of bytes, a + * byte buffer, or an array of 32-bit words. + * + * @param key the symmetric key to use. + * @param mode the cipher mode to use (default: 'CBC'). + * + * @return the cipher. + */ +forge$z.aes.createEncryptionCipher = function(key, mode) { + return _createCipher$1({ + key: key, + output: null, + decrypt: false, + mode: mode + }); +}; + +/** + * Deprecated. Instead, use: + * + * var decipher = forge.cipher.createDecipher('AES-', key); + * decipher.start({iv: iv}); + * + * Creates an AES cipher object to decrypt data using the given symmetric key. + * The output will be stored in the 'output' member of the returned cipher. + * + * The key and iv may be given as a string of bytes, an array of bytes, + * a byte buffer, or an array of 32-bit words. + * + * @param key the symmetric key to use. + * @param iv the initialization vector to use. + * @param output the buffer to write to, null to create one. + * @param mode the cipher mode to use (default: 'CBC'). + * + * @return the cipher. + */ +forge$z.aes.startDecrypting = function(key, iv, output, mode) { + var cipher = _createCipher$1({ + key: key, + output: output, + decrypt: true, + mode: mode + }); + cipher.start(iv); + return cipher; +}; + +/** + * Deprecated. Instead, use: + * + * var decipher = forge.cipher.createDecipher('AES-', key); + * + * Creates an AES cipher object to decrypt data using the given symmetric key. + * + * The key may be given as a string of bytes, an array of bytes, a + * byte buffer, or an array of 32-bit words. + * + * @param key the symmetric key to use. + * @param mode the cipher mode to use (default: 'CBC'). + * + * @return the cipher. + */ +forge$z.aes.createDecryptionCipher = function(key, mode) { + return _createCipher$1({ + key: key, + output: null, + decrypt: true, + mode: mode + }); +}; + +/** + * Creates a new AES cipher algorithm object. + * + * @param name the name of the algorithm. + * @param mode the mode factory function. + * + * @return the AES algorithm object. + */ +forge$z.aes.Algorithm = function(name, mode) { + if(!init) { + initialize(); + } + var self = this; + self.name = name; + self.mode = new mode({ + blockSize: 16, + cipher: { + encrypt: function(inBlock, outBlock) { + return _updateBlock$1(self._w, inBlock, outBlock, false); + }, + decrypt: function(inBlock, outBlock) { + return _updateBlock$1(self._w, inBlock, outBlock, true); + } + } + }); + self._init = false; +}; + +/** + * Initializes this AES algorithm by expanding its key. + * + * @param options the options to use. + * key the key to use with this algorithm. + * decrypt true if the algorithm should be initialized for decryption, + * false for encryption. + */ +forge$z.aes.Algorithm.prototype.initialize = function(options) { + if(this._init) { + return; + } + + var key = options.key; + var tmp; + + /* Note: The key may be a string of bytes, an array of bytes, a byte + buffer, or an array of 32-bit integers. If the key is in bytes, then + it must be 16, 24, or 32 bytes in length. If it is in 32-bit + integers, it must be 4, 6, or 8 integers long. */ + + if(typeof key === 'string' && + (key.length === 16 || key.length === 24 || key.length === 32)) { + // convert key string into byte buffer + key = forge$z.util.createBuffer(key); + } else if(forge$z.util.isArray(key) && + (key.length === 16 || key.length === 24 || key.length === 32)) { + // convert key integer array into byte buffer + tmp = key; + key = forge$z.util.createBuffer(); + for(var i = 0; i < tmp.length; ++i) { + key.putByte(tmp[i]); + } + } + + // convert key byte buffer into 32-bit integer array + if(!forge$z.util.isArray(key)) { + tmp = key; + key = []; + + // key lengths of 16, 24, 32 bytes allowed + var len = tmp.length(); + if(len === 16 || len === 24 || len === 32) { + len = len >>> 2; + for(var i = 0; i < len; ++i) { + key.push(tmp.getInt32()); + } + } + } + + // key must be an array of 32-bit integers by now + if(!forge$z.util.isArray(key) || + !(key.length === 4 || key.length === 6 || key.length === 8)) { + throw new Error('Invalid key parameter.'); + } + + // encryption operation is always used for these modes + var mode = this.mode.name; + var encryptOp = (['CFB', 'OFB', 'CTR', 'GCM'].indexOf(mode) !== -1); + + // do key expansion + this._w = _expandKey(key, options.decrypt && !encryptOp); + this._init = true; +}; + +/** + * Expands a key. Typically only used for testing. + * + * @param key the symmetric key to expand, as an array of 32-bit words. + * @param decrypt true to expand for decryption, false for encryption. + * + * @return the expanded key. + */ +forge$z.aes._expandKey = function(key, decrypt) { + if(!init) { + initialize(); + } + return _expandKey(key, decrypt); +}; + +/** + * Updates a single block. Typically only used for testing. + * + * @param w the expanded key to use. + * @param input an array of block-size 32-bit words. + * @param output an array of block-size 32-bit words. + * @param decrypt true to decrypt, false to encrypt. + */ +forge$z.aes._updateBlock = _updateBlock$1; + +/** Register AES algorithms **/ + +registerAlgorithm$1('AES-ECB', forge$z.cipher.modes.ecb); +registerAlgorithm$1('AES-CBC', forge$z.cipher.modes.cbc); +registerAlgorithm$1('AES-CFB', forge$z.cipher.modes.cfb); +registerAlgorithm$1('AES-OFB', forge$z.cipher.modes.ofb); +registerAlgorithm$1('AES-CTR', forge$z.cipher.modes.ctr); +registerAlgorithm$1('AES-GCM', forge$z.cipher.modes.gcm); + +function registerAlgorithm$1(name, mode) { + var factory = function() { + return new forge$z.aes.Algorithm(name, mode); + }; + forge$z.cipher.registerAlgorithm(name, factory); +} + +/** AES implementation **/ + +var init = false; // not yet initialized +var Nb = 4; // number of words comprising the state (AES = 4) +var sbox; // non-linear substitution table used in key expansion +var isbox; // inversion of sbox +var rcon; // round constant word array +var mix; // mix-columns table +var imix; // inverse mix-columns table + +/** + * Performs initialization, ie: precomputes tables to optimize for speed. + * + * One way to understand how AES works is to imagine that 'addition' and + * 'multiplication' are interfaces that require certain mathematical + * properties to hold true (ie: they are associative) but they might have + * different implementations and produce different kinds of results ... + * provided that their mathematical properties remain true. AES defines + * its own methods of addition and multiplication but keeps some important + * properties the same, ie: associativity and distributivity. The + * explanation below tries to shed some light on how AES defines addition + * and multiplication of bytes and 32-bit words in order to perform its + * encryption and decryption algorithms. + * + * The basics: + * + * The AES algorithm views bytes as binary representations of polynomials + * that have either 1 or 0 as the coefficients. It defines the addition + * or subtraction of two bytes as the XOR operation. It also defines the + * multiplication of two bytes as a finite field referred to as GF(2^8) + * (Note: 'GF' means "Galois Field" which is a field that contains a finite + * number of elements so GF(2^8) has 256 elements). + * + * This means that any two bytes can be represented as binary polynomials; + * when they multiplied together and modularly reduced by an irreducible + * polynomial of the 8th degree, the results are the field GF(2^8). The + * specific irreducible polynomial that AES uses in hexadecimal is 0x11b. + * This multiplication is associative with 0x01 as the identity: + * + * (b * 0x01 = GF(b, 0x01) = b). + * + * The operation GF(b, 0x02) can be performed at the byte level by left + * shifting b once and then XOR'ing it (to perform the modular reduction) + * with 0x11b if b is >= 128. Repeated application of the multiplication + * of 0x02 can be used to implement the multiplication of any two bytes. + * + * For instance, multiplying 0x57 and 0x13, denoted as GF(0x57, 0x13), can + * be performed by factoring 0x13 into 0x01, 0x02, and 0x10. Then these + * factors can each be multiplied by 0x57 and then added together. To do + * the multiplication, values for 0x57 multiplied by each of these 3 factors + * can be precomputed and stored in a table. To add them, the values from + * the table are XOR'd together. + * + * AES also defines addition and multiplication of words, that is 4-byte + * numbers represented as polynomials of 3 degrees where the coefficients + * are the values of the bytes. + * + * The word [a0, a1, a2, a3] is a polynomial a3x^3 + a2x^2 + a1x + a0. + * + * Addition is performed by XOR'ing like powers of x. Multiplication + * is performed in two steps, the first is an algebriac expansion as + * you would do normally (where addition is XOR). But the result is + * a polynomial larger than 3 degrees and thus it cannot fit in a word. So + * next the result is modularly reduced by an AES-specific polynomial of + * degree 4 which will always produce a polynomial of less than 4 degrees + * such that it will fit in a word. In AES, this polynomial is x^4 + 1. + * + * The modular product of two polynomials 'a' and 'b' is thus: + * + * d(x) = d3x^3 + d2x^2 + d1x + d0 + * with + * d0 = GF(a0, b0) ^ GF(a3, b1) ^ GF(a2, b2) ^ GF(a1, b3) + * d1 = GF(a1, b0) ^ GF(a0, b1) ^ GF(a3, b2) ^ GF(a2, b3) + * d2 = GF(a2, b0) ^ GF(a1, b1) ^ GF(a0, b2) ^ GF(a3, b3) + * d3 = GF(a3, b0) ^ GF(a2, b1) ^ GF(a1, b2) ^ GF(a0, b3) + * + * As a matrix: + * + * [d0] = [a0 a3 a2 a1][b0] + * [d1] [a1 a0 a3 a2][b1] + * [d2] [a2 a1 a0 a3][b2] + * [d3] [a3 a2 a1 a0][b3] + * + * Special polynomials defined by AES (0x02 == {02}): + * a(x) = {03}x^3 + {01}x^2 + {01}x + {02} + * a^-1(x) = {0b}x^3 + {0d}x^2 + {09}x + {0e}. + * + * These polynomials are used in the MixColumns() and InverseMixColumns() + * operations, respectively, to cause each element in the state to affect + * the output (referred to as diffusing). + * + * RotWord() uses: a0 = a1 = a2 = {00} and a3 = {01}, which is the + * polynomial x3. + * + * The ShiftRows() method modifies the last 3 rows in the state (where + * the state is 4 words with 4 bytes per word) by shifting bytes cyclically. + * The 1st byte in the second row is moved to the end of the row. The 1st + * and 2nd bytes in the third row are moved to the end of the row. The 1st, + * 2nd, and 3rd bytes are moved in the fourth row. + * + * More details on how AES arithmetic works: + * + * In the polynomial representation of binary numbers, XOR performs addition + * and subtraction and multiplication in GF(2^8) denoted as GF(a, b) + * corresponds with the multiplication of polynomials modulo an irreducible + * polynomial of degree 8. In other words, for AES, GF(a, b) will multiply + * polynomial 'a' with polynomial 'b' and then do a modular reduction by + * an AES-specific irreducible polynomial of degree 8. + * + * A polynomial is irreducible if its only divisors are one and itself. For + * the AES algorithm, this irreducible polynomial is: + * + * m(x) = x^8 + x^4 + x^3 + x + 1, + * + * or {01}{1b} in hexadecimal notation, where each coefficient is a bit: + * 100011011 = 283 = 0x11b. + * + * For example, GF(0x57, 0x83) = 0xc1 because + * + * 0x57 = 87 = 01010111 = x^6 + x^4 + x^2 + x + 1 + * 0x85 = 131 = 10000101 = x^7 + x + 1 + * + * (x^6 + x^4 + x^2 + x + 1) * (x^7 + x + 1) + * = x^13 + x^11 + x^9 + x^8 + x^7 + + * x^7 + x^5 + x^3 + x^2 + x + + * x^6 + x^4 + x^2 + x + 1 + * = x^13 + x^11 + x^9 + x^8 + x^6 + x^5 + x^4 + x^3 + 1 = y + * y modulo (x^8 + x^4 + x^3 + x + 1) + * = x^7 + x^6 + 1. + * + * The modular reduction by m(x) guarantees the result will be a binary + * polynomial of less than degree 8, so that it can fit in a byte. + * + * The operation to multiply a binary polynomial b with x (the polynomial + * x in binary representation is 00000010) is: + * + * b_7x^8 + b_6x^7 + b_5x^6 + b_4x^5 + b_3x^4 + b_2x^3 + b_1x^2 + b_0x^1 + * + * To get GF(b, x) we must reduce that by m(x). If b_7 is 0 (that is the + * most significant bit is 0 in b) then the result is already reduced. If + * it is 1, then we can reduce it by subtracting m(x) via an XOR. + * + * It follows that multiplication by x (00000010 or 0x02) can be implemented + * by performing a left shift followed by a conditional bitwise XOR with + * 0x1b. This operation on bytes is denoted by xtime(). Multiplication by + * higher powers of x can be implemented by repeated application of xtime(). + * + * By adding intermediate results, multiplication by any constant can be + * implemented. For instance: + * + * GF(0x57, 0x13) = 0xfe because: + * + * xtime(b) = (b & 128) ? (b << 1 ^ 0x11b) : (b << 1) + * + * Note: We XOR with 0x11b instead of 0x1b because in javascript our + * datatype for b can be larger than 1 byte, so a left shift will not + * automatically eliminate bits that overflow a byte ... by XOR'ing the + * overflow bit with 1 (the extra one from 0x11b) we zero it out. + * + * GF(0x57, 0x02) = xtime(0x57) = 0xae + * GF(0x57, 0x04) = xtime(0xae) = 0x47 + * GF(0x57, 0x08) = xtime(0x47) = 0x8e + * GF(0x57, 0x10) = xtime(0x8e) = 0x07 + * + * GF(0x57, 0x13) = GF(0x57, (0x01 ^ 0x02 ^ 0x10)) + * + * And by the distributive property (since XOR is addition and GF() is + * multiplication): + * + * = GF(0x57, 0x01) ^ GF(0x57, 0x02) ^ GF(0x57, 0x10) + * = 0x57 ^ 0xae ^ 0x07 + * = 0xfe. + */ +function initialize() { + init = true; + + /* Populate the Rcon table. These are the values given by + [x^(i-1),{00},{00},{00}] where x^(i-1) are powers of x (and x = 0x02) + in the field of GF(2^8), where i starts at 1. + + rcon[0] = [0x00, 0x00, 0x00, 0x00] + rcon[1] = [0x01, 0x00, 0x00, 0x00] 2^(1-1) = 2^0 = 1 + rcon[2] = [0x02, 0x00, 0x00, 0x00] 2^(2-1) = 2^1 = 2 + ... + rcon[9] = [0x1B, 0x00, 0x00, 0x00] 2^(9-1) = 2^8 = 0x1B + rcon[10] = [0x36, 0x00, 0x00, 0x00] 2^(10-1) = 2^9 = 0x36 + + We only store the first byte because it is the only one used. + */ + rcon = [0x00, 0x01, 0x02, 0x04, 0x08, 0x10, 0x20, 0x40, 0x80, 0x1B, 0x36]; + + // compute xtime table which maps i onto GF(i, 0x02) + var xtime = new Array(256); + for(var i = 0; i < 128; ++i) { + xtime[i] = i << 1; + xtime[i + 128] = (i + 128) << 1 ^ 0x11B; + } + + // compute all other tables + sbox = new Array(256); + isbox = new Array(256); + mix = new Array(4); + imix = new Array(4); + for(var i = 0; i < 4; ++i) { + mix[i] = new Array(256); + imix[i] = new Array(256); + } + var e = 0, ei = 0, e2, e4, e8, sx, sx2, me, ime; + for(var i = 0; i < 256; ++i) { + /* We need to generate the SubBytes() sbox and isbox tables so that + we can perform byte substitutions. This requires us to traverse + all of the elements in GF, find their multiplicative inverses, + and apply to each the following affine transformation: + + bi' = bi ^ b(i + 4) mod 8 ^ b(i + 5) mod 8 ^ b(i + 6) mod 8 ^ + b(i + 7) mod 8 ^ ci + for 0 <= i < 8, where bi is the ith bit of the byte, and ci is the + ith bit of a byte c with the value {63} or {01100011}. + + It is possible to traverse every possible value in a Galois field + using what is referred to as a 'generator'. There are many + generators (128 out of 256): 3,5,6,9,11,82 to name a few. To fully + traverse GF we iterate 255 times, multiplying by our generator + each time. + + On each iteration we can determine the multiplicative inverse for + the current element. + + Suppose there is an element in GF 'e'. For a given generator 'g', + e = g^x. The multiplicative inverse of e is g^(255 - x). It turns + out that if use the inverse of a generator as another generator + it will produce all of the corresponding multiplicative inverses + at the same time. For this reason, we choose 5 as our inverse + generator because it only requires 2 multiplies and 1 add and its + inverse, 82, requires relatively few operations as well. + + In order to apply the affine transformation, the multiplicative + inverse 'ei' of 'e' can be repeatedly XOR'd (4 times) with a + bit-cycling of 'ei'. To do this 'ei' is first stored in 's' and + 'x'. Then 's' is left shifted and the high bit of 's' is made the + low bit. The resulting value is stored in 's'. Then 'x' is XOR'd + with 's' and stored in 'x'. On each subsequent iteration the same + operation is performed. When 4 iterations are complete, 'x' is + XOR'd with 'c' (0x63) and the transformed value is stored in 'x'. + For example: + + s = 01000001 + x = 01000001 + + iteration 1: s = 10000010, x ^= s + iteration 2: s = 00000101, x ^= s + iteration 3: s = 00001010, x ^= s + iteration 4: s = 00010100, x ^= s + x ^= 0x63 + + This can be done with a loop where s = (s << 1) | (s >> 7). However, + it can also be done by using a single 16-bit (in this case 32-bit) + number 'sx'. Since XOR is an associative operation, we can set 'sx' + to 'ei' and then XOR it with 'sx' left-shifted 1,2,3, and 4 times. + The most significant bits will flow into the high 8 bit positions + and be correctly XOR'd with one another. All that remains will be + to cycle the high 8 bits by XOR'ing them all with the lower 8 bits + afterwards. + + At the same time we're populating sbox and isbox we can precompute + the multiplication we'll need to do to do MixColumns() later. + */ + + // apply affine transformation + sx = ei ^ (ei << 1) ^ (ei << 2) ^ (ei << 3) ^ (ei << 4); + sx = (sx >> 8) ^ (sx & 255) ^ 0x63; + + // update tables + sbox[e] = sx; + isbox[sx] = e; + + /* Mixing columns is done using matrix multiplication. The columns + that are to be mixed are each a single word in the current state. + The state has Nb columns (4 columns). Therefore each column is a + 4 byte word. So to mix the columns in a single column 'c' where + its rows are r0, r1, r2, and r3, we use the following matrix + multiplication: + + [2 3 1 1]*[r0,c]=[r'0,c] + [1 2 3 1] [r1,c] [r'1,c] + [1 1 2 3] [r2,c] [r'2,c] + [3 1 1 2] [r3,c] [r'3,c] + + r0, r1, r2, and r3 are each 1 byte of one of the words in the + state (a column). To do matrix multiplication for each mixed + column c' we multiply the corresponding row from the left matrix + with the corresponding column from the right matrix. In total, we + get 4 equations: + + r0,c' = 2*r0,c + 3*r1,c + 1*r2,c + 1*r3,c + r1,c' = 1*r0,c + 2*r1,c + 3*r2,c + 1*r3,c + r2,c' = 1*r0,c + 1*r1,c + 2*r2,c + 3*r3,c + r3,c' = 3*r0,c + 1*r1,c + 1*r2,c + 2*r3,c + + As usual, the multiplication is as previously defined and the + addition is XOR. In order to optimize mixing columns we can store + the multiplication results in tables. If you think of the whole + column as a word (it might help to visualize by mentally rotating + the equations above by counterclockwise 90 degrees) then you can + see that it would be useful to map the multiplications performed on + each byte (r0, r1, r2, r3) onto a word as well. For instance, we + could map 2*r0,1*r0,1*r0,3*r0 onto a word by storing 2*r0 in the + highest 8 bits and 3*r0 in the lowest 8 bits (with the other two + respectively in the middle). This means that a table can be + constructed that uses r0 as an index to the word. We can do the + same with r1, r2, and r3, creating a total of 4 tables. + + To construct a full c', we can just look up each byte of c in + their respective tables and XOR the results together. + + Also, to build each table we only have to calculate the word + for 2,1,1,3 for every byte ... which we can do on each iteration + of this loop since we will iterate over every byte. After we have + calculated 2,1,1,3 we can get the results for the other tables + by cycling the byte at the end to the beginning. For instance + we can take the result of table 2,1,1,3 and produce table 3,2,1,1 + by moving the right most byte to the left most position just like + how you can imagine the 3 moved out of 2,1,1,3 and to the front + to produce 3,2,1,1. + + There is another optimization in that the same multiples of + the current element we need in order to advance our generator + to the next iteration can be reused in performing the 2,1,1,3 + calculation. We also calculate the inverse mix column tables, + with e,9,d,b being the inverse of 2,1,1,3. + + When we're done, and we need to actually mix columns, the first + byte of each state word should be put through mix[0] (2,1,1,3), + the second through mix[1] (3,2,1,1) and so forth. Then they should + be XOR'd together to produce the fully mixed column. + */ + + // calculate mix and imix table values + sx2 = xtime[sx]; + e2 = xtime[e]; + e4 = xtime[e2]; + e8 = xtime[e4]; + me = + (sx2 << 24) ^ // 2 + (sx << 16) ^ // 1 + (sx << 8) ^ // 1 + (sx ^ sx2); // 3 + ime = + (e2 ^ e4 ^ e8) << 24 ^ // E (14) + (e ^ e8) << 16 ^ // 9 + (e ^ e4 ^ e8) << 8 ^ // D (13) + (e ^ e2 ^ e8); // B (11) + // produce each of the mix tables by rotating the 2,1,1,3 value + for(var n = 0; n < 4; ++n) { + mix[n][e] = me; + imix[n][sx] = ime; + // cycle the right most byte to the left most position + // ie: 2,1,1,3 becomes 3,2,1,1 + me = me << 24 | me >>> 8; + ime = ime << 24 | ime >>> 8; + } + + // get next element and inverse + if(e === 0) { + // 1 is the inverse of 1 + e = ei = 1; + } else { + // e = 2e + 2*2*2*(10e)) = multiply e by 82 (chosen generator) + // ei = ei + 2*2*ei = multiply ei by 5 (inverse generator) + e = e2 ^ xtime[xtime[xtime[e2 ^ e8]]]; + ei ^= xtime[xtime[ei]]; + } + } +} + +/** + * Generates a key schedule using the AES key expansion algorithm. + * + * The AES algorithm takes the Cipher Key, K, and performs a Key Expansion + * routine to generate a key schedule. The Key Expansion generates a total + * of Nb*(Nr + 1) words: the algorithm requires an initial set of Nb words, + * and each of the Nr rounds requires Nb words of key data. The resulting + * key schedule consists of a linear array of 4-byte words, denoted [wi ], + * with i in the range 0 <= i < Nb(Nr + 1). + * + * KeyExpansion(byte key[4*Nk], word w[Nb*(Nr+1)], Nk) + * AES-128 (Nb=4, Nk=4, Nr=10) + * AES-192 (Nb=4, Nk=6, Nr=12) + * AES-256 (Nb=4, Nk=8, Nr=14) + * Note: Nr=Nk+6. + * + * Nb is the number of columns (32-bit words) comprising the State (or + * number of bytes in a block). For AES, Nb=4. + * + * @param key the key to schedule (as an array of 32-bit words). + * @param decrypt true to modify the key schedule to decrypt, false not to. + * + * @return the generated key schedule. + */ +function _expandKey(key, decrypt) { + // copy the key's words to initialize the key schedule + var w = key.slice(0); + + /* RotWord() will rotate a word, moving the first byte to the last + byte's position (shifting the other bytes left). + + We will be getting the value of Rcon at i / Nk. 'i' will iterate + from Nk to (Nb * Nr+1). Nk = 4 (4 byte key), Nb = 4 (4 words in + a block), Nr = Nk + 6 (10). Therefore 'i' will iterate from + 4 to 44 (exclusive). Each time we iterate 4 times, i / Nk will + increase by 1. We use a counter iNk to keep track of this. + */ + + // go through the rounds expanding the key + var temp, iNk = 1; + var Nk = w.length; + var Nr1 = Nk + 6 + 1; + var end = Nb * Nr1; + for(var i = Nk; i < end; ++i) { + temp = w[i - 1]; + if(i % Nk === 0) { + // temp = SubWord(RotWord(temp)) ^ Rcon[i / Nk] + temp = + sbox[temp >>> 16 & 255] << 24 ^ + sbox[temp >>> 8 & 255] << 16 ^ + sbox[temp & 255] << 8 ^ + sbox[temp >>> 24] ^ (rcon[iNk] << 24); + iNk++; + } else if(Nk > 6 && (i % Nk === 4)) { + // temp = SubWord(temp) + temp = + sbox[temp >>> 24] << 24 ^ + sbox[temp >>> 16 & 255] << 16 ^ + sbox[temp >>> 8 & 255] << 8 ^ + sbox[temp & 255]; + } + w[i] = w[i - Nk] ^ temp; + } + + /* When we are updating a cipher block we always use the code path for + encryption whether we are decrypting or not (to shorten code and + simplify the generation of look up tables). However, because there + are differences in the decryption algorithm, other than just swapping + in different look up tables, we must transform our key schedule to + account for these changes: + + 1. The decryption algorithm gets its key rounds in reverse order. + 2. The decryption algorithm adds the round key before mixing columns + instead of afterwards. + + We don't need to modify our key schedule to handle the first case, + we can just traverse the key schedule in reverse order when decrypting. + + The second case requires a little work. + + The tables we built for performing rounds will take an input and then + perform SubBytes() and MixColumns() or, for the decrypt version, + InvSubBytes() and InvMixColumns(). But the decrypt algorithm requires + us to AddRoundKey() before InvMixColumns(). This means we'll need to + apply some transformations to the round key to inverse-mix its columns + so they'll be correct for moving AddRoundKey() to after the state has + had its columns inverse-mixed. + + To inverse-mix the columns of the state when we're decrypting we use a + lookup table that will apply InvSubBytes() and InvMixColumns() at the + same time. However, the round key's bytes are not inverse-substituted + in the decryption algorithm. To get around this problem, we can first + substitute the bytes in the round key so that when we apply the + transformation via the InvSubBytes()+InvMixColumns() table, it will + undo our substitution leaving us with the original value that we + want -- and then inverse-mix that value. + + This change will correctly alter our key schedule so that we can XOR + each round key with our already transformed decryption state. This + allows us to use the same code path as the encryption algorithm. + + We make one more change to the decryption key. Since the decryption + algorithm runs in reverse from the encryption algorithm, we reverse + the order of the round keys to avoid having to iterate over the key + schedule backwards when running the encryption algorithm later in + decryption mode. In addition to reversing the order of the round keys, + we also swap each round key's 2nd and 4th rows. See the comments + section where rounds are performed for more details about why this is + done. These changes are done inline with the other substitution + described above. + */ + if(decrypt) { + var tmp; + var m0 = imix[0]; + var m1 = imix[1]; + var m2 = imix[2]; + var m3 = imix[3]; + var wnew = w.slice(0); + end = w.length; + for(var i = 0, wi = end - Nb; i < end; i += Nb, wi -= Nb) { + // do not sub the first or last round key (round keys are Nb + // words) as no column mixing is performed before they are added, + // but do change the key order + if(i === 0 || i === (end - Nb)) { + wnew[i] = w[wi]; + wnew[i + 1] = w[wi + 3]; + wnew[i + 2] = w[wi + 2]; + wnew[i + 3] = w[wi + 1]; + } else { + // substitute each round key byte because the inverse-mix + // table will inverse-substitute it (effectively cancel the + // substitution because round key bytes aren't sub'd in + // decryption mode) and swap indexes 3 and 1 + for(var n = 0; n < Nb; ++n) { + tmp = w[wi + n]; + wnew[i + (3&-n)] = + m0[sbox[tmp >>> 24]] ^ + m1[sbox[tmp >>> 16 & 255]] ^ + m2[sbox[tmp >>> 8 & 255]] ^ + m3[sbox[tmp & 255]]; + } + } + } + w = wnew; + } + + return w; +} + +/** + * Updates a single block (16 bytes) using AES. The update will either + * encrypt or decrypt the block. + * + * @param w the key schedule. + * @param input the input block (an array of 32-bit words). + * @param output the updated output block. + * @param decrypt true to decrypt the block, false to encrypt it. + */ +function _updateBlock$1(w, input, output, decrypt) { + /* + Cipher(byte in[4*Nb], byte out[4*Nb], word w[Nb*(Nr+1)]) + begin + byte state[4,Nb] + state = in + AddRoundKey(state, w[0, Nb-1]) + for round = 1 step 1 to Nr-1 + SubBytes(state) + ShiftRows(state) + MixColumns(state) + AddRoundKey(state, w[round*Nb, (round+1)*Nb-1]) + end for + SubBytes(state) + ShiftRows(state) + AddRoundKey(state, w[Nr*Nb, (Nr+1)*Nb-1]) + out = state + end + + InvCipher(byte in[4*Nb], byte out[4*Nb], word w[Nb*(Nr+1)]) + begin + byte state[4,Nb] + state = in + AddRoundKey(state, w[Nr*Nb, (Nr+1)*Nb-1]) + for round = Nr-1 step -1 downto 1 + InvShiftRows(state) + InvSubBytes(state) + AddRoundKey(state, w[round*Nb, (round+1)*Nb-1]) + InvMixColumns(state) + end for + InvShiftRows(state) + InvSubBytes(state) + AddRoundKey(state, w[0, Nb-1]) + out = state + end + */ + + // Encrypt: AddRoundKey(state, w[0, Nb-1]) + // Decrypt: AddRoundKey(state, w[Nr*Nb, (Nr+1)*Nb-1]) + var Nr = w.length / 4 - 1; + var m0, m1, m2, m3, sub; + if(decrypt) { + m0 = imix[0]; + m1 = imix[1]; + m2 = imix[2]; + m3 = imix[3]; + sub = isbox; + } else { + m0 = mix[0]; + m1 = mix[1]; + m2 = mix[2]; + m3 = mix[3]; + sub = sbox; + } + var a, b, c, d, a2, b2, c2; + a = input[0] ^ w[0]; + b = input[decrypt ? 3 : 1] ^ w[1]; + c = input[2] ^ w[2]; + d = input[decrypt ? 1 : 3] ^ w[3]; + var i = 3; + + /* In order to share code we follow the encryption algorithm when both + encrypting and decrypting. To account for the changes required in the + decryption algorithm, we use different lookup tables when decrypting + and use a modified key schedule to account for the difference in the + order of transformations applied when performing rounds. We also get + key rounds in reverse order (relative to encryption). */ + for(var round = 1; round < Nr; ++round) { + /* As described above, we'll be using table lookups to perform the + column mixing. Each column is stored as a word in the state (the + array 'input' has one column as a word at each index). In order to + mix a column, we perform these transformations on each row in c, + which is 1 byte in each word. The new column for c0 is c'0: + + m0 m1 m2 m3 + r0,c'0 = 2*r0,c0 + 3*r1,c0 + 1*r2,c0 + 1*r3,c0 + r1,c'0 = 1*r0,c0 + 2*r1,c0 + 3*r2,c0 + 1*r3,c0 + r2,c'0 = 1*r0,c0 + 1*r1,c0 + 2*r2,c0 + 3*r3,c0 + r3,c'0 = 3*r0,c0 + 1*r1,c0 + 1*r2,c0 + 2*r3,c0 + + So using mix tables where c0 is a word with r0 being its upper + 8 bits and r3 being its lower 8 bits: + + m0[c0 >> 24] will yield this word: [2*r0,1*r0,1*r0,3*r0] + ... + m3[c0 & 255] will yield this word: [1*r3,1*r3,3*r3,2*r3] + + Therefore to mix the columns in each word in the state we + do the following (& 255 omitted for brevity): + c'0,r0 = m0[c0 >> 24] ^ m1[c1 >> 16] ^ m2[c2 >> 8] ^ m3[c3] + c'0,r1 = m0[c0 >> 24] ^ m1[c1 >> 16] ^ m2[c2 >> 8] ^ m3[c3] + c'0,r2 = m0[c0 >> 24] ^ m1[c1 >> 16] ^ m2[c2 >> 8] ^ m3[c3] + c'0,r3 = m0[c0 >> 24] ^ m1[c1 >> 16] ^ m2[c2 >> 8] ^ m3[c3] + + However, before mixing, the algorithm requires us to perform + ShiftRows(). The ShiftRows() transformation cyclically shifts the + last 3 rows of the state over different offsets. The first row + (r = 0) is not shifted. + + s'_r,c = s_r,(c + shift(r, Nb) mod Nb + for 0 < r < 4 and 0 <= c < Nb and + shift(1, 4) = 1 + shift(2, 4) = 2 + shift(3, 4) = 3. + + This causes the first byte in r = 1 to be moved to the end of + the row, the first 2 bytes in r = 2 to be moved to the end of + the row, the first 3 bytes in r = 3 to be moved to the end of + the row: + + r1: [c0 c1 c2 c3] => [c1 c2 c3 c0] + r2: [c0 c1 c2 c3] [c2 c3 c0 c1] + r3: [c0 c1 c2 c3] [c3 c0 c1 c2] + + We can make these substitutions inline with our column mixing to + generate an updated set of equations to produce each word in the + state (note the columns have changed positions): + + c0 c1 c2 c3 => c0 c1 c2 c3 + c0 c1 c2 c3 c1 c2 c3 c0 (cycled 1 byte) + c0 c1 c2 c3 c2 c3 c0 c1 (cycled 2 bytes) + c0 c1 c2 c3 c3 c0 c1 c2 (cycled 3 bytes) + + Therefore: + + c'0 = 2*r0,c0 + 3*r1,c1 + 1*r2,c2 + 1*r3,c3 + c'0 = 1*r0,c0 + 2*r1,c1 + 3*r2,c2 + 1*r3,c3 + c'0 = 1*r0,c0 + 1*r1,c1 + 2*r2,c2 + 3*r3,c3 + c'0 = 3*r0,c0 + 1*r1,c1 + 1*r2,c2 + 2*r3,c3 + + c'1 = 2*r0,c1 + 3*r1,c2 + 1*r2,c3 + 1*r3,c0 + c'1 = 1*r0,c1 + 2*r1,c2 + 3*r2,c3 + 1*r3,c0 + c'1 = 1*r0,c1 + 1*r1,c2 + 2*r2,c3 + 3*r3,c0 + c'1 = 3*r0,c1 + 1*r1,c2 + 1*r2,c3 + 2*r3,c0 + + ... and so forth for c'2 and c'3. The important distinction is + that the columns are cycling, with c0 being used with the m0 + map when calculating c0, but c1 being used with the m0 map when + calculating c1 ... and so forth. + + When performing the inverse we transform the mirror image and + skip the bottom row, instead of the top one, and move upwards: + + c3 c2 c1 c0 => c0 c3 c2 c1 (cycled 3 bytes) *same as encryption + c3 c2 c1 c0 c1 c0 c3 c2 (cycled 2 bytes) + c3 c2 c1 c0 c2 c1 c0 c3 (cycled 1 byte) *same as encryption + c3 c2 c1 c0 c3 c2 c1 c0 + + If you compare the resulting matrices for ShiftRows()+MixColumns() + and for InvShiftRows()+InvMixColumns() the 2nd and 4th columns are + different (in encrypt mode vs. decrypt mode). So in order to use + the same code to handle both encryption and decryption, we will + need to do some mapping. + + If in encryption mode we let a=c0, b=c1, c=c2, d=c3, and r be + a row number in the state, then the resulting matrix in encryption + mode for applying the above transformations would be: + + r1: a b c d + r2: b c d a + r3: c d a b + r4: d a b c + + If we did the same in decryption mode we would get: + + r1: a d c b + r2: b a d c + r3: c b a d + r4: d c b a + + If instead we swap d and b (set b=c3 and d=c1), then we get: + + r1: a b c d + r2: d a b c + r3: c d a b + r4: b c d a + + Now the 1st and 3rd rows are the same as the encryption matrix. All + we need to do then to make the mapping exactly the same is to swap + the 2nd and 4th rows when in decryption mode. To do this without + having to do it on each iteration, we swapped the 2nd and 4th rows + in the decryption key schedule. We also have to do the swap above + when we first pull in the input and when we set the final output. */ + a2 = + m0[a >>> 24] ^ + m1[b >>> 16 & 255] ^ + m2[c >>> 8 & 255] ^ + m3[d & 255] ^ w[++i]; + b2 = + m0[b >>> 24] ^ + m1[c >>> 16 & 255] ^ + m2[d >>> 8 & 255] ^ + m3[a & 255] ^ w[++i]; + c2 = + m0[c >>> 24] ^ + m1[d >>> 16 & 255] ^ + m2[a >>> 8 & 255] ^ + m3[b & 255] ^ w[++i]; + d = + m0[d >>> 24] ^ + m1[a >>> 16 & 255] ^ + m2[b >>> 8 & 255] ^ + m3[c & 255] ^ w[++i]; + a = a2; + b = b2; + c = c2; + } + + /* + Encrypt: + SubBytes(state) + ShiftRows(state) + AddRoundKey(state, w[Nr*Nb, (Nr+1)*Nb-1]) + + Decrypt: + InvShiftRows(state) + InvSubBytes(state) + AddRoundKey(state, w[0, Nb-1]) + */ + // Note: rows are shifted inline + output[0] = + (sub[a >>> 24] << 24) ^ + (sub[b >>> 16 & 255] << 16) ^ + (sub[c >>> 8 & 255] << 8) ^ + (sub[d & 255]) ^ w[++i]; + output[decrypt ? 3 : 1] = + (sub[b >>> 24] << 24) ^ + (sub[c >>> 16 & 255] << 16) ^ + (sub[d >>> 8 & 255] << 8) ^ + (sub[a & 255]) ^ w[++i]; + output[2] = + (sub[c >>> 24] << 24) ^ + (sub[d >>> 16 & 255] << 16) ^ + (sub[a >>> 8 & 255] << 8) ^ + (sub[b & 255]) ^ w[++i]; + output[decrypt ? 1 : 3] = + (sub[d >>> 24] << 24) ^ + (sub[a >>> 16 & 255] << 16) ^ + (sub[b >>> 8 & 255] << 8) ^ + (sub[c & 255]) ^ w[++i]; +} + +/** + * Deprecated. Instead, use: + * + * forge.cipher.createCipher('AES-', key); + * forge.cipher.createDecipher('AES-', key); + * + * Creates a deprecated AES cipher object. This object's mode will default to + * CBC (cipher-block-chaining). + * + * The key and iv may be given as a string of bytes, an array of bytes, a + * byte buffer, or an array of 32-bit words. + * + * @param options the options to use. + * key the symmetric key to use. + * output the buffer to write to. + * decrypt true for decryption, false for encryption. + * mode the cipher mode to use (default: 'CBC'). + * + * @return the cipher. + */ +function _createCipher$1(options) { + options = options || {}; + var mode = (options.mode || 'CBC').toUpperCase(); + var algorithm = 'AES-' + mode; + + var cipher; + if(options.decrypt) { + cipher = forge$z.cipher.createDecipher(algorithm, options.key); + } else { + cipher = forge$z.cipher.createCipher(algorithm, options.key); + } + + // backwards compatible start API + var start = cipher.start; + cipher.start = function(iv, options) { + // backwards compatibility: support second arg as output buffer + var output = null; + if(options instanceof forge$z.util.ByteBuffer) { + output = options; + options = {}; + } + options = options || {}; + options.output = output; + options.iv = iv; + start.call(cipher, options); + }; + + return cipher; +} + +/** + * Object IDs for ASN.1. + * + * @author Dave Longley + * + * Copyright (c) 2010-2013 Digital Bazaar, Inc. + */ + +var forge$y = forge$D; + +forge$y.pki = forge$y.pki || {}; +var oids$2 = forge$y.pki.oids = forge$y.oids = forge$y.oids || {}; + +// set id to name mapping and name to id mapping +function _IN(id, name) { + oids$2[id] = name; + oids$2[name] = id; +} +// set id to name mapping only +function _I_(id, name) { + oids$2[id] = name; +} + +// algorithm OIDs +_IN('1.2.840.113549.1.1.1', 'rsaEncryption'); +// Note: md2 & md4 not implemented +//_IN('1.2.840.113549.1.1.2', 'md2WithRSAEncryption'); +//_IN('1.2.840.113549.1.1.3', 'md4WithRSAEncryption'); +_IN('1.2.840.113549.1.1.4', 'md5WithRSAEncryption'); +_IN('1.2.840.113549.1.1.5', 'sha1WithRSAEncryption'); +_IN('1.2.840.113549.1.1.7', 'RSAES-OAEP'); +_IN('1.2.840.113549.1.1.8', 'mgf1'); +_IN('1.2.840.113549.1.1.9', 'pSpecified'); +_IN('1.2.840.113549.1.1.10', 'RSASSA-PSS'); +_IN('1.2.840.113549.1.1.11', 'sha256WithRSAEncryption'); +_IN('1.2.840.113549.1.1.12', 'sha384WithRSAEncryption'); +_IN('1.2.840.113549.1.1.13', 'sha512WithRSAEncryption'); +// Edwards-curve Digital Signature Algorithm (EdDSA) Ed25519 +_IN('1.3.101.112', 'EdDSA25519'); + +_IN('1.2.840.10040.4.3', 'dsa-with-sha1'); + +_IN('1.3.14.3.2.7', 'desCBC'); + +_IN('1.3.14.3.2.26', 'sha1'); +// Deprecated equivalent of sha1WithRSAEncryption +_IN('1.3.14.3.2.29', 'sha1WithRSASignature'); +_IN('2.16.840.1.101.3.4.2.1', 'sha256'); +_IN('2.16.840.1.101.3.4.2.2', 'sha384'); +_IN('2.16.840.1.101.3.4.2.3', 'sha512'); +_IN('2.16.840.1.101.3.4.2.4', 'sha224'); +_IN('2.16.840.1.101.3.4.2.5', 'sha512-224'); +_IN('2.16.840.1.101.3.4.2.6', 'sha512-256'); +_IN('1.2.840.113549.2.2', 'md2'); +_IN('1.2.840.113549.2.5', 'md5'); + +// pkcs#7 content types +_IN('1.2.840.113549.1.7.1', 'data'); +_IN('1.2.840.113549.1.7.2', 'signedData'); +_IN('1.2.840.113549.1.7.3', 'envelopedData'); +_IN('1.2.840.113549.1.7.4', 'signedAndEnvelopedData'); +_IN('1.2.840.113549.1.7.5', 'digestedData'); +_IN('1.2.840.113549.1.7.6', 'encryptedData'); + +// pkcs#9 oids +_IN('1.2.840.113549.1.9.1', 'emailAddress'); +_IN('1.2.840.113549.1.9.2', 'unstructuredName'); +_IN('1.2.840.113549.1.9.3', 'contentType'); +_IN('1.2.840.113549.1.9.4', 'messageDigest'); +_IN('1.2.840.113549.1.9.5', 'signingTime'); +_IN('1.2.840.113549.1.9.6', 'counterSignature'); +_IN('1.2.840.113549.1.9.7', 'challengePassword'); +_IN('1.2.840.113549.1.9.8', 'unstructuredAddress'); +_IN('1.2.840.113549.1.9.14', 'extensionRequest'); + +_IN('1.2.840.113549.1.9.20', 'friendlyName'); +_IN('1.2.840.113549.1.9.21', 'localKeyId'); +_IN('1.2.840.113549.1.9.22.1', 'x509Certificate'); + +// pkcs#12 safe bags +_IN('1.2.840.113549.1.12.10.1.1', 'keyBag'); +_IN('1.2.840.113549.1.12.10.1.2', 'pkcs8ShroudedKeyBag'); +_IN('1.2.840.113549.1.12.10.1.3', 'certBag'); +_IN('1.2.840.113549.1.12.10.1.4', 'crlBag'); +_IN('1.2.840.113549.1.12.10.1.5', 'secretBag'); +_IN('1.2.840.113549.1.12.10.1.6', 'safeContentsBag'); + +// password-based-encryption for pkcs#12 +_IN('1.2.840.113549.1.5.13', 'pkcs5PBES2'); +_IN('1.2.840.113549.1.5.12', 'pkcs5PBKDF2'); + +_IN('1.2.840.113549.1.12.1.1', 'pbeWithSHAAnd128BitRC4'); +_IN('1.2.840.113549.1.12.1.2', 'pbeWithSHAAnd40BitRC4'); +_IN('1.2.840.113549.1.12.1.3', 'pbeWithSHAAnd3-KeyTripleDES-CBC'); +_IN('1.2.840.113549.1.12.1.4', 'pbeWithSHAAnd2-KeyTripleDES-CBC'); +_IN('1.2.840.113549.1.12.1.5', 'pbeWithSHAAnd128BitRC2-CBC'); +_IN('1.2.840.113549.1.12.1.6', 'pbewithSHAAnd40BitRC2-CBC'); + +// hmac OIDs +_IN('1.2.840.113549.2.7', 'hmacWithSHA1'); +_IN('1.2.840.113549.2.8', 'hmacWithSHA224'); +_IN('1.2.840.113549.2.9', 'hmacWithSHA256'); +_IN('1.2.840.113549.2.10', 'hmacWithSHA384'); +_IN('1.2.840.113549.2.11', 'hmacWithSHA512'); + +// symmetric key algorithm oids +_IN('1.2.840.113549.3.7', 'des-EDE3-CBC'); +_IN('2.16.840.1.101.3.4.1.2', 'aes128-CBC'); +_IN('2.16.840.1.101.3.4.1.22', 'aes192-CBC'); +_IN('2.16.840.1.101.3.4.1.42', 'aes256-CBC'); + +// certificate issuer/subject OIDs +_IN('2.5.4.3', 'commonName'); +_IN('2.5.4.4', 'surname'); +_IN('2.5.4.5', 'serialNumber'); +_IN('2.5.4.6', 'countryName'); +_IN('2.5.4.7', 'localityName'); +_IN('2.5.4.8', 'stateOrProvinceName'); +_IN('2.5.4.9', 'streetAddress'); +_IN('2.5.4.10', 'organizationName'); +_IN('2.5.4.11', 'organizationalUnitName'); +_IN('2.5.4.12', 'title'); +_IN('2.5.4.13', 'description'); +_IN('2.5.4.15', 'businessCategory'); +_IN('2.5.4.17', 'postalCode'); +_IN('2.5.4.42', 'givenName'); +_IN('1.3.6.1.4.1.311.60.2.1.2', 'jurisdictionOfIncorporationStateOrProvinceName'); +_IN('1.3.6.1.4.1.311.60.2.1.3', 'jurisdictionOfIncorporationCountryName'); + +// X.509 extension OIDs +_IN('2.16.840.1.113730.1.1', 'nsCertType'); +_IN('2.16.840.1.113730.1.13', 'nsComment'); // deprecated in theory; still widely used +_I_('2.5.29.1', 'authorityKeyIdentifier'); // deprecated, use .35 +_I_('2.5.29.2', 'keyAttributes'); // obsolete use .37 or .15 +_I_('2.5.29.3', 'certificatePolicies'); // deprecated, use .32 +_I_('2.5.29.4', 'keyUsageRestriction'); // obsolete use .37 or .15 +_I_('2.5.29.5', 'policyMapping'); // deprecated use .33 +_I_('2.5.29.6', 'subtreesConstraint'); // obsolete use .30 +_I_('2.5.29.7', 'subjectAltName'); // deprecated use .17 +_I_('2.5.29.8', 'issuerAltName'); // deprecated use .18 +_I_('2.5.29.9', 'subjectDirectoryAttributes'); +_I_('2.5.29.10', 'basicConstraints'); // deprecated use .19 +_I_('2.5.29.11', 'nameConstraints'); // deprecated use .30 +_I_('2.5.29.12', 'policyConstraints'); // deprecated use .36 +_I_('2.5.29.13', 'basicConstraints'); // deprecated use .19 +_IN('2.5.29.14', 'subjectKeyIdentifier'); +_IN('2.5.29.15', 'keyUsage'); +_I_('2.5.29.16', 'privateKeyUsagePeriod'); +_IN('2.5.29.17', 'subjectAltName'); +_IN('2.5.29.18', 'issuerAltName'); +_IN('2.5.29.19', 'basicConstraints'); +_I_('2.5.29.20', 'cRLNumber'); +_I_('2.5.29.21', 'cRLReason'); +_I_('2.5.29.22', 'expirationDate'); +_I_('2.5.29.23', 'instructionCode'); +_I_('2.5.29.24', 'invalidityDate'); +_I_('2.5.29.25', 'cRLDistributionPoints'); // deprecated use .31 +_I_('2.5.29.26', 'issuingDistributionPoint'); // deprecated use .28 +_I_('2.5.29.27', 'deltaCRLIndicator'); +_I_('2.5.29.28', 'issuingDistributionPoint'); +_I_('2.5.29.29', 'certificateIssuer'); +_I_('2.5.29.30', 'nameConstraints'); +_IN('2.5.29.31', 'cRLDistributionPoints'); +_IN('2.5.29.32', 'certificatePolicies'); +_I_('2.5.29.33', 'policyMappings'); +_I_('2.5.29.34', 'policyConstraints'); // deprecated use .36 +_IN('2.5.29.35', 'authorityKeyIdentifier'); +_I_('2.5.29.36', 'policyConstraints'); +_IN('2.5.29.37', 'extKeyUsage'); +_I_('2.5.29.46', 'freshestCRL'); +_I_('2.5.29.54', 'inhibitAnyPolicy'); + +// extKeyUsage purposes +_IN('1.3.6.1.4.1.11129.2.4.2', 'timestampList'); +_IN('1.3.6.1.5.5.7.1.1', 'authorityInfoAccess'); +_IN('1.3.6.1.5.5.7.3.1', 'serverAuth'); +_IN('1.3.6.1.5.5.7.3.2', 'clientAuth'); +_IN('1.3.6.1.5.5.7.3.3', 'codeSigning'); +_IN('1.3.6.1.5.5.7.3.4', 'emailProtection'); +_IN('1.3.6.1.5.5.7.3.8', 'timeStamping'); + +/** + * Javascript implementation of Abstract Syntax Notation Number One. + * + * @author Dave Longley + * + * Copyright (c) 2010-2015 Digital Bazaar, Inc. + * + * An API for storing data using the Abstract Syntax Notation Number One + * format using DER (Distinguished Encoding Rules) encoding. This encoding is + * commonly used to store data for PKI, i.e. X.509 Certificates, and this + * implementation exists for that purpose. + * + * Abstract Syntax Notation Number One (ASN.1) is used to define the abstract + * syntax of information without restricting the way the information is encoded + * for transmission. It provides a standard that allows for open systems + * communication. ASN.1 defines the syntax of information data and a number of + * simple data types as well as a notation for describing them and specifying + * values for them. + * + * The RSA algorithm creates public and private keys that are often stored in + * X.509 or PKCS#X formats -- which use ASN.1 (encoded in DER format). This + * class provides the most basic functionality required to store and load DSA + * keys that are encoded according to ASN.1. + * + * The most common binary encodings for ASN.1 are BER (Basic Encoding Rules) + * and DER (Distinguished Encoding Rules). DER is just a subset of BER that + * has stricter requirements for how data must be encoded. + * + * Each ASN.1 structure has a tag (a byte identifying the ASN.1 structure type) + * and a byte array for the value of this ASN1 structure which may be data or a + * list of ASN.1 structures. + * + * Each ASN.1 structure using BER is (Tag-Length-Value): + * + * | byte 0 | bytes X | bytes Y | + * |--------|---------|---------- + * | tag | length | value | + * + * ASN.1 allows for tags to be of "High-tag-number form" which allows a tag to + * be two or more octets, but that is not supported by this class. A tag is + * only 1 byte. Bits 1-5 give the tag number (ie the data type within a + * particular 'class'), 6 indicates whether or not the ASN.1 value is + * constructed from other ASN.1 values, and bits 7 and 8 give the 'class'. If + * bits 7 and 8 are both zero, the class is UNIVERSAL. If only bit 7 is set, + * then the class is APPLICATION. If only bit 8 is set, then the class is + * CONTEXT_SPECIFIC. If both bits 7 and 8 are set, then the class is PRIVATE. + * The tag numbers for the data types for the class UNIVERSAL are listed below: + * + * UNIVERSAL 0 Reserved for use by the encoding rules + * UNIVERSAL 1 Boolean type + * UNIVERSAL 2 Integer type + * UNIVERSAL 3 Bitstring type + * UNIVERSAL 4 Octetstring type + * UNIVERSAL 5 Null type + * UNIVERSAL 6 Object identifier type + * UNIVERSAL 7 Object descriptor type + * UNIVERSAL 8 External type and Instance-of type + * UNIVERSAL 9 Real type + * UNIVERSAL 10 Enumerated type + * UNIVERSAL 11 Embedded-pdv type + * UNIVERSAL 12 UTF8String type + * UNIVERSAL 13 Relative object identifier type + * UNIVERSAL 14-15 Reserved for future editions + * UNIVERSAL 16 Sequence and Sequence-of types + * UNIVERSAL 17 Set and Set-of types + * UNIVERSAL 18-22, 25-30 Character string types + * UNIVERSAL 23-24 Time types + * + * The length of an ASN.1 structure is specified after the tag identifier. + * There is a definite form and an indefinite form. The indefinite form may + * be used if the encoding is constructed and not all immediately available. + * The indefinite form is encoded using a length byte with only the 8th bit + * set. The end of the constructed object is marked using end-of-contents + * octets (two zero bytes). + * + * The definite form looks like this: + * + * The length may take up 1 or more bytes, it depends on the length of the + * value of the ASN.1 structure. DER encoding requires that if the ASN.1 + * structure has a value that has a length greater than 127, more than 1 byte + * will be used to store its length, otherwise just one byte will be used. + * This is strict. + * + * In the case that the length of the ASN.1 value is less than 127, 1 octet + * (byte) is used to store the "short form" length. The 8th bit has a value of + * 0 indicating the length is "short form" and not "long form" and bits 7-1 + * give the length of the data. (The 8th bit is the left-most, most significant + * bit: also known as big endian or network format). + * + * In the case that the length of the ASN.1 value is greater than 127, 2 to + * 127 octets (bytes) are used to store the "long form" length. The first + * byte's 8th bit is set to 1 to indicate the length is "long form." Bits 7-1 + * give the number of additional octets. All following octets are in base 256 + * with the most significant digit first (typical big-endian binary unsigned + * integer storage). So, for instance, if the length of a value was 257, the + * first byte would be set to: + * + * 10000010 = 130 = 0x82. + * + * This indicates there are 2 octets (base 256) for the length. The second and + * third bytes (the octets just mentioned) would store the length in base 256: + * + * octet 2: 00000001 = 1 * 256^1 = 256 + * octet 3: 00000001 = 1 * 256^0 = 1 + * total = 257 + * + * The algorithm for converting a js integer value of 257 to base-256 is: + * + * var value = 257; + * var bytes = []; + * bytes[0] = (value >>> 8) & 0xFF; // most significant byte first + * bytes[1] = value & 0xFF; // least significant byte last + * + * On the ASN.1 UNIVERSAL Object Identifier (OID) type: + * + * An OID can be written like: "value1.value2.value3...valueN" + * + * The DER encoding rules: + * + * The first byte has the value 40 * value1 + value2. + * The following bytes, if any, encode the remaining values. Each value is + * encoded in base 128, most significant digit first (big endian), with as + * few digits as possible, and the most significant bit of each byte set + * to 1 except the last in each value's encoding. For example: Given the + * OID "1.2.840.113549", its DER encoding is (remember each byte except the + * last one in each encoding is OR'd with 0x80): + * + * byte 1: 40 * 1 + 2 = 42 = 0x2A. + * bytes 2-3: 128 * 6 + 72 = 840 = 6 72 = 6 72 = 0x0648 = 0x8648 + * bytes 4-6: 16384 * 6 + 128 * 119 + 13 = 6 119 13 = 0x06770D = 0x86F70D + * + * The final value is: 0x2A864886F70D. + * The full OID (including ASN.1 tag and length of 6 bytes) is: + * 0x06062A864886F70D + */ + +var forge$x = forge$D; + + + +/* ASN.1 API */ +var asn1$8 = forge$x.asn1 = forge$x.asn1 || {}; + +/** + * ASN.1 classes. + */ +asn1$8.Class = { + UNIVERSAL: 0x00, + APPLICATION: 0x40, + CONTEXT_SPECIFIC: 0x80, + PRIVATE: 0xC0 +}; + +/** + * ASN.1 types. Not all types are supported by this implementation, only + * those necessary to implement a simple PKI are implemented. + */ +asn1$8.Type = { + NONE: 0, + BOOLEAN: 1, + INTEGER: 2, + BITSTRING: 3, + OCTETSTRING: 4, + NULL: 5, + OID: 6, + ODESC: 7, + EXTERNAL: 8, + REAL: 9, + ENUMERATED: 10, + EMBEDDED: 11, + UTF8: 12, + ROID: 13, + SEQUENCE: 16, + SET: 17, + PRINTABLESTRING: 19, + IA5STRING: 22, + UTCTIME: 23, + GENERALIZEDTIME: 24, + BMPSTRING: 30 +}; + +/** + * Creates a new asn1 object. + * + * @param tagClass the tag class for the object. + * @param type the data type (tag number) for the object. + * @param constructed true if the asn1 object is in constructed form. + * @param value the value for the object, if it is not constructed. + * @param [options] the options to use: + * [bitStringContents] the plain BIT STRING content including padding + * byte. + * + * @return the asn1 object. + */ +asn1$8.create = function(tagClass, type, constructed, value, options) { + /* An asn1 object has a tagClass, a type, a constructed flag, and a + value. The value's type depends on the constructed flag. If + constructed, it will contain a list of other asn1 objects. If not, + it will contain the ASN.1 value as an array of bytes formatted + according to the ASN.1 data type. */ + + // remove undefined values + if(forge$x.util.isArray(value)) { + var tmp = []; + for(var i = 0; i < value.length; ++i) { + if(value[i] !== undefined) { + tmp.push(value[i]); + } + } + value = tmp; + } + + var obj = { + tagClass: tagClass, + type: type, + constructed: constructed, + composed: constructed || forge$x.util.isArray(value), + value: value + }; + if(options && 'bitStringContents' in options) { + // TODO: copy byte buffer if it's a buffer not a string + obj.bitStringContents = options.bitStringContents; + // TODO: add readonly flag to avoid this overhead + // save copy to detect changes + obj.original = asn1$8.copy(obj); + } + return obj; +}; + +/** + * Copies an asn1 object. + * + * @param obj the asn1 object. + * @param [options] copy options: + * [excludeBitStringContents] true to not copy bitStringContents + * + * @return the a copy of the asn1 object. + */ +asn1$8.copy = function(obj, options) { + var copy; + + if(forge$x.util.isArray(obj)) { + copy = []; + for(var i = 0; i < obj.length; ++i) { + copy.push(asn1$8.copy(obj[i], options)); + } + return copy; + } + + if(typeof obj === 'string') { + // TODO: copy byte buffer if it's a buffer not a string + return obj; + } + + copy = { + tagClass: obj.tagClass, + type: obj.type, + constructed: obj.constructed, + composed: obj.composed, + value: asn1$8.copy(obj.value, options) + }; + if(options && !options.excludeBitStringContents) { + // TODO: copy byte buffer if it's a buffer not a string + copy.bitStringContents = obj.bitStringContents; + } + return copy; +}; + +/** + * Compares asn1 objects for equality. + * + * Note this function does not run in constant time. + * + * @param obj1 the first asn1 object. + * @param obj2 the second asn1 object. + * @param [options] compare options: + * [includeBitStringContents] true to compare bitStringContents + * + * @return true if the asn1 objects are equal. + */ +asn1$8.equals = function(obj1, obj2, options) { + if(forge$x.util.isArray(obj1)) { + if(!forge$x.util.isArray(obj2)) { + return false; + } + if(obj1.length !== obj2.length) { + return false; + } + for(var i = 0; i < obj1.length; ++i) { + if(!asn1$8.equals(obj1[i], obj2[i])) { + return false; + } + } + return true; + } + + if(typeof obj1 !== typeof obj2) { + return false; + } + + if(typeof obj1 === 'string') { + return obj1 === obj2; + } + + var equal = obj1.tagClass === obj2.tagClass && + obj1.type === obj2.type && + obj1.constructed === obj2.constructed && + obj1.composed === obj2.composed && + asn1$8.equals(obj1.value, obj2.value); + if(options && options.includeBitStringContents) { + equal = equal && (obj1.bitStringContents === obj2.bitStringContents); + } + + return equal; +}; + +/** + * Gets the length of a BER-encoded ASN.1 value. + * + * In case the length is not specified, undefined is returned. + * + * @param b the BER-encoded ASN.1 byte buffer, starting with the first + * length byte. + * + * @return the length of the BER-encoded ASN.1 value or undefined. + */ +asn1$8.getBerValueLength = function(b) { + // TODO: move this function and related DER/BER functions to a der.js + // file; better abstract ASN.1 away from der/ber. + var b2 = b.getByte(); + if(b2 === 0x80) { + return undefined; + } + + // see if the length is "short form" or "long form" (bit 8 set) + var length; + var longForm = b2 & 0x80; + if(!longForm) { + // length is just the first byte + length = b2; + } else { + // the number of bytes the length is specified in bits 7 through 1 + // and each length byte is in big-endian base-256 + length = b.getInt((b2 & 0x7F) << 3); + } + return length; +}; + +/** + * Check if the byte buffer has enough bytes. Throws an Error if not. + * + * @param bytes the byte buffer to parse from. + * @param remaining the bytes remaining in the current parsing state. + * @param n the number of bytes the buffer must have. + */ +function _checkBufferLength(bytes, remaining, n) { + if(n > remaining) { + var error = new Error('Too few bytes to parse DER.'); + error.available = bytes.length(); + error.remaining = remaining; + error.requested = n; + throw error; + } +} + +/** + * Gets the length of a BER-encoded ASN.1 value. + * + * In case the length is not specified, undefined is returned. + * + * @param bytes the byte buffer to parse from. + * @param remaining the bytes remaining in the current parsing state. + * + * @return the length of the BER-encoded ASN.1 value or undefined. + */ +var _getValueLength = function(bytes, remaining) { + // TODO: move this function and related DER/BER functions to a der.js + // file; better abstract ASN.1 away from der/ber. + // fromDer already checked that this byte exists + var b2 = bytes.getByte(); + remaining--; + if(b2 === 0x80) { + return undefined; + } + + // see if the length is "short form" or "long form" (bit 8 set) + var length; + var longForm = b2 & 0x80; + if(!longForm) { + // length is just the first byte + length = b2; + } else { + // the number of bytes the length is specified in bits 7 through 1 + // and each length byte is in big-endian base-256 + var longFormBytes = b2 & 0x7F; + _checkBufferLength(bytes, remaining, longFormBytes); + length = bytes.getInt(longFormBytes << 3); + } + // FIXME: this will only happen for 32 bit getInt with high bit set + if(length < 0) { + throw new Error('Negative length: ' + length); + } + return length; +}; + +/** + * Parses an asn1 object from a byte buffer in DER format. + * + * @param bytes the byte buffer to parse from. + * @param [strict] true to be strict when checking value lengths, false to + * allow truncated values (default: true). + * @param [options] object with options or boolean strict flag + * [strict] true to be strict when checking value lengths, false to + * allow truncated values (default: true). + * [parseAllBytes] true to ensure all bytes are parsed + * (default: true) + * [decodeBitStrings] true to attempt to decode the content of + * BIT STRINGs (not OCTET STRINGs) using strict mode. Note that + * without schema support to understand the data context this can + * erroneously decode values that happen to be valid ASN.1. This + * flag will be deprecated or removed as soon as schema support is + * available. (default: true) + * + * @throws Will throw an error for various malformed input conditions. + * + * @return the parsed asn1 object. + */ +asn1$8.fromDer = function(bytes, options) { + if(options === undefined) { + options = { + strict: true, + parseAllBytes: true, + decodeBitStrings: true + }; + } + if(typeof options === 'boolean') { + options = { + strict: options, + parseAllBytes: true, + decodeBitStrings: true + }; + } + if(!('strict' in options)) { + options.strict = true; + } + if(!('parseAllBytes' in options)) { + options.parseAllBytes = true; + } + if(!('decodeBitStrings' in options)) { + options.decodeBitStrings = true; + } + + // wrap in buffer if needed + if(typeof bytes === 'string') { + bytes = forge$x.util.createBuffer(bytes); + } + + var byteCount = bytes.length(); + var value = _fromDer(bytes, bytes.length(), 0, options); + if(options.parseAllBytes && bytes.length() !== 0) { + var error = new Error('Unparsed DER bytes remain after ASN.1 parsing.'); + error.byteCount = byteCount; + error.remaining = bytes.length(); + throw error; + } + return value; +}; + +/** + * Internal function to parse an asn1 object from a byte buffer in DER format. + * + * @param bytes the byte buffer to parse from. + * @param remaining the number of bytes remaining for this chunk. + * @param depth the current parsing depth. + * @param options object with same options as fromDer(). + * + * @return the parsed asn1 object. + */ +function _fromDer(bytes, remaining, depth, options) { + // temporary storage for consumption calculations + var start; + + // minimum length for ASN.1 DER structure is 2 + _checkBufferLength(bytes, remaining, 2); + + // get the first byte + var b1 = bytes.getByte(); + // consumed one byte + remaining--; + + // get the tag class + var tagClass = (b1 & 0xC0); + + // get the type (bits 1-5) + var type = b1 & 0x1F; + + // get the variable value length and adjust remaining bytes + start = bytes.length(); + var length = _getValueLength(bytes, remaining); + remaining -= start - bytes.length(); + + // ensure there are enough bytes to get the value + if(length !== undefined && length > remaining) { + if(options.strict) { + var error = new Error('Too few bytes to read ASN.1 value.'); + error.available = bytes.length(); + error.remaining = remaining; + error.requested = length; + throw error; + } + // Note: be lenient with truncated values and use remaining state bytes + length = remaining; + } + + // value storage + var value; + // possible BIT STRING contents storage + var bitStringContents; + + // constructed flag is bit 6 (32 = 0x20) of the first byte + var constructed = ((b1 & 0x20) === 0x20); + if(constructed) { + // parse child asn1 objects from the value + value = []; + if(length === undefined) { + // asn1 object of indefinite length, read until end tag + for(;;) { + _checkBufferLength(bytes, remaining, 2); + if(bytes.bytes(2) === String.fromCharCode(0, 0)) { + bytes.getBytes(2); + remaining -= 2; + break; + } + start = bytes.length(); + value.push(_fromDer(bytes, remaining, depth + 1, options)); + remaining -= start - bytes.length(); + } + } else { + // parsing asn1 object of definite length + while(length > 0) { + start = bytes.length(); + value.push(_fromDer(bytes, length, depth + 1, options)); + remaining -= start - bytes.length(); + length -= start - bytes.length(); + } + } + } + + // if a BIT STRING, save the contents including padding + if(value === undefined && tagClass === asn1$8.Class.UNIVERSAL && + type === asn1$8.Type.BITSTRING) { + bitStringContents = bytes.bytes(length); + } + + // determine if a non-constructed value should be decoded as a composed + // value that contains other ASN.1 objects. BIT STRINGs (and OCTET STRINGs) + // can be used this way. + if(value === undefined && options.decodeBitStrings && + tagClass === asn1$8.Class.UNIVERSAL && + // FIXME: OCTET STRINGs not yet supported here + // .. other parts of forge expect to decode OCTET STRINGs manually + (type === asn1$8.Type.BITSTRING /*|| type === asn1.Type.OCTETSTRING*/) && + length > 1) { + // save read position + var savedRead = bytes.read; + var savedRemaining = remaining; + var unused = 0; + if(type === asn1$8.Type.BITSTRING) { + /* The first octet gives the number of bits by which the length of the + bit string is less than the next multiple of eight (this is called + the "number of unused bits"). + + The second and following octets give the value of the bit string + converted to an octet string. */ + _checkBufferLength(bytes, remaining, 1); + unused = bytes.getByte(); + remaining--; + } + // if all bits are used, maybe the BIT/OCTET STRING holds ASN.1 objs + if(unused === 0) { + try { + // attempt to parse child asn1 object from the value + // (stored in array to signal composed value) + start = bytes.length(); + var subOptions = { + // enforce strict mode to avoid parsing ASN.1 from plain data + strict: true, + decodeBitStrings: true + }; + var composed = _fromDer(bytes, remaining, depth + 1, subOptions); + var used = start - bytes.length(); + remaining -= used; + if(type == asn1$8.Type.BITSTRING) { + used++; + } + + // if the data all decoded and the class indicates UNIVERSAL or + // CONTEXT_SPECIFIC then assume we've got an encapsulated ASN.1 object + var tc = composed.tagClass; + if(used === length && + (tc === asn1$8.Class.UNIVERSAL || tc === asn1$8.Class.CONTEXT_SPECIFIC)) { + value = [composed]; + } + } catch(ex) { + } + } + if(value === undefined) { + // restore read position + bytes.read = savedRead; + remaining = savedRemaining; + } + } + + if(value === undefined) { + // asn1 not constructed or composed, get raw value + // TODO: do DER to OID conversion and vice-versa in .toDer? + + if(length === undefined) { + if(options.strict) { + throw new Error('Non-constructed ASN.1 object of indefinite length.'); + } + // be lenient and use remaining state bytes + length = remaining; + } + + if(type === asn1$8.Type.BMPSTRING) { + value = ''; + for(; length > 0; length -= 2) { + _checkBufferLength(bytes, remaining, 2); + value += String.fromCharCode(bytes.getInt16()); + remaining -= 2; + } + } else { + value = bytes.getBytes(length); + remaining -= length; + } + } + + // add BIT STRING contents if available + var asn1Options = bitStringContents === undefined ? null : { + bitStringContents: bitStringContents + }; + + // create and return asn1 object + return asn1$8.create(tagClass, type, constructed, value, asn1Options); +} + +/** + * Converts the given asn1 object to a buffer of bytes in DER format. + * + * @param asn1 the asn1 object to convert to bytes. + * + * @return the buffer of bytes. + */ +asn1$8.toDer = function(obj) { + var bytes = forge$x.util.createBuffer(); + + // build the first byte + var b1 = obj.tagClass | obj.type; + + // for storing the ASN.1 value + var value = forge$x.util.createBuffer(); + + // use BIT STRING contents if available and data not changed + var useBitStringContents = false; + if('bitStringContents' in obj) { + useBitStringContents = true; + if(obj.original) { + useBitStringContents = asn1$8.equals(obj, obj.original); + } + } + + if(useBitStringContents) { + value.putBytes(obj.bitStringContents); + } else if(obj.composed) { + // if composed, use each child asn1 object's DER bytes as value + // turn on 6th bit (0x20 = 32) to indicate asn1 is constructed + // from other asn1 objects + if(obj.constructed) { + b1 |= 0x20; + } else { + // type is a bit string, add unused bits of 0x00 + value.putByte(0x00); + } + + // add all of the child DER bytes together + for(var i = 0; i < obj.value.length; ++i) { + if(obj.value[i] !== undefined) { + value.putBuffer(asn1$8.toDer(obj.value[i])); + } + } + } else { + // use asn1.value directly + if(obj.type === asn1$8.Type.BMPSTRING) { + for(var i = 0; i < obj.value.length; ++i) { + value.putInt16(obj.value.charCodeAt(i)); + } + } else { + // ensure integer is minimally-encoded + // TODO: should all leading bytes be stripped vs just one? + // .. ex '00 00 01' => '01'? + if(obj.type === asn1$8.Type.INTEGER && + obj.value.length > 1 && + // leading 0x00 for positive integer + ((obj.value.charCodeAt(0) === 0 && + (obj.value.charCodeAt(1) & 0x80) === 0) || + // leading 0xFF for negative integer + (obj.value.charCodeAt(0) === 0xFF && + (obj.value.charCodeAt(1) & 0x80) === 0x80))) { + value.putBytes(obj.value.substr(1)); + } else { + value.putBytes(obj.value); + } + } + } + + // add tag byte + bytes.putByte(b1); + + // use "short form" encoding + if(value.length() <= 127) { + // one byte describes the length + // bit 8 = 0 and bits 7-1 = length + bytes.putByte(value.length() & 0x7F); + } else { + // use "long form" encoding + // 2 to 127 bytes describe the length + // first byte: bit 8 = 1 and bits 7-1 = # of additional bytes + // other bytes: length in base 256, big-endian + var len = value.length(); + var lenBytes = ''; + do { + lenBytes += String.fromCharCode(len & 0xFF); + len = len >>> 8; + } while(len > 0); + + // set first byte to # bytes used to store the length and turn on + // bit 8 to indicate long-form length is used + bytes.putByte(lenBytes.length | 0x80); + + // concatenate length bytes in reverse since they were generated + // little endian and we need big endian + for(var i = lenBytes.length - 1; i >= 0; --i) { + bytes.putByte(lenBytes.charCodeAt(i)); + } + } + + // concatenate value bytes + bytes.putBuffer(value); + return bytes; +}; + +/** + * Converts an OID dot-separated string to a byte buffer. The byte buffer + * contains only the DER-encoded value, not any tag or length bytes. + * + * @param oid the OID dot-separated string. + * + * @return the byte buffer. + */ +asn1$8.oidToDer = function(oid) { + // split OID into individual values + var values = oid.split('.'); + var bytes = forge$x.util.createBuffer(); + + // first byte is 40 * value1 + value2 + bytes.putByte(40 * parseInt(values[0], 10) + parseInt(values[1], 10)); + // other bytes are each value in base 128 with 8th bit set except for + // the last byte for each value + var last, valueBytes, value, b; + for(var i = 2; i < values.length; ++i) { + // produce value bytes in reverse because we don't know how many + // bytes it will take to store the value + last = true; + valueBytes = []; + value = parseInt(values[i], 10); + do { + b = value & 0x7F; + value = value >>> 7; + // if value is not last, then turn on 8th bit + if(!last) { + b |= 0x80; + } + valueBytes.push(b); + last = false; + } while(value > 0); + + // add value bytes in reverse (needs to be in big endian) + for(var n = valueBytes.length - 1; n >= 0; --n) { + bytes.putByte(valueBytes[n]); + } + } + + return bytes; +}; + +/** + * Converts a DER-encoded byte buffer to an OID dot-separated string. The + * byte buffer should contain only the DER-encoded value, not any tag or + * length bytes. + * + * @param bytes the byte buffer. + * + * @return the OID dot-separated string. + */ +asn1$8.derToOid = function(bytes) { + var oid; + + // wrap in buffer if needed + if(typeof bytes === 'string') { + bytes = forge$x.util.createBuffer(bytes); + } + + // first byte is 40 * value1 + value2 + var b = bytes.getByte(); + oid = Math.floor(b / 40) + '.' + (b % 40); + + // other bytes are each value in base 128 with 8th bit set except for + // the last byte for each value + var value = 0; + while(bytes.length() > 0) { + b = bytes.getByte(); + value = value << 7; + // not the last byte for the value + if(b & 0x80) { + value += b & 0x7F; + } else { + // last byte + oid += '.' + (value + b); + value = 0; + } + } + + return oid; +}; + +/** + * Converts a UTCTime value to a date. + * + * Note: GeneralizedTime has 4 digits for the year and is used for X.509 + * dates past 2049. Parsing that structure hasn't been implemented yet. + * + * @param utc the UTCTime value to convert. + * + * @return the date. + */ +asn1$8.utcTimeToDate = function(utc) { + /* The following formats can be used: + + YYMMDDhhmmZ + YYMMDDhhmm+hh'mm' + YYMMDDhhmm-hh'mm' + YYMMDDhhmmssZ + YYMMDDhhmmss+hh'mm' + YYMMDDhhmmss-hh'mm' + + Where: + + YY is the least significant two digits of the year + MM is the month (01 to 12) + DD is the day (01 to 31) + hh is the hour (00 to 23) + mm are the minutes (00 to 59) + ss are the seconds (00 to 59) + Z indicates that local time is GMT, + indicates that local time is + later than GMT, and - indicates that local time is earlier than GMT + hh' is the absolute value of the offset from GMT in hours + mm' is the absolute value of the offset from GMT in minutes */ + var date = new Date(); + + // if YY >= 50 use 19xx, if YY < 50 use 20xx + var year = parseInt(utc.substr(0, 2), 10); + year = (year >= 50) ? 1900 + year : 2000 + year; + var MM = parseInt(utc.substr(2, 2), 10) - 1; // use 0-11 for month + var DD = parseInt(utc.substr(4, 2), 10); + var hh = parseInt(utc.substr(6, 2), 10); + var mm = parseInt(utc.substr(8, 2), 10); + var ss = 0; + + // not just YYMMDDhhmmZ + if(utc.length > 11) { + // get character after minutes + var c = utc.charAt(10); + var end = 10; + + // see if seconds are present + if(c !== '+' && c !== '-') { + // get seconds + ss = parseInt(utc.substr(10, 2), 10); + end += 2; + } + } + + // update date + date.setUTCFullYear(year, MM, DD); + date.setUTCHours(hh, mm, ss, 0); + + if(end) { + // get +/- after end of time + c = utc.charAt(end); + if(c === '+' || c === '-') { + // get hours+minutes offset + var hhoffset = parseInt(utc.substr(end + 1, 2), 10); + var mmoffset = parseInt(utc.substr(end + 4, 2), 10); + + // calculate offset in milliseconds + var offset = hhoffset * 60 + mmoffset; + offset *= 60000; + + // apply offset + if(c === '+') { + date.setTime(+date - offset); + } else { + date.setTime(+date + offset); + } + } + } + + return date; +}; + +/** + * Converts a GeneralizedTime value to a date. + * + * @param gentime the GeneralizedTime value to convert. + * + * @return the date. + */ +asn1$8.generalizedTimeToDate = function(gentime) { + /* The following formats can be used: + + YYYYMMDDHHMMSS + YYYYMMDDHHMMSS.fff + YYYYMMDDHHMMSSZ + YYYYMMDDHHMMSS.fffZ + YYYYMMDDHHMMSS+hh'mm' + YYYYMMDDHHMMSS.fff+hh'mm' + YYYYMMDDHHMMSS-hh'mm' + YYYYMMDDHHMMSS.fff-hh'mm' + + Where: + + YYYY is the year + MM is the month (01 to 12) + DD is the day (01 to 31) + hh is the hour (00 to 23) + mm are the minutes (00 to 59) + ss are the seconds (00 to 59) + .fff is the second fraction, accurate to three decimal places + Z indicates that local time is GMT, + indicates that local time is + later than GMT, and - indicates that local time is earlier than GMT + hh' is the absolute value of the offset from GMT in hours + mm' is the absolute value of the offset from GMT in minutes */ + var date = new Date(); + + var YYYY = parseInt(gentime.substr(0, 4), 10); + var MM = parseInt(gentime.substr(4, 2), 10) - 1; // use 0-11 for month + var DD = parseInt(gentime.substr(6, 2), 10); + var hh = parseInt(gentime.substr(8, 2), 10); + var mm = parseInt(gentime.substr(10, 2), 10); + var ss = parseInt(gentime.substr(12, 2), 10); + var fff = 0; + var offset = 0; + var isUTC = false; + + if(gentime.charAt(gentime.length - 1) === 'Z') { + isUTC = true; + } + + var end = gentime.length - 5, c = gentime.charAt(end); + if(c === '+' || c === '-') { + // get hours+minutes offset + var hhoffset = parseInt(gentime.substr(end + 1, 2), 10); + var mmoffset = parseInt(gentime.substr(end + 4, 2), 10); + + // calculate offset in milliseconds + offset = hhoffset * 60 + mmoffset; + offset *= 60000; + + // apply offset + if(c === '+') { + offset *= -1; + } + + isUTC = true; + } + + // check for second fraction + if(gentime.charAt(14) === '.') { + fff = parseFloat(gentime.substr(14), 10) * 1000; + } + + if(isUTC) { + date.setUTCFullYear(YYYY, MM, DD); + date.setUTCHours(hh, mm, ss, fff); + + // apply offset + date.setTime(+date + offset); + } else { + date.setFullYear(YYYY, MM, DD); + date.setHours(hh, mm, ss, fff); + } + + return date; +}; + +/** + * Converts a date to a UTCTime value. + * + * Note: GeneralizedTime has 4 digits for the year and is used for X.509 + * dates past 2049. Converting to a GeneralizedTime hasn't been + * implemented yet. + * + * @param date the date to convert. + * + * @return the UTCTime value. + */ +asn1$8.dateToUtcTime = function(date) { + // TODO: validate; currently assumes proper format + if(typeof date === 'string') { + return date; + } + + var rval = ''; + + // create format YYMMDDhhmmssZ + var format = []; + format.push(('' + date.getUTCFullYear()).substr(2)); + format.push('' + (date.getUTCMonth() + 1)); + format.push('' + date.getUTCDate()); + format.push('' + date.getUTCHours()); + format.push('' + date.getUTCMinutes()); + format.push('' + date.getUTCSeconds()); + + // ensure 2 digits are used for each format entry + for(var i = 0; i < format.length; ++i) { + if(format[i].length < 2) { + rval += '0'; + } + rval += format[i]; + } + rval += 'Z'; + + return rval; +}; + +/** + * Converts a date to a GeneralizedTime value. + * + * @param date the date to convert. + * + * @return the GeneralizedTime value as a string. + */ +asn1$8.dateToGeneralizedTime = function(date) { + // TODO: validate; currently assumes proper format + if(typeof date === 'string') { + return date; + } + + var rval = ''; + + // create format YYYYMMDDHHMMSSZ + var format = []; + format.push('' + date.getUTCFullYear()); + format.push('' + (date.getUTCMonth() + 1)); + format.push('' + date.getUTCDate()); + format.push('' + date.getUTCHours()); + format.push('' + date.getUTCMinutes()); + format.push('' + date.getUTCSeconds()); + + // ensure 2 digits are used for each format entry + for(var i = 0; i < format.length; ++i) { + if(format[i].length < 2) { + rval += '0'; + } + rval += format[i]; + } + rval += 'Z'; + + return rval; +}; + +/** + * Converts a javascript integer to a DER-encoded byte buffer to be used + * as the value for an INTEGER type. + * + * @param x the integer. + * + * @return the byte buffer. + */ +asn1$8.integerToDer = function(x) { + var rval = forge$x.util.createBuffer(); + if(x >= -0x80 && x < 0x80) { + return rval.putSignedInt(x, 8); + } + if(x >= -0x8000 && x < 0x8000) { + return rval.putSignedInt(x, 16); + } + if(x >= -0x800000 && x < 0x800000) { + return rval.putSignedInt(x, 24); + } + if(x >= -0x80000000 && x < 0x80000000) { + return rval.putSignedInt(x, 32); + } + var error = new Error('Integer too large; max is 32-bits.'); + error.integer = x; + throw error; +}; + +/** + * Converts a DER-encoded byte buffer to a javascript integer. This is + * typically used to decode the value of an INTEGER type. + * + * @param bytes the byte buffer. + * + * @return the integer. + */ +asn1$8.derToInteger = function(bytes) { + // wrap in buffer if needed + if(typeof bytes === 'string') { + bytes = forge$x.util.createBuffer(bytes); + } + + var n = bytes.length() * 8; + if(n > 32) { + throw new Error('Integer too large; max is 32-bits.'); + } + return bytes.getSignedInt(n); +}; + +/** + * Validates that the given ASN.1 object is at least a super set of the + * given ASN.1 structure. Only tag classes and types are checked. An + * optional map may also be provided to capture ASN.1 values while the + * structure is checked. + * + * To capture an ASN.1 value, set an object in the validator's 'capture' + * parameter to the key to use in the capture map. To capture the full + * ASN.1 object, specify 'captureAsn1'. To capture BIT STRING bytes, including + * the leading unused bits counter byte, specify 'captureBitStringContents'. + * To capture BIT STRING bytes, without the leading unused bits counter byte, + * specify 'captureBitStringValue'. + * + * Objects in the validator may set a field 'optional' to true to indicate + * that it isn't necessary to pass validation. + * + * @param obj the ASN.1 object to validate. + * @param v the ASN.1 structure validator. + * @param capture an optional map to capture values in. + * @param errors an optional array for storing validation errors. + * + * @return true on success, false on failure. + */ +asn1$8.validate = function(obj, v, capture, errors) { + var rval = false; + + // ensure tag class and type are the same if specified + if((obj.tagClass === v.tagClass || typeof(v.tagClass) === 'undefined') && + (obj.type === v.type || typeof(v.type) === 'undefined')) { + // ensure constructed flag is the same if specified + if(obj.constructed === v.constructed || + typeof(v.constructed) === 'undefined') { + rval = true; + + // handle sub values + if(v.value && forge$x.util.isArray(v.value)) { + var j = 0; + for(var i = 0; rval && i < v.value.length; ++i) { + rval = v.value[i].optional || false; + if(obj.value[j]) { + rval = asn1$8.validate(obj.value[j], v.value[i], capture, errors); + if(rval) { + ++j; + } else if(v.value[i].optional) { + rval = true; + } + } + if(!rval && errors) { + errors.push( + '[' + v.name + '] ' + + 'Tag class "' + v.tagClass + '", type "' + + v.type + '" expected value length "' + + v.value.length + '", got "' + + obj.value.length + '"'); + } + } + } + + if(rval && capture) { + if(v.capture) { + capture[v.capture] = obj.value; + } + if(v.captureAsn1) { + capture[v.captureAsn1] = obj; + } + if(v.captureBitStringContents && 'bitStringContents' in obj) { + capture[v.captureBitStringContents] = obj.bitStringContents; + } + if(v.captureBitStringValue && 'bitStringContents' in obj) { + if(obj.bitStringContents.length < 2) { + capture[v.captureBitStringValue] = ''; + } else { + // FIXME: support unused bits with data shifting + var unused = obj.bitStringContents.charCodeAt(0); + if(unused !== 0) { + throw new Error( + 'captureBitStringValue only supported for zero unused bits'); + } + capture[v.captureBitStringValue] = obj.bitStringContents.slice(1); + } + } + } + } else if(errors) { + errors.push( + '[' + v.name + '] ' + + 'Expected constructed "' + v.constructed + '", got "' + + obj.constructed + '"'); + } + } else if(errors) { + if(obj.tagClass !== v.tagClass) { + errors.push( + '[' + v.name + '] ' + + 'Expected tag class "' + v.tagClass + '", got "' + + obj.tagClass + '"'); + } + if(obj.type !== v.type) { + errors.push( + '[' + v.name + '] ' + + 'Expected type "' + v.type + '", got "' + obj.type + '"'); + } + } + return rval; +}; + +// regex for testing for non-latin characters +var _nonLatinRegex = /[^\\u0000-\\u00ff]/; + +/** + * Pretty prints an ASN.1 object to a string. + * + * @param obj the object to write out. + * @param level the level in the tree. + * @param indentation the indentation to use. + * + * @return the string. + */ +asn1$8.prettyPrint = function(obj, level, indentation) { + var rval = ''; + + // set default level and indentation + level = level || 0; + indentation = indentation || 2; + + // start new line for deep levels + if(level > 0) { + rval += '\n'; + } + + // create indent + var indent = ''; + for(var i = 0; i < level * indentation; ++i) { + indent += ' '; + } + + // print class:type + rval += indent + 'Tag: '; + switch(obj.tagClass) { + case asn1$8.Class.UNIVERSAL: + rval += 'Universal:'; + break; + case asn1$8.Class.APPLICATION: + rval += 'Application:'; + break; + case asn1$8.Class.CONTEXT_SPECIFIC: + rval += 'Context-Specific:'; + break; + case asn1$8.Class.PRIVATE: + rval += 'Private:'; + break; + } + + if(obj.tagClass === asn1$8.Class.UNIVERSAL) { + rval += obj.type; + + // known types + switch(obj.type) { + case asn1$8.Type.NONE: + rval += ' (None)'; + break; + case asn1$8.Type.BOOLEAN: + rval += ' (Boolean)'; + break; + case asn1$8.Type.INTEGER: + rval += ' (Integer)'; + break; + case asn1$8.Type.BITSTRING: + rval += ' (Bit string)'; + break; + case asn1$8.Type.OCTETSTRING: + rval += ' (Octet string)'; + break; + case asn1$8.Type.NULL: + rval += ' (Null)'; + break; + case asn1$8.Type.OID: + rval += ' (Object Identifier)'; + break; + case asn1$8.Type.ODESC: + rval += ' (Object Descriptor)'; + break; + case asn1$8.Type.EXTERNAL: + rval += ' (External or Instance of)'; + break; + case asn1$8.Type.REAL: + rval += ' (Real)'; + break; + case asn1$8.Type.ENUMERATED: + rval += ' (Enumerated)'; + break; + case asn1$8.Type.EMBEDDED: + rval += ' (Embedded PDV)'; + break; + case asn1$8.Type.UTF8: + rval += ' (UTF8)'; + break; + case asn1$8.Type.ROID: + rval += ' (Relative Object Identifier)'; + break; + case asn1$8.Type.SEQUENCE: + rval += ' (Sequence)'; + break; + case asn1$8.Type.SET: + rval += ' (Set)'; + break; + case asn1$8.Type.PRINTABLESTRING: + rval += ' (Printable String)'; + break; + case asn1$8.Type.IA5String: + rval += ' (IA5String (ASCII))'; + break; + case asn1$8.Type.UTCTIME: + rval += ' (UTC time)'; + break; + case asn1$8.Type.GENERALIZEDTIME: + rval += ' (Generalized time)'; + break; + case asn1$8.Type.BMPSTRING: + rval += ' (BMP String)'; + break; + } + } else { + rval += obj.type; + } + + rval += '\n'; + rval += indent + 'Constructed: ' + obj.constructed + '\n'; + + if(obj.composed) { + var subvalues = 0; + var sub = ''; + for(var i = 0; i < obj.value.length; ++i) { + if(obj.value[i] !== undefined) { + subvalues += 1; + sub += asn1$8.prettyPrint(obj.value[i], level + 1, indentation); + if((i + 1) < obj.value.length) { + sub += ','; + } + } + } + rval += indent + 'Sub values: ' + subvalues + sub; + } else { + rval += indent + 'Value: '; + if(obj.type === asn1$8.Type.OID) { + var oid = asn1$8.derToOid(obj.value); + rval += oid; + if(forge$x.pki && forge$x.pki.oids) { + if(oid in forge$x.pki.oids) { + rval += ' (' + forge$x.pki.oids[oid] + ') '; + } + } + } + if(obj.type === asn1$8.Type.INTEGER) { + try { + rval += asn1$8.derToInteger(obj.value); + } catch(ex) { + rval += '0x' + forge$x.util.bytesToHex(obj.value); + } + } else if(obj.type === asn1$8.Type.BITSTRING) { + // TODO: shift bits as needed to display without padding + if(obj.value.length > 1) { + // remove unused bits field + rval += '0x' + forge$x.util.bytesToHex(obj.value.slice(1)); + } else { + rval += '(none)'; + } + // show unused bit count + if(obj.value.length > 0) { + var unused = obj.value.charCodeAt(0); + if(unused == 1) { + rval += ' (1 unused bit shown)'; + } else if(unused > 1) { + rval += ' (' + unused + ' unused bits shown)'; + } + } + } else if(obj.type === asn1$8.Type.OCTETSTRING) { + if(!_nonLatinRegex.test(obj.value)) { + rval += '(' + obj.value + ') '; + } + rval += '0x' + forge$x.util.bytesToHex(obj.value); + } else if(obj.type === asn1$8.Type.UTF8) { + try { + rval += forge$x.util.decodeUtf8(obj.value); + } catch(e) { + if(e.message === 'URI malformed') { + rval += + '0x' + forge$x.util.bytesToHex(obj.value) + ' (malformed UTF8)'; + } else { + throw e; + } + } + } else if(obj.type === asn1$8.Type.PRINTABLESTRING || + obj.type === asn1$8.Type.IA5String) { + rval += obj.value; + } else if(_nonLatinRegex.test(obj.value)) { + rval += '0x' + forge$x.util.bytesToHex(obj.value); + } else if(obj.value.length === 0) { + rval += '[null]'; + } else { + rval += obj.value; + } + } + + return rval; +}; + +/** + * Node.js module for Forge message digests. + * + * @author Dave Longley + * + * Copyright 2011-2017 Digital Bazaar, Inc. + */ + +var forge$w = forge$D; + +forge$w.md = forge$w.md || {}; +forge$w.md.algorithms = forge$w.md.algorithms || {}; + +/** + * Hash-based Message Authentication Code implementation. Requires a message + * digest object that can be obtained, for example, from forge.md.sha1 or + * forge.md.md5. + * + * @author Dave Longley + * + * Copyright (c) 2010-2012 Digital Bazaar, Inc. All rights reserved. + */ + +var forge$v = forge$D; + + + +/* HMAC API */ +var hmac = forge$v.hmac = forge$v.hmac || {}; + +/** + * Creates an HMAC object that uses the given message digest object. + * + * @return an HMAC object. + */ +hmac.create = function() { + // the hmac key to use + var _key = null; + + // the message digest to use + var _md = null; + + // the inner padding + var _ipadding = null; + + // the outer padding + var _opadding = null; + + // hmac context + var ctx = {}; + + /** + * Starts or restarts the HMAC with the given key and message digest. + * + * @param md the message digest to use, null to reuse the previous one, + * a string to use builtin 'sha1', 'md5', 'sha256'. + * @param key the key to use as a string, array of bytes, byte buffer, + * or null to reuse the previous key. + */ + ctx.start = function(md, key) { + if(md !== null) { + if(typeof md === 'string') { + // create builtin message digest + md = md.toLowerCase(); + if(md in forge$v.md.algorithms) { + _md = forge$v.md.algorithms[md].create(); + } else { + throw new Error('Unknown hash algorithm "' + md + '"'); + } + } else { + // store message digest + _md = md; + } + } + + if(key === null) { + // reuse previous key + key = _key; + } else { + if(typeof key === 'string') { + // convert string into byte buffer + key = forge$v.util.createBuffer(key); + } else if(forge$v.util.isArray(key)) { + // convert byte array into byte buffer + var tmp = key; + key = forge$v.util.createBuffer(); + for(var i = 0; i < tmp.length; ++i) { + key.putByte(tmp[i]); + } + } + + // if key is longer than blocksize, hash it + var keylen = key.length(); + if(keylen > _md.blockLength) { + _md.start(); + _md.update(key.bytes()); + key = _md.digest(); + } + + // mix key into inner and outer padding + // ipadding = [0x36 * blocksize] ^ key + // opadding = [0x5C * blocksize] ^ key + _ipadding = forge$v.util.createBuffer(); + _opadding = forge$v.util.createBuffer(); + keylen = key.length(); + for(var i = 0; i < keylen; ++i) { + var tmp = key.at(i); + _ipadding.putByte(0x36 ^ tmp); + _opadding.putByte(0x5C ^ tmp); + } + + // if key is shorter than blocksize, add additional padding + if(keylen < _md.blockLength) { + var tmp = _md.blockLength - keylen; + for(var i = 0; i < tmp; ++i) { + _ipadding.putByte(0x36); + _opadding.putByte(0x5C); + } + } + _key = key; + _ipadding = _ipadding.bytes(); + _opadding = _opadding.bytes(); + } + + // digest is done like so: hash(opadding | hash(ipadding | message)) + + // prepare to do inner hash + // hash(ipadding | message) + _md.start(); + _md.update(_ipadding); + }; + + /** + * Updates the HMAC with the given message bytes. + * + * @param bytes the bytes to update with. + */ + ctx.update = function(bytes) { + _md.update(bytes); + }; + + /** + * Produces the Message Authentication Code (MAC). + * + * @return a byte buffer containing the digest value. + */ + ctx.getMac = function() { + // digest is done like so: hash(opadding | hash(ipadding | message)) + // here we do the outer hashing + var inner = _md.digest().bytes(); + _md.start(); + _md.update(_opadding); + _md.update(inner); + return _md.digest(); + }; + // alias for getMac + ctx.digest = ctx.getMac; + + return ctx; +}; + +/** + * Message Digest Algorithm 5 with 128-bit digest (MD5) implementation. + * + * @author Dave Longley + * + * Copyright (c) 2010-2014 Digital Bazaar, Inc. + */ + +var forge$u = forge$D; + + + +var md5 = forge$u.md5 = forge$u.md5 || {}; +forge$u.md.md5 = forge$u.md.algorithms.md5 = md5; + +/** + * Creates an MD5 message digest object. + * + * @return a message digest object. + */ +md5.create = function() { + // do initialization as necessary + if(!_initialized$3) { + _init$3(); + } + + // MD5 state contains four 32-bit integers + var _state = null; + + // input buffer + var _input = forge$u.util.createBuffer(); + + // used for word storage + var _w = new Array(16); + + // message digest object + var md = { + algorithm: 'md5', + blockLength: 64, + digestLength: 16, + // 56-bit length of message so far (does not including padding) + messageLength: 0, + // true message length + fullMessageLength: null, + // size of message length in bytes + messageLengthSize: 8 + }; + + /** + * Starts the digest. + * + * @return this digest object. + */ + md.start = function() { + // up to 56-bit message length for convenience + md.messageLength = 0; + + // full message length (set md.messageLength64 for backwards-compatibility) + md.fullMessageLength = md.messageLength64 = []; + var int32s = md.messageLengthSize / 4; + for(var i = 0; i < int32s; ++i) { + md.fullMessageLength.push(0); + } + _input = forge$u.util.createBuffer(); + _state = { + h0: 0x67452301, + h1: 0xEFCDAB89, + h2: 0x98BADCFE, + h3: 0x10325476 + }; + return md; + }; + // start digest automatically for first time + md.start(); + + /** + * Updates the digest with the given message input. The given input can + * treated as raw input (no encoding will be applied) or an encoding of + * 'utf8' maybe given to encode the input using UTF-8. + * + * @param msg the message input to update with. + * @param encoding the encoding to use (default: 'raw', other: 'utf8'). + * + * @return this digest object. + */ + md.update = function(msg, encoding) { + if(encoding === 'utf8') { + msg = forge$u.util.encodeUtf8(msg); + } + + // update message length + var len = msg.length; + md.messageLength += len; + len = [(len / 0x100000000) >>> 0, len >>> 0]; + for(var i = md.fullMessageLength.length - 1; i >= 0; --i) { + md.fullMessageLength[i] += len[1]; + len[1] = len[0] + ((md.fullMessageLength[i] / 0x100000000) >>> 0); + md.fullMessageLength[i] = md.fullMessageLength[i] >>> 0; + len[0] = (len[1] / 0x100000000) >>> 0; + } + + // add bytes to input buffer + _input.putBytes(msg); + + // process bytes + _update$3(_state, _w, _input); + + // compact input buffer every 2K or if empty + if(_input.read > 2048 || _input.length() === 0) { + _input.compact(); + } + + return md; + }; + + /** + * Produces the digest. + * + * @return a byte buffer containing the digest value. + */ + md.digest = function() { + /* Note: Here we copy the remaining bytes in the input buffer and + add the appropriate MD5 padding. Then we do the final update + on a copy of the state so that if the user wants to get + intermediate digests they can do so. */ + + /* Determine the number of bytes that must be added to the message + to ensure its length is congruent to 448 mod 512. In other words, + the data to be digested must be a multiple of 512 bits (or 128 bytes). + This data includes the message, some padding, and the length of the + message. Since the length of the message will be encoded as 8 bytes (64 + bits), that means that the last segment of the data must have 56 bytes + (448 bits) of message and padding. Therefore, the length of the message + plus the padding must be congruent to 448 mod 512 because + 512 - 128 = 448. + + In order to fill up the message length it must be filled with + padding that begins with 1 bit followed by all 0 bits. Padding + must *always* be present, so if the message length is already + congruent to 448 mod 512, then 512 padding bits must be added. */ + + var finalBlock = forge$u.util.createBuffer(); + finalBlock.putBytes(_input.bytes()); + + // compute remaining size to be digested (include message length size) + var remaining = ( + md.fullMessageLength[md.fullMessageLength.length - 1] + + md.messageLengthSize); + + // add padding for overflow blockSize - overflow + // _padding starts with 1 byte with first bit is set (byte value 128), then + // there may be up to (blockSize - 1) other pad bytes + var overflow = remaining & (md.blockLength - 1); + finalBlock.putBytes(_padding$3.substr(0, md.blockLength - overflow)); + + // serialize message length in bits in little-endian order; since length + // is stored in bytes we multiply by 8 and add carry + var bits, carry = 0; + for(var i = md.fullMessageLength.length - 1; i >= 0; --i) { + bits = md.fullMessageLength[i] * 8 + carry; + carry = (bits / 0x100000000) >>> 0; + finalBlock.putInt32Le(bits >>> 0); + } + + var s2 = { + h0: _state.h0, + h1: _state.h1, + h2: _state.h2, + h3: _state.h3 + }; + _update$3(s2, _w, finalBlock); + var rval = forge$u.util.createBuffer(); + rval.putInt32Le(s2.h0); + rval.putInt32Le(s2.h1); + rval.putInt32Le(s2.h2); + rval.putInt32Le(s2.h3); + return rval; + }; + + return md; +}; + +// padding, constant tables for calculating md5 +var _padding$3 = null; +var _g = null; +var _r = null; +var _k$2 = null; +var _initialized$3 = false; + +/** + * Initializes the constant tables. + */ +function _init$3() { + // create padding + _padding$3 = String.fromCharCode(128); + _padding$3 += forge$u.util.fillString(String.fromCharCode(0x00), 64); + + // g values + _g = [ + 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, + 1, 6, 11, 0, 5, 10, 15, 4, 9, 14, 3, 8, 13, 2, 7, 12, + 5, 8, 11, 14, 1, 4, 7, 10, 13, 0, 3, 6, 9, 12, 15, 2, + 0, 7, 14, 5, 12, 3, 10, 1, 8, 15, 6, 13, 4, 11, 2, 9]; + + // rounds table + _r = [ + 7, 12, 17, 22, 7, 12, 17, 22, 7, 12, 17, 22, 7, 12, 17, 22, + 5, 9, 14, 20, 5, 9, 14, 20, 5, 9, 14, 20, 5, 9, 14, 20, + 4, 11, 16, 23, 4, 11, 16, 23, 4, 11, 16, 23, 4, 11, 16, 23, + 6, 10, 15, 21, 6, 10, 15, 21, 6, 10, 15, 21, 6, 10, 15, 21]; + + // get the result of abs(sin(i + 1)) as a 32-bit integer + _k$2 = new Array(64); + for(var i = 0; i < 64; ++i) { + _k$2[i] = Math.floor(Math.abs(Math.sin(i + 1)) * 0x100000000); + } + + // now initialized + _initialized$3 = true; +} + +/** + * Updates an MD5 state with the given byte buffer. + * + * @param s the MD5 state to update. + * @param w the array to use to store words. + * @param bytes the byte buffer to update with. + */ +function _update$3(s, w, bytes) { + // consume 512 bit (64 byte) chunks + var t, a, b, c, d, f, r, i; + var len = bytes.length(); + while(len >= 64) { + // initialize hash value for this chunk + a = s.h0; + b = s.h1; + c = s.h2; + d = s.h3; + + // round 1 + for(i = 0; i < 16; ++i) { + w[i] = bytes.getInt32Le(); + f = d ^ (b & (c ^ d)); + t = (a + f + _k$2[i] + w[i]); + r = _r[i]; + a = d; + d = c; + c = b; + b += (t << r) | (t >>> (32 - r)); + } + // round 2 + for(; i < 32; ++i) { + f = c ^ (d & (b ^ c)); + t = (a + f + _k$2[i] + w[_g[i]]); + r = _r[i]; + a = d; + d = c; + c = b; + b += (t << r) | (t >>> (32 - r)); + } + // round 3 + for(; i < 48; ++i) { + f = b ^ c ^ d; + t = (a + f + _k$2[i] + w[_g[i]]); + r = _r[i]; + a = d; + d = c; + c = b; + b += (t << r) | (t >>> (32 - r)); + } + // round 4 + for(; i < 64; ++i) { + f = c ^ (b | ~d); + t = (a + f + _k$2[i] + w[_g[i]]); + r = _r[i]; + a = d; + d = c; + c = b; + b += (t << r) | (t >>> (32 - r)); + } + + // update hash state + s.h0 = (s.h0 + a) | 0; + s.h1 = (s.h1 + b) | 0; + s.h2 = (s.h2 + c) | 0; + s.h3 = (s.h3 + d) | 0; + + len -= 64; + } +} + +/** + * Javascript implementation of basic PEM (Privacy Enhanced Mail) algorithms. + * + * See: RFC 1421. + * + * @author Dave Longley + * + * Copyright (c) 2013-2014 Digital Bazaar, Inc. + * + * A Forge PEM object has the following fields: + * + * type: identifies the type of message (eg: "RSA PRIVATE KEY"). + * + * procType: identifies the type of processing performed on the message, + * it has two subfields: version and type, eg: 4,ENCRYPTED. + * + * contentDomain: identifies the type of content in the message, typically + * only uses the value: "RFC822". + * + * dekInfo: identifies the message encryption algorithm and mode and includes + * any parameters for the algorithm, it has two subfields: algorithm and + * parameters, eg: DES-CBC,F8143EDE5960C597. + * + * headers: contains all other PEM encapsulated headers -- where order is + * significant (for pairing data like recipient ID + key info). + * + * body: the binary-encoded body. + */ + +var forge$t = forge$D; + + +// shortcut for pem API +var pem = forge$t.pem = forge$t.pem || {}; + +/** + * Encodes (serializes) the given PEM object. + * + * @param msg the PEM message object to encode. + * @param options the options to use: + * maxline the maximum characters per line for the body, (default: 64). + * + * @return the PEM-formatted string. + */ +pem.encode = function(msg, options) { + options = options || {}; + var rval = '-----BEGIN ' + msg.type + '-----\r\n'; + + // encode special headers + var header; + if(msg.procType) { + header = { + name: 'Proc-Type', + values: [String(msg.procType.version), msg.procType.type] + }; + rval += foldHeader(header); + } + if(msg.contentDomain) { + header = {name: 'Content-Domain', values: [msg.contentDomain]}; + rval += foldHeader(header); + } + if(msg.dekInfo) { + header = {name: 'DEK-Info', values: [msg.dekInfo.algorithm]}; + if(msg.dekInfo.parameters) { + header.values.push(msg.dekInfo.parameters); + } + rval += foldHeader(header); + } + + if(msg.headers) { + // encode all other headers + for(var i = 0; i < msg.headers.length; ++i) { + rval += foldHeader(msg.headers[i]); + } + } + + // terminate header + if(msg.procType) { + rval += '\r\n'; + } + + // add body + rval += forge$t.util.encode64(msg.body, options.maxline || 64) + '\r\n'; + + rval += '-----END ' + msg.type + '-----\r\n'; + return rval; +}; + +/** + * Decodes (deserializes) all PEM messages found in the given string. + * + * @param str the PEM-formatted string to decode. + * + * @return the PEM message objects in an array. + */ +pem.decode = function(str) { + var rval = []; + + // split string into PEM messages (be lenient w/EOF on BEGIN line) + var rMessage = /\s*-----BEGIN ([A-Z0-9- ]+)-----\r?\n?([\x21-\x7e\s]+?(?:\r?\n\r?\n))?([:A-Za-z0-9+\/=\s]+?)-----END \1-----/g; + var rHeader = /([\x21-\x7e]+):\s*([\x21-\x7e\s^:]+)/; + var rCRLF = /\r?\n/; + var match; + while(true) { + match = rMessage.exec(str); + if(!match) { + break; + } + + // accept "NEW CERTIFICATE REQUEST" as "CERTIFICATE REQUEST" + // https://datatracker.ietf.org/doc/html/rfc7468#section-7 + var type = match[1]; + if(type === 'NEW CERTIFICATE REQUEST') { + type = 'CERTIFICATE REQUEST'; + } + + var msg = { + type: type, + procType: null, + contentDomain: null, + dekInfo: null, + headers: [], + body: forge$t.util.decode64(match[3]) + }; + rval.push(msg); + + // no headers + if(!match[2]) { + continue; + } + + // parse headers + var lines = match[2].split(rCRLF); + var li = 0; + while(match && li < lines.length) { + // get line, trim any rhs whitespace + var line = lines[li].replace(/\s+$/, ''); + + // RFC2822 unfold any following folded lines + for(var nl = li + 1; nl < lines.length; ++nl) { + var next = lines[nl]; + if(!/\s/.test(next[0])) { + break; + } + line += next; + li = nl; + } + + // parse header + match = line.match(rHeader); + if(match) { + var header = {name: match[1], values: []}; + var values = match[2].split(','); + for(var vi = 0; vi < values.length; ++vi) { + header.values.push(ltrim(values[vi])); + } + + // Proc-Type must be the first header + if(!msg.procType) { + if(header.name !== 'Proc-Type') { + throw new Error('Invalid PEM formatted message. The first ' + + 'encapsulated header must be "Proc-Type".'); + } else if(header.values.length !== 2) { + throw new Error('Invalid PEM formatted message. The "Proc-Type" ' + + 'header must have two subfields.'); + } + msg.procType = {version: values[0], type: values[1]}; + } else if(!msg.contentDomain && header.name === 'Content-Domain') { + // special-case Content-Domain + msg.contentDomain = values[0] || ''; + } else if(!msg.dekInfo && header.name === 'DEK-Info') { + // special-case DEK-Info + if(header.values.length === 0) { + throw new Error('Invalid PEM formatted message. The "DEK-Info" ' + + 'header must have at least one subfield.'); + } + msg.dekInfo = {algorithm: values[0], parameters: values[1] || null}; + } else { + msg.headers.push(header); + } + } + + ++li; + } + + if(msg.procType === 'ENCRYPTED' && !msg.dekInfo) { + throw new Error('Invalid PEM formatted message. The "DEK-Info" ' + + 'header must be present if "Proc-Type" is "ENCRYPTED".'); + } + } + + if(rval.length === 0) { + throw new Error('Invalid PEM formatted message.'); + } + + return rval; +}; + +function foldHeader(header) { + var rval = header.name + ': '; + + // ensure values with CRLF are folded + var values = []; + var insertSpace = function(match, $1) { + return ' ' + $1; + }; + for(var i = 0; i < header.values.length; ++i) { + values.push(header.values[i].replace(/^(\S+\r\n)/, insertSpace)); + } + rval += values.join(',') + '\r\n'; + + // do folding + var length = 0; + var candidate = -1; + for(var i = 0; i < rval.length; ++i, ++length) { + if(length > 65 && candidate !== -1) { + var insert = rval[candidate]; + if(insert === ',') { + ++candidate; + rval = rval.substr(0, candidate) + '\r\n ' + rval.substr(candidate); + } else { + rval = rval.substr(0, candidate) + + '\r\n' + insert + rval.substr(candidate + 1); + } + length = (i - candidate - 1); + candidate = -1; + ++i; + } else if(rval[i] === ' ' || rval[i] === '\t' || rval[i] === ',') { + candidate = i; + } + } + + return rval; +} + +function ltrim(str) { + return str.replace(/^\s+/, ''); +} + +/** + * DES (Data Encryption Standard) implementation. + * + * This implementation supports DES as well as 3DES-EDE in ECB and CBC mode. + * It is based on the BSD-licensed implementation by Paul Tero: + * + * Paul Tero, July 2001 + * http://www.tero.co.uk/des/ + * + * Optimised for performance with large blocks by + * Michael Hayworth, November 2001 + * http://www.netdealing.com + * + * THIS SOFTWARE IS PROVIDED "AS IS" AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * @author Stefan Siegl + * @author Dave Longley + * + * Copyright (c) 2012 Stefan Siegl + * Copyright (c) 2012-2014 Digital Bazaar, Inc. + */ + +var forge$s = forge$D; + + + + +/* DES API */ +forge$s.des = forge$s.des || {}; + +/** + * Deprecated. Instead, use: + * + * var cipher = forge.cipher.createCipher('DES-', key); + * cipher.start({iv: iv}); + * + * Creates an DES cipher object to encrypt data using the given symmetric key. + * The output will be stored in the 'output' member of the returned cipher. + * + * The key and iv may be given as binary-encoded strings of bytes or + * byte buffers. + * + * @param key the symmetric key to use (64 or 192 bits). + * @param iv the initialization vector to use. + * @param output the buffer to write to, null to create one. + * @param mode the cipher mode to use (default: 'CBC' if IV is + * given, 'ECB' if null). + * + * @return the cipher. + */ +forge$s.des.startEncrypting = function(key, iv, output, mode) { + var cipher = _createCipher({ + key: key, + output: output, + decrypt: false, + mode: mode || (iv === null ? 'ECB' : 'CBC') + }); + cipher.start(iv); + return cipher; +}; + +/** + * Deprecated. Instead, use: + * + * var cipher = forge.cipher.createCipher('DES-', key); + * + * Creates an DES cipher object to encrypt data using the given symmetric key. + * + * The key may be given as a binary-encoded string of bytes or a byte buffer. + * + * @param key the symmetric key to use (64 or 192 bits). + * @param mode the cipher mode to use (default: 'CBC'). + * + * @return the cipher. + */ +forge$s.des.createEncryptionCipher = function(key, mode) { + return _createCipher({ + key: key, + output: null, + decrypt: false, + mode: mode + }); +}; + +/** + * Deprecated. Instead, use: + * + * var decipher = forge.cipher.createDecipher('DES-', key); + * decipher.start({iv: iv}); + * + * Creates an DES cipher object to decrypt data using the given symmetric key. + * The output will be stored in the 'output' member of the returned cipher. + * + * The key and iv may be given as binary-encoded strings of bytes or + * byte buffers. + * + * @param key the symmetric key to use (64 or 192 bits). + * @param iv the initialization vector to use. + * @param output the buffer to write to, null to create one. + * @param mode the cipher mode to use (default: 'CBC' if IV is + * given, 'ECB' if null). + * + * @return the cipher. + */ +forge$s.des.startDecrypting = function(key, iv, output, mode) { + var cipher = _createCipher({ + key: key, + output: output, + decrypt: true, + mode: mode || (iv === null ? 'ECB' : 'CBC') + }); + cipher.start(iv); + return cipher; +}; + +/** + * Deprecated. Instead, use: + * + * var decipher = forge.cipher.createDecipher('DES-', key); + * + * Creates an DES cipher object to decrypt data using the given symmetric key. + * + * The key may be given as a binary-encoded string of bytes or a byte buffer. + * + * @param key the symmetric key to use (64 or 192 bits). + * @param mode the cipher mode to use (default: 'CBC'). + * + * @return the cipher. + */ +forge$s.des.createDecryptionCipher = function(key, mode) { + return _createCipher({ + key: key, + output: null, + decrypt: true, + mode: mode + }); +}; + +/** + * Creates a new DES cipher algorithm object. + * + * @param name the name of the algorithm. + * @param mode the mode factory function. + * + * @return the DES algorithm object. + */ +forge$s.des.Algorithm = function(name, mode) { + var self = this; + self.name = name; + self.mode = new mode({ + blockSize: 8, + cipher: { + encrypt: function(inBlock, outBlock) { + return _updateBlock(self._keys, inBlock, outBlock, false); + }, + decrypt: function(inBlock, outBlock) { + return _updateBlock(self._keys, inBlock, outBlock, true); + } + } + }); + self._init = false; +}; + +/** + * Initializes this DES algorithm by expanding its key. + * + * @param options the options to use. + * key the key to use with this algorithm. + * decrypt true if the algorithm should be initialized for decryption, + * false for encryption. + */ +forge$s.des.Algorithm.prototype.initialize = function(options) { + if(this._init) { + return; + } + + var key = forge$s.util.createBuffer(options.key); + if(this.name.indexOf('3DES') === 0) { + if(key.length() !== 24) { + throw new Error('Invalid Triple-DES key size: ' + key.length() * 8); + } + } + + // do key expansion to 16 or 48 subkeys (single or triple DES) + this._keys = _createKeys(key); + this._init = true; +}; + +/** Register DES algorithms **/ + +registerAlgorithm('DES-ECB', forge$s.cipher.modes.ecb); +registerAlgorithm('DES-CBC', forge$s.cipher.modes.cbc); +registerAlgorithm('DES-CFB', forge$s.cipher.modes.cfb); +registerAlgorithm('DES-OFB', forge$s.cipher.modes.ofb); +registerAlgorithm('DES-CTR', forge$s.cipher.modes.ctr); + +registerAlgorithm('3DES-ECB', forge$s.cipher.modes.ecb); +registerAlgorithm('3DES-CBC', forge$s.cipher.modes.cbc); +registerAlgorithm('3DES-CFB', forge$s.cipher.modes.cfb); +registerAlgorithm('3DES-OFB', forge$s.cipher.modes.ofb); +registerAlgorithm('3DES-CTR', forge$s.cipher.modes.ctr); + +function registerAlgorithm(name, mode) { + var factory = function() { + return new forge$s.des.Algorithm(name, mode); + }; + forge$s.cipher.registerAlgorithm(name, factory); +} + +/** DES implementation **/ + +var spfunction1 = [0x1010400,0,0x10000,0x1010404,0x1010004,0x10404,0x4,0x10000,0x400,0x1010400,0x1010404,0x400,0x1000404,0x1010004,0x1000000,0x4,0x404,0x1000400,0x1000400,0x10400,0x10400,0x1010000,0x1010000,0x1000404,0x10004,0x1000004,0x1000004,0x10004,0,0x404,0x10404,0x1000000,0x10000,0x1010404,0x4,0x1010000,0x1010400,0x1000000,0x1000000,0x400,0x1010004,0x10000,0x10400,0x1000004,0x400,0x4,0x1000404,0x10404,0x1010404,0x10004,0x1010000,0x1000404,0x1000004,0x404,0x10404,0x1010400,0x404,0x1000400,0x1000400,0,0x10004,0x10400,0,0x1010004]; +var spfunction2 = [-0x7fef7fe0,-0x7fff8000,0x8000,0x108020,0x100000,0x20,-0x7fefffe0,-0x7fff7fe0,-0x7fffffe0,-0x7fef7fe0,-0x7fef8000,-0x80000000,-0x7fff8000,0x100000,0x20,-0x7fefffe0,0x108000,0x100020,-0x7fff7fe0,0,-0x80000000,0x8000,0x108020,-0x7ff00000,0x100020,-0x7fffffe0,0,0x108000,0x8020,-0x7fef8000,-0x7ff00000,0x8020,0,0x108020,-0x7fefffe0,0x100000,-0x7fff7fe0,-0x7ff00000,-0x7fef8000,0x8000,-0x7ff00000,-0x7fff8000,0x20,-0x7fef7fe0,0x108020,0x20,0x8000,-0x80000000,0x8020,-0x7fef8000,0x100000,-0x7fffffe0,0x100020,-0x7fff7fe0,-0x7fffffe0,0x100020,0x108000,0,-0x7fff8000,0x8020,-0x80000000,-0x7fefffe0,-0x7fef7fe0,0x108000]; +var spfunction3 = [0x208,0x8020200,0,0x8020008,0x8000200,0,0x20208,0x8000200,0x20008,0x8000008,0x8000008,0x20000,0x8020208,0x20008,0x8020000,0x208,0x8000000,0x8,0x8020200,0x200,0x20200,0x8020000,0x8020008,0x20208,0x8000208,0x20200,0x20000,0x8000208,0x8,0x8020208,0x200,0x8000000,0x8020200,0x8000000,0x20008,0x208,0x20000,0x8020200,0x8000200,0,0x200,0x20008,0x8020208,0x8000200,0x8000008,0x200,0,0x8020008,0x8000208,0x20000,0x8000000,0x8020208,0x8,0x20208,0x20200,0x8000008,0x8020000,0x8000208,0x208,0x8020000,0x20208,0x8,0x8020008,0x20200]; +var spfunction4 = [0x802001,0x2081,0x2081,0x80,0x802080,0x800081,0x800001,0x2001,0,0x802000,0x802000,0x802081,0x81,0,0x800080,0x800001,0x1,0x2000,0x800000,0x802001,0x80,0x800000,0x2001,0x2080,0x800081,0x1,0x2080,0x800080,0x2000,0x802080,0x802081,0x81,0x800080,0x800001,0x802000,0x802081,0x81,0,0,0x802000,0x2080,0x800080,0x800081,0x1,0x802001,0x2081,0x2081,0x80,0x802081,0x81,0x1,0x2000,0x800001,0x2001,0x802080,0x800081,0x2001,0x2080,0x800000,0x802001,0x80,0x800000,0x2000,0x802080]; +var spfunction5 = [0x100,0x2080100,0x2080000,0x42000100,0x80000,0x100,0x40000000,0x2080000,0x40080100,0x80000,0x2000100,0x40080100,0x42000100,0x42080000,0x80100,0x40000000,0x2000000,0x40080000,0x40080000,0,0x40000100,0x42080100,0x42080100,0x2000100,0x42080000,0x40000100,0,0x42000000,0x2080100,0x2000000,0x42000000,0x80100,0x80000,0x42000100,0x100,0x2000000,0x40000000,0x2080000,0x42000100,0x40080100,0x2000100,0x40000000,0x42080000,0x2080100,0x40080100,0x100,0x2000000,0x42080000,0x42080100,0x80100,0x42000000,0x42080100,0x2080000,0,0x40080000,0x42000000,0x80100,0x2000100,0x40000100,0x80000,0,0x40080000,0x2080100,0x40000100]; +var spfunction6 = [0x20000010,0x20400000,0x4000,0x20404010,0x20400000,0x10,0x20404010,0x400000,0x20004000,0x404010,0x400000,0x20000010,0x400010,0x20004000,0x20000000,0x4010,0,0x400010,0x20004010,0x4000,0x404000,0x20004010,0x10,0x20400010,0x20400010,0,0x404010,0x20404000,0x4010,0x404000,0x20404000,0x20000000,0x20004000,0x10,0x20400010,0x404000,0x20404010,0x400000,0x4010,0x20000010,0x400000,0x20004000,0x20000000,0x4010,0x20000010,0x20404010,0x404000,0x20400000,0x404010,0x20404000,0,0x20400010,0x10,0x4000,0x20400000,0x404010,0x4000,0x400010,0x20004010,0,0x20404000,0x20000000,0x400010,0x20004010]; +var spfunction7 = [0x200000,0x4200002,0x4000802,0,0x800,0x4000802,0x200802,0x4200800,0x4200802,0x200000,0,0x4000002,0x2,0x4000000,0x4200002,0x802,0x4000800,0x200802,0x200002,0x4000800,0x4000002,0x4200000,0x4200800,0x200002,0x4200000,0x800,0x802,0x4200802,0x200800,0x2,0x4000000,0x200800,0x4000000,0x200800,0x200000,0x4000802,0x4000802,0x4200002,0x4200002,0x2,0x200002,0x4000000,0x4000800,0x200000,0x4200800,0x802,0x200802,0x4200800,0x802,0x4000002,0x4200802,0x4200000,0x200800,0,0x2,0x4200802,0,0x200802,0x4200000,0x800,0x4000002,0x4000800,0x800,0x200002]; +var spfunction8 = [0x10001040,0x1000,0x40000,0x10041040,0x10000000,0x10001040,0x40,0x10000000,0x40040,0x10040000,0x10041040,0x41000,0x10041000,0x41040,0x1000,0x40,0x10040000,0x10000040,0x10001000,0x1040,0x41000,0x40040,0x10040040,0x10041000,0x1040,0,0,0x10040040,0x10000040,0x10001000,0x41040,0x40000,0x41040,0x40000,0x10041000,0x1000,0x40,0x10040040,0x1000,0x41040,0x10001000,0x40,0x10000040,0x10040000,0x10040040,0x10000000,0x40000,0x10001040,0,0x10041040,0x40040,0x10000040,0x10040000,0x10001000,0x10001040,0,0x10041040,0x41000,0x41000,0x1040,0x1040,0x40040,0x10000000,0x10041000]; + +/** + * Create necessary sub keys. + * + * @param key the 64-bit or 192-bit key. + * + * @return the expanded keys. + */ +function _createKeys(key) { + var pc2bytes0 = [0,0x4,0x20000000,0x20000004,0x10000,0x10004,0x20010000,0x20010004,0x200,0x204,0x20000200,0x20000204,0x10200,0x10204,0x20010200,0x20010204], + pc2bytes1 = [0,0x1,0x100000,0x100001,0x4000000,0x4000001,0x4100000,0x4100001,0x100,0x101,0x100100,0x100101,0x4000100,0x4000101,0x4100100,0x4100101], + pc2bytes2 = [0,0x8,0x800,0x808,0x1000000,0x1000008,0x1000800,0x1000808,0,0x8,0x800,0x808,0x1000000,0x1000008,0x1000800,0x1000808], + pc2bytes3 = [0,0x200000,0x8000000,0x8200000,0x2000,0x202000,0x8002000,0x8202000,0x20000,0x220000,0x8020000,0x8220000,0x22000,0x222000,0x8022000,0x8222000], + pc2bytes4 = [0,0x40000,0x10,0x40010,0,0x40000,0x10,0x40010,0x1000,0x41000,0x1010,0x41010,0x1000,0x41000,0x1010,0x41010], + pc2bytes5 = [0,0x400,0x20,0x420,0,0x400,0x20,0x420,0x2000000,0x2000400,0x2000020,0x2000420,0x2000000,0x2000400,0x2000020,0x2000420], + pc2bytes6 = [0,0x10000000,0x80000,0x10080000,0x2,0x10000002,0x80002,0x10080002,0,0x10000000,0x80000,0x10080000,0x2,0x10000002,0x80002,0x10080002], + pc2bytes7 = [0,0x10000,0x800,0x10800,0x20000000,0x20010000,0x20000800,0x20010800,0x20000,0x30000,0x20800,0x30800,0x20020000,0x20030000,0x20020800,0x20030800], + pc2bytes8 = [0,0x40000,0,0x40000,0x2,0x40002,0x2,0x40002,0x2000000,0x2040000,0x2000000,0x2040000,0x2000002,0x2040002,0x2000002,0x2040002], + pc2bytes9 = [0,0x10000000,0x8,0x10000008,0,0x10000000,0x8,0x10000008,0x400,0x10000400,0x408,0x10000408,0x400,0x10000400,0x408,0x10000408], + pc2bytes10 = [0,0x20,0,0x20,0x100000,0x100020,0x100000,0x100020,0x2000,0x2020,0x2000,0x2020,0x102000,0x102020,0x102000,0x102020], + pc2bytes11 = [0,0x1000000,0x200,0x1000200,0x200000,0x1200000,0x200200,0x1200200,0x4000000,0x5000000,0x4000200,0x5000200,0x4200000,0x5200000,0x4200200,0x5200200], + pc2bytes12 = [0,0x1000,0x8000000,0x8001000,0x80000,0x81000,0x8080000,0x8081000,0x10,0x1010,0x8000010,0x8001010,0x80010,0x81010,0x8080010,0x8081010], + pc2bytes13 = [0,0x4,0x100,0x104,0,0x4,0x100,0x104,0x1,0x5,0x101,0x105,0x1,0x5,0x101,0x105]; + + // how many iterations (1 for des, 3 for triple des) + // changed by Paul 16/6/2007 to use Triple DES for 9+ byte keys + var iterations = key.length() > 8 ? 3 : 1; + + // stores the return keys + var keys = []; + + // now define the left shifts which need to be done + var shifts = [0, 0, 1, 1, 1, 1, 1, 1, 0, 1, 1, 1, 1, 1, 1, 0]; + + var n = 0, tmp; + for(var j = 0; j < iterations; j++) { + var left = key.getInt32(); + var right = key.getInt32(); + + tmp = ((left >>> 4) ^ right) & 0x0f0f0f0f; + right ^= tmp; + left ^= (tmp << 4); + + tmp = ((right >>> -16) ^ left) & 0x0000ffff; + left ^= tmp; + right ^= (tmp << -16); + + tmp = ((left >>> 2) ^ right) & 0x33333333; + right ^= tmp; + left ^= (tmp << 2); + + tmp = ((right >>> -16) ^ left) & 0x0000ffff; + left ^= tmp; + right ^= (tmp << -16); + + tmp = ((left >>> 1) ^ right) & 0x55555555; + right ^= tmp; + left ^= (tmp << 1); + + tmp = ((right >>> 8) ^ left) & 0x00ff00ff; + left ^= tmp; + right ^= (tmp << 8); + + tmp = ((left >>> 1) ^ right) & 0x55555555; + right ^= tmp; + left ^= (tmp << 1); + + // right needs to be shifted and OR'd with last four bits of left + tmp = (left << 8) | ((right >>> 20) & 0x000000f0); + + // left needs to be put upside down + left = ((right << 24) | ((right << 8) & 0xff0000) | + ((right >>> 8) & 0xff00) | ((right >>> 24) & 0xf0)); + right = tmp; + + // now go through and perform these shifts on the left and right keys + for(var i = 0; i < shifts.length; ++i) { + //shift the keys either one or two bits to the left + if(shifts[i]) { + left = (left << 2) | (left >>> 26); + right = (right << 2) | (right >>> 26); + } else { + left = (left << 1) | (left >>> 27); + right = (right << 1) | (right >>> 27); + } + left &= -0xf; + right &= -0xf; + + // now apply PC-2, in such a way that E is easier when encrypting or + // decrypting this conversion will look like PC-2 except only the last 6 + // bits of each byte are used rather than 48 consecutive bits and the + // order of lines will be according to how the S selection functions will + // be applied: S2, S4, S6, S8, S1, S3, S5, S7 + var lefttmp = ( + pc2bytes0[left >>> 28] | pc2bytes1[(left >>> 24) & 0xf] | + pc2bytes2[(left >>> 20) & 0xf] | pc2bytes3[(left >>> 16) & 0xf] | + pc2bytes4[(left >>> 12) & 0xf] | pc2bytes5[(left >>> 8) & 0xf] | + pc2bytes6[(left >>> 4) & 0xf]); + var righttmp = ( + pc2bytes7[right >>> 28] | pc2bytes8[(right >>> 24) & 0xf] | + pc2bytes9[(right >>> 20) & 0xf] | pc2bytes10[(right >>> 16) & 0xf] | + pc2bytes11[(right >>> 12) & 0xf] | pc2bytes12[(right >>> 8) & 0xf] | + pc2bytes13[(right >>> 4) & 0xf]); + tmp = ((righttmp >>> 16) ^ lefttmp) & 0x0000ffff; + keys[n++] = lefttmp ^ tmp; + keys[n++] = righttmp ^ (tmp << 16); + } + } + + return keys; +} + +/** + * Updates a single block (1 byte) using DES. The update will either + * encrypt or decrypt the block. + * + * @param keys the expanded keys. + * @param input the input block (an array of 32-bit words). + * @param output the updated output block. + * @param decrypt true to decrypt the block, false to encrypt it. + */ +function _updateBlock(keys, input, output, decrypt) { + // set up loops for single or triple DES + var iterations = keys.length === 32 ? 3 : 9; + var looping; + if(iterations === 3) { + looping = decrypt ? [30, -2, -2] : [0, 32, 2]; + } else { + looping = (decrypt ? + [94, 62, -2, 32, 64, 2, 30, -2, -2] : + [0, 32, 2, 62, 30, -2, 64, 96, 2]); + } + + var tmp; + + var left = input[0]; + var right = input[1]; + + // first each 64 bit chunk of the message must be permuted according to IP + tmp = ((left >>> 4) ^ right) & 0x0f0f0f0f; + right ^= tmp; + left ^= (tmp << 4); + + tmp = ((left >>> 16) ^ right) & 0x0000ffff; + right ^= tmp; + left ^= (tmp << 16); + + tmp = ((right >>> 2) ^ left) & 0x33333333; + left ^= tmp; + right ^= (tmp << 2); + + tmp = ((right >>> 8) ^ left) & 0x00ff00ff; + left ^= tmp; + right ^= (tmp << 8); + + tmp = ((left >>> 1) ^ right) & 0x55555555; + right ^= tmp; + left ^= (tmp << 1); + + // rotate left 1 bit + left = ((left << 1) | (left >>> 31)); + right = ((right << 1) | (right >>> 31)); + + for(var j = 0; j < iterations; j += 3) { + var endloop = looping[j + 1]; + var loopinc = looping[j + 2]; + + // now go through and perform the encryption or decryption + for(var i = looping[j]; i != endloop; i += loopinc) { + var right1 = right ^ keys[i]; + var right2 = ((right >>> 4) | (right << 28)) ^ keys[i + 1]; + + // passing these bytes through the S selection functions + tmp = left; + left = right; + right = tmp ^ ( + spfunction2[(right1 >>> 24) & 0x3f] | + spfunction4[(right1 >>> 16) & 0x3f] | + spfunction6[(right1 >>> 8) & 0x3f] | + spfunction8[right1 & 0x3f] | + spfunction1[(right2 >>> 24) & 0x3f] | + spfunction3[(right2 >>> 16) & 0x3f] | + spfunction5[(right2 >>> 8) & 0x3f] | + spfunction7[right2 & 0x3f]); + } + // unreverse left and right + tmp = left; + left = right; + right = tmp; + } + + // rotate right 1 bit + left = ((left >>> 1) | (left << 31)); + right = ((right >>> 1) | (right << 31)); + + // now perform IP-1, which is IP in the opposite direction + tmp = ((left >>> 1) ^ right) & 0x55555555; + right ^= tmp; + left ^= (tmp << 1); + + tmp = ((right >>> 8) ^ left) & 0x00ff00ff; + left ^= tmp; + right ^= (tmp << 8); + + tmp = ((right >>> 2) ^ left) & 0x33333333; + left ^= tmp; + right ^= (tmp << 2); + + tmp = ((left >>> 16) ^ right) & 0x0000ffff; + right ^= tmp; + left ^= (tmp << 16); + + tmp = ((left >>> 4) ^ right) & 0x0f0f0f0f; + right ^= tmp; + left ^= (tmp << 4); + + output[0] = left; + output[1] = right; +} + +/** + * Deprecated. Instead, use: + * + * forge.cipher.createCipher('DES-', key); + * forge.cipher.createDecipher('DES-', key); + * + * Creates a deprecated DES cipher object. This object's mode will default to + * CBC (cipher-block-chaining). + * + * The key may be given as a binary-encoded string of bytes or a byte buffer. + * + * @param options the options to use. + * key the symmetric key to use (64 or 192 bits). + * output the buffer to write to. + * decrypt true for decryption, false for encryption. + * mode the cipher mode to use (default: 'CBC'). + * + * @return the cipher. + */ +function _createCipher(options) { + options = options || {}; + var mode = (options.mode || 'CBC').toUpperCase(); + var algorithm = 'DES-' + mode; + + var cipher; + if(options.decrypt) { + cipher = forge$s.cipher.createDecipher(algorithm, options.key); + } else { + cipher = forge$s.cipher.createCipher(algorithm, options.key); + } + + // backwards compatible start API + var start = cipher.start; + cipher.start = function(iv, options) { + // backwards compatibility: support second arg as output buffer + var output = null; + if(options instanceof forge$s.util.ByteBuffer) { + output = options; + options = {}; + } + options = options || {}; + options.output = output; + options.iv = iv; + start.call(cipher, options); + }; + + return cipher; +} + +/** + * Password-Based Key-Derivation Function #2 implementation. + * + * See RFC 2898 for details. + * + * @author Dave Longley + * + * Copyright (c) 2010-2013 Digital Bazaar, Inc. + */ + +var forge$r = forge$D; + + + + +var pkcs5 = forge$r.pkcs5 = forge$r.pkcs5 || {}; + +var crypto; +if(forge$r.util.isNodejs && !forge$r.options.usePureJavaScript) { + crypto = require$$1$1; +} + +/** + * Derives a key from a password. + * + * @param p the password as a binary-encoded string of bytes. + * @param s the salt as a binary-encoded string of bytes. + * @param c the iteration count, a positive integer. + * @param dkLen the intended length, in bytes, of the derived key, + * (max: 2^32 - 1) * hash length of the PRF. + * @param [md] the message digest (or algorithm identifier as a string) to use + * in the PRF, defaults to SHA-1. + * @param [callback(err, key)] presence triggers asynchronous version, called + * once the operation completes. + * + * @return the derived key, as a binary-encoded string of bytes, for the + * synchronous version (if no callback is specified). + */ +forge$r.pbkdf2 = pkcs5.pbkdf2 = function( + p, s, c, dkLen, md, callback) { + if(typeof md === 'function') { + callback = md; + md = null; + } + + // use native implementation if possible and not disabled, note that + // some node versions only support SHA-1, others allow digest to be changed + if(forge$r.util.isNodejs && !forge$r.options.usePureJavaScript && + crypto.pbkdf2 && (md === null || typeof md !== 'object') && + (crypto.pbkdf2Sync.length > 4 || (!md || md === 'sha1'))) { + if(typeof md !== 'string') { + // default prf to SHA-1 + md = 'sha1'; + } + p = Buffer.from(p, 'binary'); + s = Buffer.from(s, 'binary'); + if(!callback) { + if(crypto.pbkdf2Sync.length === 4) { + return crypto.pbkdf2Sync(p, s, c, dkLen).toString('binary'); + } + return crypto.pbkdf2Sync(p, s, c, dkLen, md).toString('binary'); + } + if(crypto.pbkdf2Sync.length === 4) { + return crypto.pbkdf2(p, s, c, dkLen, function(err, key) { + if(err) { + return callback(err); + } + callback(null, key.toString('binary')); + }); + } + return crypto.pbkdf2(p, s, c, dkLen, md, function(err, key) { + if(err) { + return callback(err); + } + callback(null, key.toString('binary')); + }); + } + + if(typeof md === 'undefined' || md === null) { + // default prf to SHA-1 + md = 'sha1'; + } + if(typeof md === 'string') { + if(!(md in forge$r.md.algorithms)) { + throw new Error('Unknown hash algorithm: ' + md); + } + md = forge$r.md[md].create(); + } + + var hLen = md.digestLength; + + /* 1. If dkLen > (2^32 - 1) * hLen, output "derived key too long" and + stop. */ + if(dkLen > (0xFFFFFFFF * hLen)) { + var err = new Error('Derived key is too long.'); + if(callback) { + return callback(err); + } + throw err; + } + + /* 2. Let len be the number of hLen-octet blocks in the derived key, + rounding up, and let r be the number of octets in the last + block: + + len = CEIL(dkLen / hLen), + r = dkLen - (len - 1) * hLen. */ + var len = Math.ceil(dkLen / hLen); + var r = dkLen - (len - 1) * hLen; + + /* 3. For each block of the derived key apply the function F defined + below to the password P, the salt S, the iteration count c, and + the block index to compute the block: + + T_1 = F(P, S, c, 1), + T_2 = F(P, S, c, 2), + ... + T_len = F(P, S, c, len), + + where the function F is defined as the exclusive-or sum of the + first c iterates of the underlying pseudorandom function PRF + applied to the password P and the concatenation of the salt S + and the block index i: + + F(P, S, c, i) = u_1 XOR u_2 XOR ... XOR u_c + + where + + u_1 = PRF(P, S || INT(i)), + u_2 = PRF(P, u_1), + ... + u_c = PRF(P, u_{c-1}). + + Here, INT(i) is a four-octet encoding of the integer i, most + significant octet first. */ + var prf = forge$r.hmac.create(); + prf.start(md, p); + var dk = ''; + var xor, u_c, u_c1; + + // sync version + if(!callback) { + for(var i = 1; i <= len; ++i) { + // PRF(P, S || INT(i)) (first iteration) + prf.start(null, null); + prf.update(s); + prf.update(forge$r.util.int32ToBytes(i)); + xor = u_c1 = prf.digest().getBytes(); + + // PRF(P, u_{c-1}) (other iterations) + for(var j = 2; j <= c; ++j) { + prf.start(null, null); + prf.update(u_c1); + u_c = prf.digest().getBytes(); + // F(p, s, c, i) + xor = forge$r.util.xorBytes(xor, u_c, hLen); + u_c1 = u_c; + } + + /* 4. Concatenate the blocks and extract the first dkLen octets to + produce a derived key DK: + + DK = T_1 || T_2 || ... || T_len<0..r-1> */ + dk += (i < len) ? xor : xor.substr(0, r); + } + /* 5. Output the derived key DK. */ + return dk; + } + + // async version + var i = 1, j; + function outer() { + if(i > len) { + // done + return callback(null, dk); + } + + // PRF(P, S || INT(i)) (first iteration) + prf.start(null, null); + prf.update(s); + prf.update(forge$r.util.int32ToBytes(i)); + xor = u_c1 = prf.digest().getBytes(); + + // PRF(P, u_{c-1}) (other iterations) + j = 2; + inner(); + } + + function inner() { + if(j <= c) { + prf.start(null, null); + prf.update(u_c1); + u_c = prf.digest().getBytes(); + // F(p, s, c, i) + xor = forge$r.util.xorBytes(xor, u_c, hLen); + u_c1 = u_c; + ++j; + return forge$r.util.setImmediate(inner); + } + + /* 4. Concatenate the blocks and extract the first dkLen octets to + produce a derived key DK: + + DK = T_1 || T_2 || ... || T_len<0..r-1> */ + dk += (i < len) ? xor : xor.substr(0, r); + + ++i; + outer(); + } + + outer(); +}; + +/** + * Secure Hash Algorithm with 256-bit digest (SHA-256) implementation. + * + * See FIPS 180-2 for details. + * + * @author Dave Longley + * + * Copyright (c) 2010-2015 Digital Bazaar, Inc. + */ + +var forge$q = forge$D; + + + +var sha256 = forge$q.sha256 = forge$q.sha256 || {}; +forge$q.md.sha256 = forge$q.md.algorithms.sha256 = sha256; + +/** + * Creates a SHA-256 message digest object. + * + * @return a message digest object. + */ +sha256.create = function() { + // do initialization as necessary + if(!_initialized$2) { + _init$2(); + } + + // SHA-256 state contains eight 32-bit integers + var _state = null; + + // input buffer + var _input = forge$q.util.createBuffer(); + + // used for word storage + var _w = new Array(64); + + // message digest object + var md = { + algorithm: 'sha256', + blockLength: 64, + digestLength: 32, + // 56-bit length of message so far (does not including padding) + messageLength: 0, + // true message length + fullMessageLength: null, + // size of message length in bytes + messageLengthSize: 8 + }; + + /** + * Starts the digest. + * + * @return this digest object. + */ + md.start = function() { + // up to 56-bit message length for convenience + md.messageLength = 0; + + // full message length (set md.messageLength64 for backwards-compatibility) + md.fullMessageLength = md.messageLength64 = []; + var int32s = md.messageLengthSize / 4; + for(var i = 0; i < int32s; ++i) { + md.fullMessageLength.push(0); + } + _input = forge$q.util.createBuffer(); + _state = { + h0: 0x6A09E667, + h1: 0xBB67AE85, + h2: 0x3C6EF372, + h3: 0xA54FF53A, + h4: 0x510E527F, + h5: 0x9B05688C, + h6: 0x1F83D9AB, + h7: 0x5BE0CD19 + }; + return md; + }; + // start digest automatically for first time + md.start(); + + /** + * Updates the digest with the given message input. The given input can + * treated as raw input (no encoding will be applied) or an encoding of + * 'utf8' maybe given to encode the input using UTF-8. + * + * @param msg the message input to update with. + * @param encoding the encoding to use (default: 'raw', other: 'utf8'). + * + * @return this digest object. + */ + md.update = function(msg, encoding) { + if(encoding === 'utf8') { + msg = forge$q.util.encodeUtf8(msg); + } + + // update message length + var len = msg.length; + md.messageLength += len; + len = [(len / 0x100000000) >>> 0, len >>> 0]; + for(var i = md.fullMessageLength.length - 1; i >= 0; --i) { + md.fullMessageLength[i] += len[1]; + len[1] = len[0] + ((md.fullMessageLength[i] / 0x100000000) >>> 0); + md.fullMessageLength[i] = md.fullMessageLength[i] >>> 0; + len[0] = ((len[1] / 0x100000000) >>> 0); + } + + // add bytes to input buffer + _input.putBytes(msg); + + // process bytes + _update$2(_state, _w, _input); + + // compact input buffer every 2K or if empty + if(_input.read > 2048 || _input.length() === 0) { + _input.compact(); + } + + return md; + }; + + /** + * Produces the digest. + * + * @return a byte buffer containing the digest value. + */ + md.digest = function() { + /* Note: Here we copy the remaining bytes in the input buffer and + add the appropriate SHA-256 padding. Then we do the final update + on a copy of the state so that if the user wants to get + intermediate digests they can do so. */ + + /* Determine the number of bytes that must be added to the message + to ensure its length is congruent to 448 mod 512. In other words, + the data to be digested must be a multiple of 512 bits (or 128 bytes). + This data includes the message, some padding, and the length of the + message. Since the length of the message will be encoded as 8 bytes (64 + bits), that means that the last segment of the data must have 56 bytes + (448 bits) of message and padding. Therefore, the length of the message + plus the padding must be congruent to 448 mod 512 because + 512 - 128 = 448. + + In order to fill up the message length it must be filled with + padding that begins with 1 bit followed by all 0 bits. Padding + must *always* be present, so if the message length is already + congruent to 448 mod 512, then 512 padding bits must be added. */ + + var finalBlock = forge$q.util.createBuffer(); + finalBlock.putBytes(_input.bytes()); + + // compute remaining size to be digested (include message length size) + var remaining = ( + md.fullMessageLength[md.fullMessageLength.length - 1] + + md.messageLengthSize); + + // add padding for overflow blockSize - overflow + // _padding starts with 1 byte with first bit is set (byte value 128), then + // there may be up to (blockSize - 1) other pad bytes + var overflow = remaining & (md.blockLength - 1); + finalBlock.putBytes(_padding$2.substr(0, md.blockLength - overflow)); + + // serialize message length in bits in big-endian order; since length + // is stored in bytes we multiply by 8 and add carry from next int + var next, carry; + var bits = md.fullMessageLength[0] * 8; + for(var i = 0; i < md.fullMessageLength.length - 1; ++i) { + next = md.fullMessageLength[i + 1] * 8; + carry = (next / 0x100000000) >>> 0; + bits += carry; + finalBlock.putInt32(bits >>> 0); + bits = next >>> 0; + } + finalBlock.putInt32(bits); + + var s2 = { + h0: _state.h0, + h1: _state.h1, + h2: _state.h2, + h3: _state.h3, + h4: _state.h4, + h5: _state.h5, + h6: _state.h6, + h7: _state.h7 + }; + _update$2(s2, _w, finalBlock); + var rval = forge$q.util.createBuffer(); + rval.putInt32(s2.h0); + rval.putInt32(s2.h1); + rval.putInt32(s2.h2); + rval.putInt32(s2.h3); + rval.putInt32(s2.h4); + rval.putInt32(s2.h5); + rval.putInt32(s2.h6); + rval.putInt32(s2.h7); + return rval; + }; + + return md; +}; + +// sha-256 padding bytes not initialized yet +var _padding$2 = null; +var _initialized$2 = false; + +// table of constants +var _k$1 = null; + +/** + * Initializes the constant tables. + */ +function _init$2() { + // create padding + _padding$2 = String.fromCharCode(128); + _padding$2 += forge$q.util.fillString(String.fromCharCode(0x00), 64); + + // create K table for SHA-256 + _k$1 = [ + 0x428a2f98, 0x71374491, 0xb5c0fbcf, 0xe9b5dba5, + 0x3956c25b, 0x59f111f1, 0x923f82a4, 0xab1c5ed5, + 0xd807aa98, 0x12835b01, 0x243185be, 0x550c7dc3, + 0x72be5d74, 0x80deb1fe, 0x9bdc06a7, 0xc19bf174, + 0xe49b69c1, 0xefbe4786, 0x0fc19dc6, 0x240ca1cc, + 0x2de92c6f, 0x4a7484aa, 0x5cb0a9dc, 0x76f988da, + 0x983e5152, 0xa831c66d, 0xb00327c8, 0xbf597fc7, + 0xc6e00bf3, 0xd5a79147, 0x06ca6351, 0x14292967, + 0x27b70a85, 0x2e1b2138, 0x4d2c6dfc, 0x53380d13, + 0x650a7354, 0x766a0abb, 0x81c2c92e, 0x92722c85, + 0xa2bfe8a1, 0xa81a664b, 0xc24b8b70, 0xc76c51a3, + 0xd192e819, 0xd6990624, 0xf40e3585, 0x106aa070, + 0x19a4c116, 0x1e376c08, 0x2748774c, 0x34b0bcb5, + 0x391c0cb3, 0x4ed8aa4a, 0x5b9cca4f, 0x682e6ff3, + 0x748f82ee, 0x78a5636f, 0x84c87814, 0x8cc70208, + 0x90befffa, 0xa4506ceb, 0xbef9a3f7, 0xc67178f2]; + + // now initialized + _initialized$2 = true; +} + +/** + * Updates a SHA-256 state with the given byte buffer. + * + * @param s the SHA-256 state to update. + * @param w the array to use to store words. + * @param bytes the byte buffer to update with. + */ +function _update$2(s, w, bytes) { + // consume 512 bit (64 byte) chunks + var t1, t2, s0, s1, ch, maj, i, a, b, c, d, e, f, g, h; + var len = bytes.length(); + while(len >= 64) { + // the w array will be populated with sixteen 32-bit big-endian words + // and then extended into 64 32-bit words according to SHA-256 + for(i = 0; i < 16; ++i) { + w[i] = bytes.getInt32(); + } + for(; i < 64; ++i) { + // XOR word 2 words ago rot right 17, rot right 19, shft right 10 + t1 = w[i - 2]; + t1 = + ((t1 >>> 17) | (t1 << 15)) ^ + ((t1 >>> 19) | (t1 << 13)) ^ + (t1 >>> 10); + // XOR word 15 words ago rot right 7, rot right 18, shft right 3 + t2 = w[i - 15]; + t2 = + ((t2 >>> 7) | (t2 << 25)) ^ + ((t2 >>> 18) | (t2 << 14)) ^ + (t2 >>> 3); + // sum(t1, word 7 ago, t2, word 16 ago) modulo 2^32 + w[i] = (t1 + w[i - 7] + t2 + w[i - 16]) | 0; + } + + // initialize hash value for this chunk + a = s.h0; + b = s.h1; + c = s.h2; + d = s.h3; + e = s.h4; + f = s.h5; + g = s.h6; + h = s.h7; + + // round function + for(i = 0; i < 64; ++i) { + // Sum1(e) + s1 = + ((e >>> 6) | (e << 26)) ^ + ((e >>> 11) | (e << 21)) ^ + ((e >>> 25) | (e << 7)); + // Ch(e, f, g) (optimized the same way as SHA-1) + ch = g ^ (e & (f ^ g)); + // Sum0(a) + s0 = + ((a >>> 2) | (a << 30)) ^ + ((a >>> 13) | (a << 19)) ^ + ((a >>> 22) | (a << 10)); + // Maj(a, b, c) (optimized the same way as SHA-1) + maj = (a & b) | (c & (a ^ b)); + + // main algorithm + t1 = h + s1 + ch + _k$1[i] + w[i]; + t2 = s0 + maj; + h = g; + g = f; + f = e; + // `>>> 0` necessary to avoid iOS/Safari 10 optimization bug + // can't truncate with `| 0` + e = (d + t1) >>> 0; + d = c; + c = b; + b = a; + // `>>> 0` necessary to avoid iOS/Safari 10 optimization bug + // can't truncate with `| 0` + a = (t1 + t2) >>> 0; + } + + // update hash state + s.h0 = (s.h0 + a) | 0; + s.h1 = (s.h1 + b) | 0; + s.h2 = (s.h2 + c) | 0; + s.h3 = (s.h3 + d) | 0; + s.h4 = (s.h4 + e) | 0; + s.h5 = (s.h5 + f) | 0; + s.h6 = (s.h6 + g) | 0; + s.h7 = (s.h7 + h) | 0; + len -= 64; + } +} + +/** + * A javascript implementation of a cryptographically-secure + * Pseudo Random Number Generator (PRNG). The Fortuna algorithm is followed + * here though the use of SHA-256 is not enforced; when generating an + * a PRNG context, the hashing algorithm and block cipher used for + * the generator are specified via a plugin. + * + * @author Dave Longley + * + * Copyright (c) 2010-2014 Digital Bazaar, Inc. + */ + +var forge$p = forge$D; + + +var _crypto$1 = null; +if(forge$p.util.isNodejs && !forge$p.options.usePureJavaScript && + !process.versions['node-webkit']) { + _crypto$1 = require$$1$1; +} + +/* PRNG API */ +var prng = forge$p.prng = forge$p.prng || {}; + +/** + * Creates a new PRNG context. + * + * A PRNG plugin must be passed in that will provide: + * + * 1. A function that initializes the key and seed of a PRNG context. It + * will be given a 16 byte key and a 16 byte seed. Any key expansion + * or transformation of the seed from a byte string into an array of + * integers (or similar) should be performed. + * 2. The cryptographic function used by the generator. It takes a key and + * a seed. + * 3. A seed increment function. It takes the seed and returns seed + 1. + * 4. An api to create a message digest. + * + * For an example, see random.js. + * + * @param plugin the PRNG plugin to use. + */ +prng.create = function(plugin) { + var ctx = { + plugin: plugin, + key: null, + seed: null, + time: null, + // number of reseeds so far + reseeds: 0, + // amount of data generated so far + generated: 0, + // no initial key bytes + keyBytes: '' + }; + + // create 32 entropy pools (each is a message digest) + var md = plugin.md; + var pools = new Array(32); + for(var i = 0; i < 32; ++i) { + pools[i] = md.create(); + } + ctx.pools = pools; + + // entropy pools are written to cyclically, starting at index 0 + ctx.pool = 0; + + /** + * Generates random bytes. The bytes may be generated synchronously or + * asynchronously. Web workers must use the asynchronous interface or + * else the behavior is undefined. + * + * @param count the number of random bytes to generate. + * @param [callback(err, bytes)] called once the operation completes. + * + * @return count random bytes as a string. + */ + ctx.generate = function(count, callback) { + // do synchronously + if(!callback) { + return ctx.generateSync(count); + } + + // simple generator using counter-based CBC + var cipher = ctx.plugin.cipher; + var increment = ctx.plugin.increment; + var formatKey = ctx.plugin.formatKey; + var formatSeed = ctx.plugin.formatSeed; + var b = forge$p.util.createBuffer(); + + // paranoid deviation from Fortuna: + // reset key for every request to protect previously + // generated random bytes should the key be discovered; + // there is no 100ms based reseeding because of this + // forced reseed for every `generate` call + ctx.key = null; + + generate(); + + function generate(err) { + if(err) { + return callback(err); + } + + // sufficient bytes generated + if(b.length() >= count) { + return callback(null, b.getBytes(count)); + } + + // if amount of data generated is greater than 1 MiB, trigger reseed + if(ctx.generated > 0xfffff) { + ctx.key = null; + } + + if(ctx.key === null) { + // prevent stack overflow + return forge$p.util.nextTick(function() { + _reseed(generate); + }); + } + + // generate the random bytes + var bytes = cipher(ctx.key, ctx.seed); + ctx.generated += bytes.length; + b.putBytes(bytes); + + // generate bytes for a new key and seed + ctx.key = formatKey(cipher(ctx.key, increment(ctx.seed))); + ctx.seed = formatSeed(cipher(ctx.key, ctx.seed)); + + forge$p.util.setImmediate(generate); + } + }; + + /** + * Generates random bytes synchronously. + * + * @param count the number of random bytes to generate. + * + * @return count random bytes as a string. + */ + ctx.generateSync = function(count) { + // simple generator using counter-based CBC + var cipher = ctx.plugin.cipher; + var increment = ctx.plugin.increment; + var formatKey = ctx.plugin.formatKey; + var formatSeed = ctx.plugin.formatSeed; + + // paranoid deviation from Fortuna: + // reset key for every request to protect previously + // generated random bytes should the key be discovered; + // there is no 100ms based reseeding because of this + // forced reseed for every `generateSync` call + ctx.key = null; + + var b = forge$p.util.createBuffer(); + while(b.length() < count) { + // if amount of data generated is greater than 1 MiB, trigger reseed + if(ctx.generated > 0xfffff) { + ctx.key = null; + } + + if(ctx.key === null) { + _reseedSync(); + } + + // generate the random bytes + var bytes = cipher(ctx.key, ctx.seed); + ctx.generated += bytes.length; + b.putBytes(bytes); + + // generate bytes for a new key and seed + ctx.key = formatKey(cipher(ctx.key, increment(ctx.seed))); + ctx.seed = formatSeed(cipher(ctx.key, ctx.seed)); + } + + return b.getBytes(count); + }; + + /** + * Private function that asynchronously reseeds a generator. + * + * @param callback(err) called once the operation completes. + */ + function _reseed(callback) { + if(ctx.pools[0].messageLength >= 32) { + _seed(); + return callback(); + } + // not enough seed data... + var needed = (32 - ctx.pools[0].messageLength) << 5; + ctx.seedFile(needed, function(err, bytes) { + if(err) { + return callback(err); + } + ctx.collect(bytes); + _seed(); + callback(); + }); + } + + /** + * Private function that synchronously reseeds a generator. + */ + function _reseedSync() { + if(ctx.pools[0].messageLength >= 32) { + return _seed(); + } + // not enough seed data... + var needed = (32 - ctx.pools[0].messageLength) << 5; + ctx.collect(ctx.seedFileSync(needed)); + _seed(); + } + + /** + * Private function that seeds a generator once enough bytes are available. + */ + function _seed() { + // update reseed count + ctx.reseeds = (ctx.reseeds === 0xffffffff) ? 0 : ctx.reseeds + 1; + + // goal is to update `key` via: + // key = hash(key + s) + // where 's' is all collected entropy from selected pools, then... + + // create a plugin-based message digest + var md = ctx.plugin.md.create(); + + // consume current key bytes + md.update(ctx.keyBytes); + + // digest the entropy of pools whose index k meet the + // condition 'n mod 2^k == 0' where n is the number of reseeds + var _2powK = 1; + for(var k = 0; k < 32; ++k) { + if(ctx.reseeds % _2powK === 0) { + md.update(ctx.pools[k].digest().getBytes()); + ctx.pools[k].start(); + } + _2powK = _2powK << 1; + } + + // get digest for key bytes + ctx.keyBytes = md.digest().getBytes(); + + // paranoid deviation from Fortuna: + // update `seed` via `seed = hash(key)` + // instead of initializing to zero once and only + // ever incrementing it + md.start(); + md.update(ctx.keyBytes); + var seedBytes = md.digest().getBytes(); + + // update state + ctx.key = ctx.plugin.formatKey(ctx.keyBytes); + ctx.seed = ctx.plugin.formatSeed(seedBytes); + ctx.generated = 0; + } + + /** + * The built-in default seedFile. This seedFile is used when entropy + * is needed immediately. + * + * @param needed the number of bytes that are needed. + * + * @return the random bytes. + */ + function defaultSeedFile(needed) { + // use window.crypto.getRandomValues strong source of entropy if available + var getRandomValues = null; + var globalScope = forge$p.util.globalScope; + var _crypto = globalScope.crypto || globalScope.msCrypto; + if(_crypto && _crypto.getRandomValues) { + getRandomValues = function(arr) { + return _crypto.getRandomValues(arr); + }; + } + + var b = forge$p.util.createBuffer(); + if(getRandomValues) { + while(b.length() < needed) { + // max byte length is 65536 before QuotaExceededError is thrown + // http://www.w3.org/TR/WebCryptoAPI/#RandomSource-method-getRandomValues + var count = Math.max(1, Math.min(needed - b.length(), 65536) / 4); + var entropy = new Uint32Array(Math.floor(count)); + try { + getRandomValues(entropy); + for(var i = 0; i < entropy.length; ++i) { + b.putInt32(entropy[i]); + } + } catch(e) { + /* only ignore QuotaExceededError */ + if(!(typeof QuotaExceededError !== 'undefined' && + e instanceof QuotaExceededError)) { + throw e; + } + } + } + } + + // be sad and add some weak random data + if(b.length() < needed) { + /* Draws from Park-Miller "minimal standard" 31 bit PRNG, + implemented with David G. Carta's optimization: with 32 bit math + and without division (Public Domain). */ + var hi, lo, next; + var seed = Math.floor(Math.random() * 0x010000); + while(b.length() < needed) { + lo = 16807 * (seed & 0xFFFF); + hi = 16807 * (seed >> 16); + lo += (hi & 0x7FFF) << 16; + lo += hi >> 15; + lo = (lo & 0x7FFFFFFF) + (lo >> 31); + seed = lo & 0xFFFFFFFF; + + // consume lower 3 bytes of seed + for(var i = 0; i < 3; ++i) { + // throw in more pseudo random + next = seed >>> (i << 3); + next ^= Math.floor(Math.random() * 0x0100); + b.putByte(next & 0xFF); + } + } + } + + return b.getBytes(needed); + } + // initialize seed file APIs + if(_crypto$1) { + // use nodejs async API + ctx.seedFile = function(needed, callback) { + _crypto$1.randomBytes(needed, function(err, bytes) { + if(err) { + return callback(err); + } + callback(null, bytes.toString()); + }); + }; + // use nodejs sync API + ctx.seedFileSync = function(needed) { + return _crypto$1.randomBytes(needed).toString(); + }; + } else { + ctx.seedFile = function(needed, callback) { + try { + callback(null, defaultSeedFile(needed)); + } catch(e) { + callback(e); + } + }; + ctx.seedFileSync = defaultSeedFile; + } + + /** + * Adds entropy to a prng ctx's accumulator. + * + * @param bytes the bytes of entropy as a string. + */ + ctx.collect = function(bytes) { + // iterate over pools distributing entropy cyclically + var count = bytes.length; + for(var i = 0; i < count; ++i) { + ctx.pools[ctx.pool].update(bytes.substr(i, 1)); + ctx.pool = (ctx.pool === 31) ? 0 : ctx.pool + 1; + } + }; + + /** + * Collects an integer of n bits. + * + * @param i the integer entropy. + * @param n the number of bits in the integer. + */ + ctx.collectInt = function(i, n) { + var bytes = ''; + for(var x = 0; x < n; x += 8) { + bytes += String.fromCharCode((i >> x) & 0xFF); + } + ctx.collect(bytes); + }; + + /** + * Registers a Web Worker to receive immediate entropy from the main thread. + * This method is required until Web Workers can access the native crypto + * API. This method should be called twice for each created worker, once in + * the main thread, and once in the worker itself. + * + * @param worker the worker to register. + */ + ctx.registerWorker = function(worker) { + // worker receives random bytes + if(worker === self) { + ctx.seedFile = function(needed, callback) { + function listener(e) { + var data = e.data; + if(data.forge && data.forge.prng) { + self.removeEventListener('message', listener); + callback(data.forge.prng.err, data.forge.prng.bytes); + } + } + self.addEventListener('message', listener); + self.postMessage({forge: {prng: {needed: needed}}}); + }; + } else { + // main thread sends random bytes upon request + var listener = function(e) { + var data = e.data; + if(data.forge && data.forge.prng) { + ctx.seedFile(data.forge.prng.needed, function(err, bytes) { + worker.postMessage({forge: {prng: {err: err, bytes: bytes}}}); + }); + } + }; + // TODO: do we need to remove the event listener when the worker dies? + worker.addEventListener('message', listener); + } + }; + + return ctx; +}; + +/** + * An API for getting cryptographically-secure random bytes. The bytes are + * generated using the Fortuna algorithm devised by Bruce Schneier and + * Niels Ferguson. + * + * Getting strong random bytes is not yet easy to do in javascript. The only + * truish random entropy that can be collected is from the mouse, keyboard, or + * from timing with respect to page loads, etc. This generator makes a poor + * attempt at providing random bytes when those sources haven't yet provided + * enough entropy to initially seed or to reseed the PRNG. + * + * @author Dave Longley + * + * Copyright (c) 2009-2014 Digital Bazaar, Inc. + */ + +var forge$o = forge$D; + + + + + +(function() { + +// forge.random already defined +if(forge$o.random && forge$o.random.getBytes) { + forge$o.random; + return; +} + +(function(jQuery) { + +// the default prng plugin, uses AES-128 +var prng_aes = {}; +var _prng_aes_output = new Array(4); +var _prng_aes_buffer = forge$o.util.createBuffer(); +prng_aes.formatKey = function(key) { + // convert the key into 32-bit integers + var tmp = forge$o.util.createBuffer(key); + key = new Array(4); + key[0] = tmp.getInt32(); + key[1] = tmp.getInt32(); + key[2] = tmp.getInt32(); + key[3] = tmp.getInt32(); + + // return the expanded key + return forge$o.aes._expandKey(key, false); +}; +prng_aes.formatSeed = function(seed) { + // convert seed into 32-bit integers + var tmp = forge$o.util.createBuffer(seed); + seed = new Array(4); + seed[0] = tmp.getInt32(); + seed[1] = tmp.getInt32(); + seed[2] = tmp.getInt32(); + seed[3] = tmp.getInt32(); + return seed; +}; +prng_aes.cipher = function(key, seed) { + forge$o.aes._updateBlock(key, seed, _prng_aes_output, false); + _prng_aes_buffer.putInt32(_prng_aes_output[0]); + _prng_aes_buffer.putInt32(_prng_aes_output[1]); + _prng_aes_buffer.putInt32(_prng_aes_output[2]); + _prng_aes_buffer.putInt32(_prng_aes_output[3]); + return _prng_aes_buffer.getBytes(); +}; +prng_aes.increment = function(seed) { + // FIXME: do we care about carry or signed issues? + ++seed[3]; + return seed; +}; +prng_aes.md = forge$o.md.sha256; + +/** + * Creates a new PRNG. + */ +function spawnPrng() { + var ctx = forge$o.prng.create(prng_aes); + + /** + * Gets random bytes. If a native secure crypto API is unavailable, this + * method tries to make the bytes more unpredictable by drawing from data that + * can be collected from the user of the browser, eg: mouse movement. + * + * If a callback is given, this method will be called asynchronously. + * + * @param count the number of random bytes to get. + * @param [callback(err, bytes)] called once the operation completes. + * + * @return the random bytes in a string. + */ + ctx.getBytes = function(count, callback) { + return ctx.generate(count, callback); + }; + + /** + * Gets random bytes asynchronously. If a native secure crypto API is + * unavailable, this method tries to make the bytes more unpredictable by + * drawing from data that can be collected from the user of the browser, + * eg: mouse movement. + * + * @param count the number of random bytes to get. + * + * @return the random bytes in a string. + */ + ctx.getBytesSync = function(count) { + return ctx.generate(count); + }; + + return ctx; +} + +// create default prng context +var _ctx = spawnPrng(); + +// add other sources of entropy only if window.crypto.getRandomValues is not +// available -- otherwise this source will be automatically used by the prng +var getRandomValues = null; +var globalScope = forge$o.util.globalScope; +var _crypto = globalScope.crypto || globalScope.msCrypto; +if(_crypto && _crypto.getRandomValues) { + getRandomValues = function(arr) { + return _crypto.getRandomValues(arr); + }; +} + +if(forge$o.options.usePureJavaScript || + (!forge$o.util.isNodejs && !getRandomValues)) { + + // get load time entropy + _ctx.collectInt(+new Date(), 32); + + // add some entropy from navigator object + if(typeof(navigator) !== 'undefined') { + var _navBytes = ''; + for(var key in navigator) { + try { + if(typeof(navigator[key]) == 'string') { + _navBytes += navigator[key]; + } + } catch(e) { + /* Some navigator keys might not be accessible, e.g. the geolocation + attribute throws an exception if touched in Mozilla chrome:// + context. + + Silently ignore this and just don't use this as a source of + entropy. */ + } + } + _ctx.collect(_navBytes); + _navBytes = null; + } + + // add mouse and keyboard collectors if jquery is available + if(jQuery) { + // set up mouse entropy capture + jQuery().mousemove(function(e) { + // add mouse coords + _ctx.collectInt(e.clientX, 16); + _ctx.collectInt(e.clientY, 16); + }); + + // set up keyboard entropy capture + jQuery().keypress(function(e) { + _ctx.collectInt(e.charCode, 8); + }); + } +} + +/* Random API */ +if(!forge$o.random) { + forge$o.random = _ctx; +} else { + // extend forge.random with _ctx + for(var key in _ctx) { + forge$o.random[key] = _ctx[key]; + } +} + +// expose spawn PRNG +forge$o.random.createInstance = spawnPrng; + +forge$o.random; + +})(typeof(jQuery) !== 'undefined' ? jQuery : null); + +})(); + +/** + * RC2 implementation. + * + * @author Stefan Siegl + * + * Copyright (c) 2012 Stefan Siegl + * + * Information on the RC2 cipher is available from RFC #2268, + * http://www.ietf.org/rfc/rfc2268.txt + */ + +var forge$n = forge$D; + + +var piTable = [ + 0xd9, 0x78, 0xf9, 0xc4, 0x19, 0xdd, 0xb5, 0xed, 0x28, 0xe9, 0xfd, 0x79, 0x4a, 0xa0, 0xd8, 0x9d, + 0xc6, 0x7e, 0x37, 0x83, 0x2b, 0x76, 0x53, 0x8e, 0x62, 0x4c, 0x64, 0x88, 0x44, 0x8b, 0xfb, 0xa2, + 0x17, 0x9a, 0x59, 0xf5, 0x87, 0xb3, 0x4f, 0x13, 0x61, 0x45, 0x6d, 0x8d, 0x09, 0x81, 0x7d, 0x32, + 0xbd, 0x8f, 0x40, 0xeb, 0x86, 0xb7, 0x7b, 0x0b, 0xf0, 0x95, 0x21, 0x22, 0x5c, 0x6b, 0x4e, 0x82, + 0x54, 0xd6, 0x65, 0x93, 0xce, 0x60, 0xb2, 0x1c, 0x73, 0x56, 0xc0, 0x14, 0xa7, 0x8c, 0xf1, 0xdc, + 0x12, 0x75, 0xca, 0x1f, 0x3b, 0xbe, 0xe4, 0xd1, 0x42, 0x3d, 0xd4, 0x30, 0xa3, 0x3c, 0xb6, 0x26, + 0x6f, 0xbf, 0x0e, 0xda, 0x46, 0x69, 0x07, 0x57, 0x27, 0xf2, 0x1d, 0x9b, 0xbc, 0x94, 0x43, 0x03, + 0xf8, 0x11, 0xc7, 0xf6, 0x90, 0xef, 0x3e, 0xe7, 0x06, 0xc3, 0xd5, 0x2f, 0xc8, 0x66, 0x1e, 0xd7, + 0x08, 0xe8, 0xea, 0xde, 0x80, 0x52, 0xee, 0xf7, 0x84, 0xaa, 0x72, 0xac, 0x35, 0x4d, 0x6a, 0x2a, + 0x96, 0x1a, 0xd2, 0x71, 0x5a, 0x15, 0x49, 0x74, 0x4b, 0x9f, 0xd0, 0x5e, 0x04, 0x18, 0xa4, 0xec, + 0xc2, 0xe0, 0x41, 0x6e, 0x0f, 0x51, 0xcb, 0xcc, 0x24, 0x91, 0xaf, 0x50, 0xa1, 0xf4, 0x70, 0x39, + 0x99, 0x7c, 0x3a, 0x85, 0x23, 0xb8, 0xb4, 0x7a, 0xfc, 0x02, 0x36, 0x5b, 0x25, 0x55, 0x97, 0x31, + 0x2d, 0x5d, 0xfa, 0x98, 0xe3, 0x8a, 0x92, 0xae, 0x05, 0xdf, 0x29, 0x10, 0x67, 0x6c, 0xba, 0xc9, + 0xd3, 0x00, 0xe6, 0xcf, 0xe1, 0x9e, 0xa8, 0x2c, 0x63, 0x16, 0x01, 0x3f, 0x58, 0xe2, 0x89, 0xa9, + 0x0d, 0x38, 0x34, 0x1b, 0xab, 0x33, 0xff, 0xb0, 0xbb, 0x48, 0x0c, 0x5f, 0xb9, 0xb1, 0xcd, 0x2e, + 0xc5, 0xf3, 0xdb, 0x47, 0xe5, 0xa5, 0x9c, 0x77, 0x0a, 0xa6, 0x20, 0x68, 0xfe, 0x7f, 0xc1, 0xad +]; + +var s = [1, 2, 3, 5]; + +/** + * Rotate a word left by given number of bits. + * + * Bits that are shifted out on the left are put back in on the right + * hand side. + * + * @param word The word to shift left. + * @param bits The number of bits to shift by. + * @return The rotated word. + */ +var rol = function(word, bits) { + return ((word << bits) & 0xffff) | ((word & 0xffff) >> (16 - bits)); +}; + +/** + * Rotate a word right by given number of bits. + * + * Bits that are shifted out on the right are put back in on the left + * hand side. + * + * @param word The word to shift right. + * @param bits The number of bits to shift by. + * @return The rotated word. + */ +var ror = function(word, bits) { + return ((word & 0xffff) >> bits) | ((word << (16 - bits)) & 0xffff); +}; + +/* RC2 API */ +forge$n.rc2 = forge$n.rc2 || {}; + +/** + * Perform RC2 key expansion as per RFC #2268, section 2. + * + * @param key variable-length user key (between 1 and 128 bytes) + * @param effKeyBits number of effective key bits (default: 128) + * @return the expanded RC2 key (ByteBuffer of 128 bytes) + */ +forge$n.rc2.expandKey = function(key, effKeyBits) { + if(typeof key === 'string') { + key = forge$n.util.createBuffer(key); + } + effKeyBits = effKeyBits || 128; + + /* introduce variables that match the names used in RFC #2268 */ + var L = key; + var T = key.length(); + var T1 = effKeyBits; + var T8 = Math.ceil(T1 / 8); + var TM = 0xff >> (T1 & 0x07); + var i; + + for(i = T; i < 128; i++) { + L.putByte(piTable[(L.at(i - 1) + L.at(i - T)) & 0xff]); + } + + L.setAt(128 - T8, piTable[L.at(128 - T8) & TM]); + + for(i = 127 - T8; i >= 0; i--) { + L.setAt(i, piTable[L.at(i + 1) ^ L.at(i + T8)]); + } + + return L; +}; + +/** + * Creates a RC2 cipher object. + * + * @param key the symmetric key to use (as base for key generation). + * @param bits the number of effective key bits. + * @param encrypt false for decryption, true for encryption. + * + * @return the cipher. + */ +var createCipher = function(key, bits, encrypt) { + var _finish = false, _input = null, _output = null, _iv = null; + var mixRound, mashRound; + var i, j, K = []; + + /* Expand key and fill into K[] Array */ + key = forge$n.rc2.expandKey(key, bits); + for(i = 0; i < 64; i++) { + K.push(key.getInt16Le()); + } + + if(encrypt) { + /** + * Perform one mixing round "in place". + * + * @param R Array of four words to perform mixing on. + */ + mixRound = function(R) { + for(i = 0; i < 4; i++) { + R[i] += K[j] + (R[(i + 3) % 4] & R[(i + 2) % 4]) + + ((~R[(i + 3) % 4]) & R[(i + 1) % 4]); + R[i] = rol(R[i], s[i]); + j++; + } + }; + + /** + * Perform one mashing round "in place". + * + * @param R Array of four words to perform mashing on. + */ + mashRound = function(R) { + for(i = 0; i < 4; i++) { + R[i] += K[R[(i + 3) % 4] & 63]; + } + }; + } else { + /** + * Perform one r-mixing round "in place". + * + * @param R Array of four words to perform mixing on. + */ + mixRound = function(R) { + for(i = 3; i >= 0; i--) { + R[i] = ror(R[i], s[i]); + R[i] -= K[j] + (R[(i + 3) % 4] & R[(i + 2) % 4]) + + ((~R[(i + 3) % 4]) & R[(i + 1) % 4]); + j--; + } + }; + + /** + * Perform one r-mashing round "in place". + * + * @param R Array of four words to perform mashing on. + */ + mashRound = function(R) { + for(i = 3; i >= 0; i--) { + R[i] -= K[R[(i + 3) % 4] & 63]; + } + }; + } + + /** + * Run the specified cipher execution plan. + * + * This function takes four words from the input buffer, applies the IV on + * it (if requested) and runs the provided execution plan. + * + * The plan must be put together in form of a array of arrays. Where the + * outer one is simply a list of steps to perform and the inner one needs + * to have two elements: the first one telling how many rounds to perform, + * the second one telling what to do (i.e. the function to call). + * + * @param {Array} plan The plan to execute. + */ + var runPlan = function(plan) { + var R = []; + + /* Get data from input buffer and fill the four words into R */ + for(i = 0; i < 4; i++) { + var val = _input.getInt16Le(); + + if(_iv !== null) { + if(encrypt) { + /* We're encrypting, apply the IV first. */ + val ^= _iv.getInt16Le(); + } else { + /* We're decryption, keep cipher text for next block. */ + _iv.putInt16Le(val); + } + } + + R.push(val & 0xffff); + } + + /* Reset global "j" variable as per spec. */ + j = encrypt ? 0 : 63; + + /* Run execution plan. */ + for(var ptr = 0; ptr < plan.length; ptr++) { + for(var ctr = 0; ctr < plan[ptr][0]; ctr++) { + plan[ptr][1](R); + } + } + + /* Write back result to output buffer. */ + for(i = 0; i < 4; i++) { + if(_iv !== null) { + if(encrypt) { + /* We're encrypting in CBC-mode, feed back encrypted bytes into + IV buffer to carry it forward to next block. */ + _iv.putInt16Le(R[i]); + } else { + R[i] ^= _iv.getInt16Le(); + } + } + + _output.putInt16Le(R[i]); + } + }; + + /* Create cipher object */ + var cipher = null; + cipher = { + /** + * Starts or restarts the encryption or decryption process, whichever + * was previously configured. + * + * To use the cipher in CBC mode, iv may be given either as a string + * of bytes, or as a byte buffer. For ECB mode, give null as iv. + * + * @param iv the initialization vector to use, null for ECB mode. + * @param output the output the buffer to write to, null to create one. + */ + start: function(iv, output) { + if(iv) { + /* CBC mode */ + if(typeof iv === 'string') { + iv = forge$n.util.createBuffer(iv); + } + } + + _finish = false; + _input = forge$n.util.createBuffer(); + _output = output || new forge$n.util.createBuffer(); + _iv = iv; + + cipher.output = _output; + }, + + /** + * Updates the next block. + * + * @param input the buffer to read from. + */ + update: function(input) { + if(!_finish) { + // not finishing, so fill the input buffer with more input + _input.putBuffer(input); + } + + while(_input.length() >= 8) { + runPlan([ + [ 5, mixRound ], + [ 1, mashRound ], + [ 6, mixRound ], + [ 1, mashRound ], + [ 5, mixRound ] + ]); + } + }, + + /** + * Finishes encrypting or decrypting. + * + * @param pad a padding function to use, null for PKCS#7 padding, + * signature(blockSize, buffer, decrypt). + * + * @return true if successful, false on error. + */ + finish: function(pad) { + var rval = true; + + if(encrypt) { + if(pad) { + rval = pad(8, _input, !encrypt); + } else { + // add PKCS#7 padding to block (each pad byte is the + // value of the number of pad bytes) + var padding = (_input.length() === 8) ? 8 : (8 - _input.length()); + _input.fillWithByte(padding, padding); + } + } + + if(rval) { + // do final update + _finish = true; + cipher.update(); + } + + if(!encrypt) { + // check for error: input data not a multiple of block size + rval = (_input.length() === 0); + if(rval) { + if(pad) { + rval = pad(8, _output, !encrypt); + } else { + // ensure padding byte count is valid + var len = _output.length(); + var count = _output.at(len - 1); + + if(count > len) { + rval = false; + } else { + // trim off padding bytes + _output.truncate(count); + } + } + } + } + + return rval; + } + }; + + return cipher; +}; + +/** + * Creates an RC2 cipher object to encrypt data in ECB or CBC mode using the + * given symmetric key. The output will be stored in the 'output' member + * of the returned cipher. + * + * The key and iv may be given as a string of bytes or a byte buffer. + * The cipher is initialized to use 128 effective key bits. + * + * @param key the symmetric key to use. + * @param iv the initialization vector to use. + * @param output the buffer to write to, null to create one. + * + * @return the cipher. + */ +forge$n.rc2.startEncrypting = function(key, iv, output) { + var cipher = forge$n.rc2.createEncryptionCipher(key, 128); + cipher.start(iv, output); + return cipher; +}; + +/** + * Creates an RC2 cipher object to encrypt data in ECB or CBC mode using the + * given symmetric key. + * + * The key may be given as a string of bytes or a byte buffer. + * + * To start encrypting call start() on the cipher with an iv and optional + * output buffer. + * + * @param key the symmetric key to use. + * + * @return the cipher. + */ +forge$n.rc2.createEncryptionCipher = function(key, bits) { + return createCipher(key, bits, true); +}; + +/** + * Creates an RC2 cipher object to decrypt data in ECB or CBC mode using the + * given symmetric key. The output will be stored in the 'output' member + * of the returned cipher. + * + * The key and iv may be given as a string of bytes or a byte buffer. + * The cipher is initialized to use 128 effective key bits. + * + * @param key the symmetric key to use. + * @param iv the initialization vector to use. + * @param output the buffer to write to, null to create one. + * + * @return the cipher. + */ +forge$n.rc2.startDecrypting = function(key, iv, output) { + var cipher = forge$n.rc2.createDecryptionCipher(key, 128); + cipher.start(iv, output); + return cipher; +}; + +/** + * Creates an RC2 cipher object to decrypt data in ECB or CBC mode using the + * given symmetric key. + * + * The key may be given as a string of bytes or a byte buffer. + * + * To start decrypting call start() on the cipher with an iv and optional + * output buffer. + * + * @param key the symmetric key to use. + * + * @return the cipher. + */ +forge$n.rc2.createDecryptionCipher = function(key, bits) { + return createCipher(key, bits, false); +}; + +// Copyright (c) 2005 Tom Wu +// All Rights Reserved. +// See "LICENSE" for details. + +// Basic JavaScript BN library - subset useful for RSA encryption. + +/* +Licensing (LICENSE) +------------------- + +This software is covered under the following copyright: +*/ +/* + * Copyright (c) 2003-2005 Tom Wu + * All Rights Reserved. + * + * Permission is hereby granted, free of charge, to any person obtaining + * a copy of this software and associated documentation files (the + * "Software"), to deal in the Software without restriction, including + * without limitation the rights to use, copy, modify, merge, publish, + * distribute, sublicense, and/or sell copies of the Software, and to + * permit persons to whom the Software is furnished to do so, subject to + * the following conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS-IS" AND WITHOUT WARRANTY OF ANY KIND, + * EXPRESS, IMPLIED OR OTHERWISE, INCLUDING WITHOUT LIMITATION, ANY + * WARRANTY OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE. + * + * IN NO EVENT SHALL TOM WU BE LIABLE FOR ANY SPECIAL, INCIDENTAL, + * INDIRECT OR CONSEQUENTIAL DAMAGES OF ANY KIND, OR ANY DAMAGES WHATSOEVER + * RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER OR NOT ADVISED OF + * THE POSSIBILITY OF DAMAGE, AND ON ANY THEORY OF LIABILITY, ARISING OUT + * OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + * + * In addition, the following condition applies: + * + * All redistributions must retain an intact copy of this copyright notice + * and disclaimer. + */ +/* +Address all questions regarding this license to: + + Tom Wu + tjw@cs.Stanford.EDU +*/ +var forge$m = forge$D; + +forge$m.jsbn = forge$m.jsbn || {}; + +// Bits per digit +var dbits; + +// (public) Constructor +function BigInteger$4(a,b,c) { + this.data = []; + if(a != null) + if("number" == typeof a) this.fromNumber(a,b,c); + else if(b == null && "string" != typeof a) this.fromString(a,256); + else this.fromString(a,b); +} +forge$m.jsbn.BigInteger = BigInteger$4; + +// return new, unset BigInteger +function nbi() { return new BigInteger$4(null); } + +// am: Compute w_j += (x*this_i), propagate carries, +// c is initial carry, returns final carry. +// c < 3*dvalue, x < 2*dvalue, this_i < dvalue +// We need to select the fastest one that works in this environment. + +// am1: use a single mult and divide to get the high bits, +// max digit bits should be 26 because +// max internal value = 2*dvalue^2-2*dvalue (< 2^53) +function am1(i,x,w,j,c,n) { + while(--n >= 0) { + var v = x*this.data[i++]+w.data[j]+c; + c = Math.floor(v/0x4000000); + w.data[j++] = v&0x3ffffff; + } + return c; +} +// am2 avoids a big mult-and-extract completely. +// Max digit bits should be <= 30 because we do bitwise ops +// on values up to 2*hdvalue^2-hdvalue-1 (< 2^31) +function am2(i,x,w,j,c,n) { + var xl = x&0x7fff, xh = x>>15; + while(--n >= 0) { + var l = this.data[i]&0x7fff; + var h = this.data[i++]>>15; + var m = xh*l+h*xl; + l = xl*l+((m&0x7fff)<<15)+w.data[j]+(c&0x3fffffff); + c = (l>>>30)+(m>>>15)+xh*h+(c>>>30); + w.data[j++] = l&0x3fffffff; + } + return c; +} +// Alternately, set max digit bits to 28 since some +// browsers slow down when dealing with 32-bit numbers. +function am3(i,x,w,j,c,n) { + var xl = x&0x3fff, xh = x>>14; + while(--n >= 0) { + var l = this.data[i]&0x3fff; + var h = this.data[i++]>>14; + var m = xh*l+h*xl; + l = xl*l+((m&0x3fff)<<14)+w.data[j]+c; + c = (l>>28)+(m>>14)+xh*h; + w.data[j++] = l&0xfffffff; + } + return c; +} + +// node.js (no browser) +if(typeof(navigator) === 'undefined') +{ + BigInteger$4.prototype.am = am3; + dbits = 28; +} else if((navigator.appName == "Microsoft Internet Explorer")) { + BigInteger$4.prototype.am = am2; + dbits = 30; +} else if((navigator.appName != "Netscape")) { + BigInteger$4.prototype.am = am1; + dbits = 26; +} else { // Mozilla/Netscape seems to prefer am3 + BigInteger$4.prototype.am = am3; + dbits = 28; +} + +BigInteger$4.prototype.DB = dbits; +BigInteger$4.prototype.DM = ((1<= 0; --i) r.data[i] = this.data[i]; + r.t = this.t; + r.s = this.s; +} + +// (protected) set from integer value x, -DV <= x < DV +function bnpFromInt(x) { + this.t = 1; + this.s = (x<0)?-1:0; + if(x > 0) this.data[0] = x; + else if(x < -1) this.data[0] = x+this.DV; + else this.t = 0; +} + +// return bigint initialized to value +function nbv(i) { var r = nbi(); r.fromInt(i); return r; } + +// (protected) set from string and radix +function bnpFromString(s,b) { + var k; + if(b == 16) k = 4; + else if(b == 8) k = 3; + else if(b == 256) k = 8; // byte array + else if(b == 2) k = 1; + else if(b == 32) k = 5; + else if(b == 4) k = 2; + else { this.fromRadix(s,b); return; } + this.t = 0; + this.s = 0; + var i = s.length, mi = false, sh = 0; + while(--i >= 0) { + var x = (k==8)?s[i]&0xff:intAt(s,i); + if(x < 0) { + if(s.charAt(i) == "-") mi = true; + continue; + } + mi = false; + if(sh == 0) + this.data[this.t++] = x; + else if(sh+k > this.DB) { + this.data[this.t-1] |= (x&((1<<(this.DB-sh))-1))<>(this.DB-sh)); + } else + this.data[this.t-1] |= x<= this.DB) sh -= this.DB; + } + if(k == 8 && (s[0]&0x80) != 0) { + this.s = -1; + if(sh > 0) this.data[this.t-1] |= ((1<<(this.DB-sh))-1)< 0 && this.data[this.t-1] == c) --this.t; +} + +// (public) return string representation in given radix +function bnToString(b) { + if(this.s < 0) return "-"+this.negate().toString(b); + var k; + if(b == 16) k = 4; + else if(b == 8) k = 3; + else if(b == 2) k = 1; + else if(b == 32) k = 5; + else if(b == 4) k = 2; + else return this.toRadix(b); + var km = (1< 0) { + if(p < this.DB && (d = this.data[i]>>p) > 0) { m = true; r = int2char(d); } + while(i >= 0) { + if(p < k) { + d = (this.data[i]&((1<>(p+=this.DB-k); + } else { + d = (this.data[i]>>(p-=k))&km; + if(p <= 0) { p += this.DB; --i; } + } + if(d > 0) m = true; + if(m) r += int2char(d); + } + } + return m?r:"0"; +} + +// (public) -this +function bnNegate() { var r = nbi(); BigInteger$4.ZERO.subTo(this,r); return r; } + +// (public) |this| +function bnAbs() { return (this.s<0)?this.negate():this; } + +// (public) return + if this > a, - if this < a, 0 if equal +function bnCompareTo(a) { + var r = this.s-a.s; + if(r != 0) return r; + var i = this.t; + r = i-a.t; + if(r != 0) return (this.s<0)?-r:r; + while(--i >= 0) if((r=this.data[i]-a.data[i]) != 0) return r; + return 0; +} + +// returns bit length of the integer x +function nbits(x) { + var r = 1, t; + if((t=x>>>16) != 0) { x = t; r += 16; } + if((t=x>>8) != 0) { x = t; r += 8; } + if((t=x>>4) != 0) { x = t; r += 4; } + if((t=x>>2) != 0) { x = t; r += 2; } + if((t=x>>1) != 0) { x = t; r += 1; } + return r; +} + +// (public) return the number of bits in "this" +function bnBitLength() { + if(this.t <= 0) return 0; + return this.DB*(this.t-1)+nbits(this.data[this.t-1]^(this.s&this.DM)); +} + +// (protected) r = this << n*DB +function bnpDLShiftTo(n,r) { + var i; + for(i = this.t-1; i >= 0; --i) r.data[i+n] = this.data[i]; + for(i = n-1; i >= 0; --i) r.data[i] = 0; + r.t = this.t+n; + r.s = this.s; +} + +// (protected) r = this >> n*DB +function bnpDRShiftTo(n,r) { + for(var i = n; i < this.t; ++i) r.data[i-n] = this.data[i]; + r.t = Math.max(this.t-n,0); + r.s = this.s; +} + +// (protected) r = this << n +function bnpLShiftTo(n,r) { + var bs = n%this.DB; + var cbs = this.DB-bs; + var bm = (1<= 0; --i) { + r.data[i+ds+1] = (this.data[i]>>cbs)|c; + c = (this.data[i]&bm)<= 0; --i) r.data[i] = 0; + r.data[ds] = c; + r.t = this.t+ds+1; + r.s = this.s; + r.clamp(); +} + +// (protected) r = this >> n +function bnpRShiftTo(n,r) { + r.s = this.s; + var ds = Math.floor(n/this.DB); + if(ds >= this.t) { r.t = 0; return; } + var bs = n%this.DB; + var cbs = this.DB-bs; + var bm = (1<>bs; + for(var i = ds+1; i < this.t; ++i) { + r.data[i-ds-1] |= (this.data[i]&bm)<>bs; + } + if(bs > 0) r.data[this.t-ds-1] |= (this.s&bm)<>= this.DB; + } + if(a.t < this.t) { + c -= a.s; + while(i < this.t) { + c += this.data[i]; + r.data[i++] = c&this.DM; + c >>= this.DB; + } + c += this.s; + } else { + c += this.s; + while(i < a.t) { + c -= a.data[i]; + r.data[i++] = c&this.DM; + c >>= this.DB; + } + c -= a.s; + } + r.s = (c<0)?-1:0; + if(c < -1) r.data[i++] = this.DV+c; + else if(c > 0) r.data[i++] = c; + r.t = i; + r.clamp(); +} + +// (protected) r = this * a, r != this,a (HAC 14.12) +// "this" should be the larger one if appropriate. +function bnpMultiplyTo(a,r) { + var x = this.abs(), y = a.abs(); + var i = x.t; + r.t = i+y.t; + while(--i >= 0) r.data[i] = 0; + for(i = 0; i < y.t; ++i) r.data[i+x.t] = x.am(0,y.data[i],r,i,0,x.t); + r.s = 0; + r.clamp(); + if(this.s != a.s) BigInteger$4.ZERO.subTo(r,r); +} + +// (protected) r = this^2, r != this (HAC 14.16) +function bnpSquareTo(r) { + var x = this.abs(); + var i = r.t = 2*x.t; + while(--i >= 0) r.data[i] = 0; + for(i = 0; i < x.t-1; ++i) { + var c = x.am(i,x.data[i],r,2*i,0,1); + if((r.data[i+x.t]+=x.am(i+1,2*x.data[i],r,2*i+1,c,x.t-i-1)) >= x.DV) { + r.data[i+x.t] -= x.DV; + r.data[i+x.t+1] = 1; + } + } + if(r.t > 0) r.data[r.t-1] += x.am(i,x.data[i],r,2*i,0,1); + r.s = 0; + r.clamp(); +} + +// (protected) divide this by m, quotient and remainder to q, r (HAC 14.20) +// r != q, this != m. q or r may be null. +function bnpDivRemTo(m,q,r) { + var pm = m.abs(); + if(pm.t <= 0) return; + var pt = this.abs(); + if(pt.t < pm.t) { + if(q != null) q.fromInt(0); + if(r != null) this.copyTo(r); + return; + } + if(r == null) r = nbi(); + var y = nbi(), ts = this.s, ms = m.s; + var nsh = this.DB-nbits(pm.data[pm.t-1]); // normalize modulus + if(nsh > 0) { pm.lShiftTo(nsh,y); pt.lShiftTo(nsh,r); } else { pm.copyTo(y); pt.copyTo(r); } + var ys = y.t; + var y0 = y.data[ys-1]; + if(y0 == 0) return; + var yt = y0*(1<1)?y.data[ys-2]>>this.F2:0); + var d1 = this.FV/yt, d2 = (1<= 0) { + r.data[r.t++] = 1; + r.subTo(t,r); + } + BigInteger$4.ONE.dlShiftTo(ys,t); + t.subTo(y,y); // "negative" y so we can replace sub with am later + while(y.t < ys) y.data[y.t++] = 0; + while(--j >= 0) { + // Estimate quotient digit + var qd = (r.data[--i]==y0)?this.DM:Math.floor(r.data[i]*d1+(r.data[i-1]+e)*d2); + if((r.data[i]+=y.am(0,qd,r,j,0,ys)) < qd) { // Try it out + y.dlShiftTo(j,t); + r.subTo(t,r); + while(r.data[i] < --qd) r.subTo(t,r); + } + } + if(q != null) { + r.drShiftTo(ys,q); + if(ts != ms) BigInteger$4.ZERO.subTo(q,q); + } + r.t = ys; + r.clamp(); + if(nsh > 0) r.rShiftTo(nsh,r); // Denormalize remainder + if(ts < 0) BigInteger$4.ZERO.subTo(r,r); +} + +// (public) this mod a +function bnMod(a) { + var r = nbi(); + this.abs().divRemTo(a,null,r); + if(this.s < 0 && r.compareTo(BigInteger$4.ZERO) > 0) a.subTo(r,r); + return r; +} + +// Modular reduction using "classic" algorithm +function Classic(m) { this.m = m; } +function cConvert(x) { + if(x.s < 0 || x.compareTo(this.m) >= 0) return x.mod(this.m); + else return x; +} +function cRevert(x) { return x; } +function cReduce(x) { x.divRemTo(this.m,null,x); } +function cMulTo(x,y,r) { x.multiplyTo(y,r); this.reduce(r); } +function cSqrTo(x,r) { x.squareTo(r); this.reduce(r); } + +Classic.prototype.convert = cConvert; +Classic.prototype.revert = cRevert; +Classic.prototype.reduce = cReduce; +Classic.prototype.mulTo = cMulTo; +Classic.prototype.sqrTo = cSqrTo; + +// (protected) return "-1/this % 2^DB"; useful for Mont. reduction +// justification: +// xy == 1 (mod m) +// xy = 1+km +// xy(2-xy) = (1+km)(1-km) +// x[y(2-xy)] = 1-k^2m^2 +// x[y(2-xy)] == 1 (mod m^2) +// if y is 1/x mod m, then y(2-xy) is 1/x mod m^2 +// should reduce x and y(2-xy) by m^2 at each step to keep size bounded. +// JS multiply "overflows" differently from C/C++, so care is needed here. +function bnpInvDigit() { + if(this.t < 1) return 0; + var x = this.data[0]; + if((x&1) == 0) return 0; + var y = x&3; // y == 1/x mod 2^2 + y = (y*(2-(x&0xf)*y))&0xf; // y == 1/x mod 2^4 + y = (y*(2-(x&0xff)*y))&0xff; // y == 1/x mod 2^8 + y = (y*(2-(((x&0xffff)*y)&0xffff)))&0xffff; // y == 1/x mod 2^16 + // last step - calculate inverse mod DV directly; + // assumes 16 < DB <= 32 and assumes ability to handle 48-bit ints + y = (y*(2-x*y%this.DV))%this.DV; // y == 1/x mod 2^dbits + // we really want the negative inverse, and -DV < y < DV + return (y>0)?this.DV-y:-y; +} + +// Montgomery reduction +function Montgomery(m) { + this.m = m; + this.mp = m.invDigit(); + this.mpl = this.mp&0x7fff; + this.mph = this.mp>>15; + this.um = (1<<(m.DB-15))-1; + this.mt2 = 2*m.t; +} + +// xR mod m +function montConvert(x) { + var r = nbi(); + x.abs().dlShiftTo(this.m.t,r); + r.divRemTo(this.m,null,r); + if(x.s < 0 && r.compareTo(BigInteger$4.ZERO) > 0) this.m.subTo(r,r); + return r; +} + +// x/R mod m +function montRevert(x) { + var r = nbi(); + x.copyTo(r); + this.reduce(r); + return r; +} + +// x = x/R mod m (HAC 14.32) +function montReduce(x) { + while(x.t <= this.mt2) // pad x so am has enough room later + x.data[x.t++] = 0; + for(var i = 0; i < this.m.t; ++i) { + // faster way of calculating u0 = x.data[i]*mp mod DV + var j = x.data[i]&0x7fff; + var u0 = (j*this.mpl+(((j*this.mph+(x.data[i]>>15)*this.mpl)&this.um)<<15))&x.DM; + // use am to combine the multiply-shift-add into one call + j = i+this.m.t; + x.data[j] += this.m.am(0,u0,x,i,0,this.m.t); + // propagate carry + while(x.data[j] >= x.DV) { x.data[j] -= x.DV; x.data[++j]++; } + } + x.clamp(); + x.drShiftTo(this.m.t,x); + if(x.compareTo(this.m) >= 0) x.subTo(this.m,x); +} + +// r = "x^2/R mod m"; x != r +function montSqrTo(x,r) { x.squareTo(r); this.reduce(r); } + +// r = "xy/R mod m"; x,y != r +function montMulTo(x,y,r) { x.multiplyTo(y,r); this.reduce(r); } + +Montgomery.prototype.convert = montConvert; +Montgomery.prototype.revert = montRevert; +Montgomery.prototype.reduce = montReduce; +Montgomery.prototype.mulTo = montMulTo; +Montgomery.prototype.sqrTo = montSqrTo; + +// (protected) true iff this is even +function bnpIsEven() { return ((this.t>0)?(this.data[0]&1):this.s) == 0; } + +// (protected) this^e, e < 2^32, doing sqr and mul with "r" (HAC 14.79) +function bnpExp(e,z) { + if(e > 0xffffffff || e < 1) return BigInteger$4.ONE; + var r = nbi(), r2 = nbi(), g = z.convert(this), i = nbits(e)-1; + g.copyTo(r); + while(--i >= 0) { + z.sqrTo(r,r2); + if((e&(1< 0) z.mulTo(r2,g,r); + else { var t = r; r = r2; r2 = t; } + } + return z.revert(r); +} + +// (public) this^e % m, 0 <= e < 2^32 +function bnModPowInt(e,m) { + var z; + if(e < 256 || m.isEven()) z = new Classic(m); else z = new Montgomery(m); + return this.exp(e,z); +} + +// protected +BigInteger$4.prototype.copyTo = bnpCopyTo; +BigInteger$4.prototype.fromInt = bnpFromInt; +BigInteger$4.prototype.fromString = bnpFromString; +BigInteger$4.prototype.clamp = bnpClamp; +BigInteger$4.prototype.dlShiftTo = bnpDLShiftTo; +BigInteger$4.prototype.drShiftTo = bnpDRShiftTo; +BigInteger$4.prototype.lShiftTo = bnpLShiftTo; +BigInteger$4.prototype.rShiftTo = bnpRShiftTo; +BigInteger$4.prototype.subTo = bnpSubTo; +BigInteger$4.prototype.multiplyTo = bnpMultiplyTo; +BigInteger$4.prototype.squareTo = bnpSquareTo; +BigInteger$4.prototype.divRemTo = bnpDivRemTo; +BigInteger$4.prototype.invDigit = bnpInvDigit; +BigInteger$4.prototype.isEven = bnpIsEven; +BigInteger$4.prototype.exp = bnpExp; + +// public +BigInteger$4.prototype.toString = bnToString; +BigInteger$4.prototype.negate = bnNegate; +BigInteger$4.prototype.abs = bnAbs; +BigInteger$4.prototype.compareTo = bnCompareTo; +BigInteger$4.prototype.bitLength = bnBitLength; +BigInteger$4.prototype.mod = bnMod; +BigInteger$4.prototype.modPowInt = bnModPowInt; + +// "constants" +BigInteger$4.ZERO = nbv(0); +BigInteger$4.ONE = nbv(1); + +// jsbn2 lib + +//Copyright (c) 2005-2009 Tom Wu +//All Rights Reserved. +//See "LICENSE" for details (See jsbn.js for LICENSE). + +//Extended JavaScript BN functions, required for RSA private ops. + +//Version 1.1: new BigInteger("0", 10) returns "proper" zero + +//(public) +function bnClone() { var r = nbi(); this.copyTo(r); return r; } + +//(public) return value as integer +function bnIntValue() { +if(this.s < 0) { + if(this.t == 1) return this.data[0]-this.DV; + else if(this.t == 0) return -1; +} else if(this.t == 1) return this.data[0]; +else if(this.t == 0) return 0; +// assumes 16 < DB < 32 +return ((this.data[1]&((1<<(32-this.DB))-1))<>24; } + +//(public) return value as short (assumes DB>=16) +function bnShortValue() { return (this.t==0)?this.s:(this.data[0]<<16)>>16; } + +//(protected) return x s.t. r^x < DV +function bnpChunkSize(r) { return Math.floor(Math.LN2*this.DB/Math.log(r)); } + +//(public) 0 if this == 0, 1 if this > 0 +function bnSigNum() { +if(this.s < 0) return -1; +else if(this.t <= 0 || (this.t == 1 && this.data[0] <= 0)) return 0; +else return 1; +} + +//(protected) convert to radix string +function bnpToRadix(b) { +if(b == null) b = 10; +if(this.signum() == 0 || b < 2 || b > 36) return "0"; +var cs = this.chunkSize(b); +var a = Math.pow(b,cs); +var d = nbv(a), y = nbi(), z = nbi(), r = ""; +this.divRemTo(d,y,z); +while(y.signum() > 0) { + r = (a+z.intValue()).toString(b).substr(1) + r; + y.divRemTo(d,y,z); +} +return z.intValue().toString(b) + r; +} + +//(protected) convert from radix string +function bnpFromRadix(s,b) { +this.fromInt(0); +if(b == null) b = 10; +var cs = this.chunkSize(b); +var d = Math.pow(b,cs), mi = false, j = 0, w = 0; +for(var i = 0; i < s.length; ++i) { + var x = intAt(s,i); + if(x < 0) { + if(s.charAt(i) == "-" && this.signum() == 0) mi = true; + continue; + } + w = b*w+x; + if(++j >= cs) { + this.dMultiply(d); + this.dAddOffset(w,0); + j = 0; + w = 0; + } +} +if(j > 0) { + this.dMultiply(Math.pow(b,j)); + this.dAddOffset(w,0); +} +if(mi) BigInteger$4.ZERO.subTo(this,this); +} + +//(protected) alternate constructor +function bnpFromNumber(a,b,c) { +if("number" == typeof b) { + // new BigInteger(int,int,RNG) + if(a < 2) this.fromInt(1); + else { + this.fromNumber(a,c); + if(!this.testBit(a-1)) // force MSB set + this.bitwiseTo(BigInteger$4.ONE.shiftLeft(a-1),op_or,this); + if(this.isEven()) this.dAddOffset(1,0); // force odd + while(!this.isProbablePrime(b)) { + this.dAddOffset(2,0); + if(this.bitLength() > a) this.subTo(BigInteger$4.ONE.shiftLeft(a-1),this); + } + } +} else { + // new BigInteger(int,RNG) + var x = new Array(), t = a&7; + x.length = (a>>3)+1; + b.nextBytes(x); + if(t > 0) x[0] &= ((1< 0) { + if(p < this.DB && (d = this.data[i]>>p) != (this.s&this.DM)>>p) + r[k++] = d|(this.s<<(this.DB-p)); + while(i >= 0) { + if(p < 8) { + d = (this.data[i]&((1<>(p+=this.DB-8); + } else { + d = (this.data[i]>>(p-=8))&0xff; + if(p <= 0) { p += this.DB; --i; } + } + if((d&0x80) != 0) d |= -256; + if(k == 0 && (this.s&0x80) != (d&0x80)) ++k; + if(k > 0 || d != this.s) r[k++] = d; + } +} +return r; +} + +function bnEquals(a) { return(this.compareTo(a)==0); } +function bnMin(a) { return (this.compareTo(a)<0)?this:a; } +function bnMax(a) { return (this.compareTo(a)>0)?this:a; } + +//(protected) r = this op a (bitwise) +function bnpBitwiseTo(a,op,r) { +var i, f, m = Math.min(a.t,this.t); +for(i = 0; i < m; ++i) r.data[i] = op(this.data[i],a.data[i]); +if(a.t < this.t) { + f = a.s&this.DM; + for(i = m; i < this.t; ++i) r.data[i] = op(this.data[i],f); + r.t = this.t; +} else { + f = this.s&this.DM; + for(i = m; i < a.t; ++i) r.data[i] = op(f,a.data[i]); + r.t = a.t; +} +r.s = op(this.s,a.s); +r.clamp(); +} + +//(public) this & a +function op_and(x,y) { return x&y; } +function bnAnd(a) { var r = nbi(); this.bitwiseTo(a,op_and,r); return r; } + +//(public) this | a +function op_or(x,y) { return x|y; } +function bnOr(a) { var r = nbi(); this.bitwiseTo(a,op_or,r); return r; } + +//(public) this ^ a +function op_xor(x,y) { return x^y; } +function bnXor(a) { var r = nbi(); this.bitwiseTo(a,op_xor,r); return r; } + +//(public) this & ~a +function op_andnot(x,y) { return x&~y; } +function bnAndNot(a) { var r = nbi(); this.bitwiseTo(a,op_andnot,r); return r; } + +//(public) ~this +function bnNot() { +var r = nbi(); +for(var i = 0; i < this.t; ++i) r.data[i] = this.DM&~this.data[i]; +r.t = this.t; +r.s = ~this.s; +return r; +} + +//(public) this << n +function bnShiftLeft(n) { +var r = nbi(); +if(n < 0) this.rShiftTo(-n,r); else this.lShiftTo(n,r); +return r; +} + +//(public) this >> n +function bnShiftRight(n) { +var r = nbi(); +if(n < 0) this.lShiftTo(-n,r); else this.rShiftTo(n,r); +return r; +} + +//return index of lowest 1-bit in x, x < 2^31 +function lbit(x) { +if(x == 0) return -1; +var r = 0; +if((x&0xffff) == 0) { x >>= 16; r += 16; } +if((x&0xff) == 0) { x >>= 8; r += 8; } +if((x&0xf) == 0) { x >>= 4; r += 4; } +if((x&3) == 0) { x >>= 2; r += 2; } +if((x&1) == 0) ++r; +return r; +} + +//(public) returns index of lowest 1-bit (or -1 if none) +function bnGetLowestSetBit() { +for(var i = 0; i < this.t; ++i) + if(this.data[i] != 0) return i*this.DB+lbit(this.data[i]); +if(this.s < 0) return this.t*this.DB; +return -1; +} + +//return number of 1 bits in x +function cbit(x) { +var r = 0; +while(x != 0) { x &= x-1; ++r; } +return r; +} + +//(public) return number of set bits +function bnBitCount() { +var r = 0, x = this.s&this.DM; +for(var i = 0; i < this.t; ++i) r += cbit(this.data[i]^x); +return r; +} + +//(public) true iff nth bit is set +function bnTestBit(n) { +var j = Math.floor(n/this.DB); +if(j >= this.t) return(this.s!=0); +return((this.data[j]&(1<<(n%this.DB)))!=0); +} + +//(protected) this op (1<>= this.DB; +} +if(a.t < this.t) { + c += a.s; + while(i < this.t) { + c += this.data[i]; + r.data[i++] = c&this.DM; + c >>= this.DB; + } + c += this.s; +} else { + c += this.s; + while(i < a.t) { + c += a.data[i]; + r.data[i++] = c&this.DM; + c >>= this.DB; + } + c += a.s; +} +r.s = (c<0)?-1:0; +if(c > 0) r.data[i++] = c; +else if(c < -1) r.data[i++] = this.DV+c; +r.t = i; +r.clamp(); +} + +//(public) this + a +function bnAdd(a) { var r = nbi(); this.addTo(a,r); return r; } + +//(public) this - a +function bnSubtract(a) { var r = nbi(); this.subTo(a,r); return r; } + +//(public) this * a +function bnMultiply(a) { var r = nbi(); this.multiplyTo(a,r); return r; } + +//(public) this / a +function bnDivide(a) { var r = nbi(); this.divRemTo(a,r,null); return r; } + +//(public) this % a +function bnRemainder(a) { var r = nbi(); this.divRemTo(a,null,r); return r; } + +//(public) [this/a,this%a] +function bnDivideAndRemainder(a) { +var q = nbi(), r = nbi(); +this.divRemTo(a,q,r); +return new Array(q,r); +} + +//(protected) this *= n, this >= 0, 1 < n < DV +function bnpDMultiply(n) { +this.data[this.t] = this.am(0,n-1,this,0,0,this.t); +++this.t; +this.clamp(); +} + +//(protected) this += n << w words, this >= 0 +function bnpDAddOffset(n,w) { +if(n == 0) return; +while(this.t <= w) this.data[this.t++] = 0; +this.data[w] += n; +while(this.data[w] >= this.DV) { + this.data[w] -= this.DV; + if(++w >= this.t) this.data[this.t++] = 0; + ++this.data[w]; +} +} + +//A "null" reducer +function NullExp() {} +function nNop(x) { return x; } +function nMulTo(x,y,r) { x.multiplyTo(y,r); } +function nSqrTo(x,r) { x.squareTo(r); } + +NullExp.prototype.convert = nNop; +NullExp.prototype.revert = nNop; +NullExp.prototype.mulTo = nMulTo; +NullExp.prototype.sqrTo = nSqrTo; + +//(public) this^e +function bnPow(e) { return this.exp(e,new NullExp()); } + +//(protected) r = lower n words of "this * a", a.t <= n +//"this" should be the larger one if appropriate. +function bnpMultiplyLowerTo(a,n,r) { +var i = Math.min(this.t+a.t,n); +r.s = 0; // assumes a,this >= 0 +r.t = i; +while(i > 0) r.data[--i] = 0; +var j; +for(j = r.t-this.t; i < j; ++i) r.data[i+this.t] = this.am(0,a.data[i],r,i,0,this.t); +for(j = Math.min(a.t,n); i < j; ++i) this.am(0,a.data[i],r,i,0,n-i); +r.clamp(); +} + +//(protected) r = "this * a" without lower n words, n > 0 +//"this" should be the larger one if appropriate. +function bnpMultiplyUpperTo(a,n,r) { +--n; +var i = r.t = this.t+a.t-n; +r.s = 0; // assumes a,this >= 0 +while(--i >= 0) r.data[i] = 0; +for(i = Math.max(n-this.t,0); i < a.t; ++i) + r.data[this.t+i-n] = this.am(n-i,a.data[i],r,0,0,this.t+i-n); +r.clamp(); +r.drShiftTo(1,r); +} + +//Barrett modular reduction +function Barrett(m) { +// setup Barrett +this.r2 = nbi(); +this.q3 = nbi(); +BigInteger$4.ONE.dlShiftTo(2*m.t,this.r2); +this.mu = this.r2.divide(m); +this.m = m; +} + +function barrettConvert(x) { +if(x.s < 0 || x.t > 2*this.m.t) return x.mod(this.m); +else if(x.compareTo(this.m) < 0) return x; +else { var r = nbi(); x.copyTo(r); this.reduce(r); return r; } +} + +function barrettRevert(x) { return x; } + +//x = x mod m (HAC 14.42) +function barrettReduce(x) { +x.drShiftTo(this.m.t-1,this.r2); +if(x.t > this.m.t+1) { x.t = this.m.t+1; x.clamp(); } +this.mu.multiplyUpperTo(this.r2,this.m.t+1,this.q3); +this.m.multiplyLowerTo(this.q3,this.m.t+1,this.r2); +while(x.compareTo(this.r2) < 0) x.dAddOffset(1,this.m.t+1); +x.subTo(this.r2,x); +while(x.compareTo(this.m) >= 0) x.subTo(this.m,x); +} + +//r = x^2 mod m; x != r +function barrettSqrTo(x,r) { x.squareTo(r); this.reduce(r); } + +//r = x*y mod m; x,y != r +function barrettMulTo(x,y,r) { x.multiplyTo(y,r); this.reduce(r); } + +Barrett.prototype.convert = barrettConvert; +Barrett.prototype.revert = barrettRevert; +Barrett.prototype.reduce = barrettReduce; +Barrett.prototype.mulTo = barrettMulTo; +Barrett.prototype.sqrTo = barrettSqrTo; + +//(public) this^e % m (HAC 14.85) +function bnModPow(e,m) { +var i = e.bitLength(), k, r = nbv(1), z; +if(i <= 0) return r; +else if(i < 18) k = 1; +else if(i < 48) k = 3; +else if(i < 144) k = 4; +else if(i < 768) k = 5; +else k = 6; +if(i < 8) + z = new Classic(m); +else if(m.isEven()) + z = new Barrett(m); +else + z = new Montgomery(m); + +// precomputation +var g = new Array(), n = 3, k1 = k-1, km = (1< 1) { + var g2 = nbi(); + z.sqrTo(g[1],g2); + while(n <= km) { + g[n] = nbi(); + z.mulTo(g2,g[n-2],g[n]); + n += 2; + } +} + +var j = e.t-1, w, is1 = true, r2 = nbi(), t; +i = nbits(e.data[j])-1; +while(j >= 0) { + if(i >= k1) w = (e.data[j]>>(i-k1))&km; + else { + w = (e.data[j]&((1<<(i+1))-1))<<(k1-i); + if(j > 0) w |= e.data[j-1]>>(this.DB+i-k1); + } + + n = k; + while((w&1) == 0) { w >>= 1; --n; } + if((i -= n) < 0) { i += this.DB; --j; } + if(is1) { // ret == 1, don't bother squaring or multiplying it + g[w].copyTo(r); + is1 = false; + } else { + while(n > 1) { z.sqrTo(r,r2); z.sqrTo(r2,r); n -= 2; } + if(n > 0) z.sqrTo(r,r2); else { t = r; r = r2; r2 = t; } + z.mulTo(r2,g[w],r); + } + + while(j >= 0 && (e.data[j]&(1< 0) { + x.rShiftTo(g,x); + y.rShiftTo(g,y); +} +while(x.signum() > 0) { + if((i = x.getLowestSetBit()) > 0) x.rShiftTo(i,x); + if((i = y.getLowestSetBit()) > 0) y.rShiftTo(i,y); + if(x.compareTo(y) >= 0) { + x.subTo(y,x); + x.rShiftTo(1,x); + } else { + y.subTo(x,y); + y.rShiftTo(1,y); + } +} +if(g > 0) y.lShiftTo(g,y); +return y; +} + +//(protected) this % n, n < 2^26 +function bnpModInt(n) { +if(n <= 0) return 0; +var d = this.DV%n, r = (this.s<0)?n-1:0; +if(this.t > 0) + if(d == 0) r = this.data[0]%n; + else for(var i = this.t-1; i >= 0; --i) r = (d*r+this.data[i])%n; +return r; +} + +//(public) 1/this % m (HAC 14.61) +function bnModInverse(m) { +var ac = m.isEven(); +if((this.isEven() && ac) || m.signum() == 0) return BigInteger$4.ZERO; +var u = m.clone(), v = this.clone(); +var a = nbv(1), b = nbv(0), c = nbv(0), d = nbv(1); +while(u.signum() != 0) { + while(u.isEven()) { + u.rShiftTo(1,u); + if(ac) { + if(!a.isEven() || !b.isEven()) { a.addTo(this,a); b.subTo(m,b); } + a.rShiftTo(1,a); + } else if(!b.isEven()) b.subTo(m,b); + b.rShiftTo(1,b); + } + while(v.isEven()) { + v.rShiftTo(1,v); + if(ac) { + if(!c.isEven() || !d.isEven()) { c.addTo(this,c); d.subTo(m,d); } + c.rShiftTo(1,c); + } else if(!d.isEven()) d.subTo(m,d); + d.rShiftTo(1,d); + } + if(u.compareTo(v) >= 0) { + u.subTo(v,u); + if(ac) a.subTo(c,a); + b.subTo(d,b); + } else { + v.subTo(u,v); + if(ac) c.subTo(a,c); + d.subTo(b,d); + } +} +if(v.compareTo(BigInteger$4.ONE) != 0) return BigInteger$4.ZERO; +if(d.compareTo(m) >= 0) return d.subtract(m); +if(d.signum() < 0) d.addTo(m,d); else return d; +if(d.signum() < 0) return d.add(m); else return d; +} + +var lowprimes = [2,3,5,7,11,13,17,19,23,29,31,37,41,43,47,53,59,61,67,71,73,79,83,89,97,101,103,107,109,113,127,131,137,139,149,151,157,163,167,173,179,181,191,193,197,199,211,223,227,229,233,239,241,251,257,263,269,271,277,281,283,293,307,311,313,317,331,337,347,349,353,359,367,373,379,383,389,397,401,409,419,421,431,433,439,443,449,457,461,463,467,479,487,491,499,503,509]; +var lplim = (1<<26)/lowprimes[lowprimes.length-1]; + +//(public) test primality with certainty >= 1-.5^t +function bnIsProbablePrime(t) { +var i, x = this.abs(); +if(x.t == 1 && x.data[0] <= lowprimes[lowprimes.length-1]) { + for(i = 0; i < lowprimes.length; ++i) + if(x.data[0] == lowprimes[i]) return true; + return false; +} +if(x.isEven()) return false; +i = 1; +while(i < lowprimes.length) { + var m = lowprimes[i], j = i+1; + while(j < lowprimes.length && m < lplim) m *= lowprimes[j++]; + m = x.modInt(m); + while(i < j) if(m%lowprimes[i++] == 0) return false; +} +return x.millerRabin(t); +} + +//(protected) true if probably prime (HAC 4.24, Miller-Rabin) +function bnpMillerRabin(t) { +var n1 = this.subtract(BigInteger$4.ONE); +var k = n1.getLowestSetBit(); +if(k <= 0) return false; +var r = n1.shiftRight(k); +var prng = bnGetPrng(); +var a; +for(var i = 0; i < t; ++i) { + // select witness 'a' at random from between 1 and n1 + do { + a = new BigInteger$4(this.bitLength(), prng); + } + while(a.compareTo(BigInteger$4.ONE) <= 0 || a.compareTo(n1) >= 0); + var y = a.modPow(r,this); + if(y.compareTo(BigInteger$4.ONE) != 0 && y.compareTo(n1) != 0) { + var j = 1; + while(j++ < k && y.compareTo(n1) != 0) { + y = y.modPowInt(2,this); + if(y.compareTo(BigInteger$4.ONE) == 0) return false; + } + if(y.compareTo(n1) != 0) return false; + } +} +return true; +} + +// get pseudo random number generator +function bnGetPrng() { + // create prng with api that matches BigInteger secure random + return { + // x is an array to fill with bytes + nextBytes: function(x) { + for(var i = 0; i < x.length; ++i) { + x[i] = Math.floor(Math.random() * 0x0100); + } + } + }; +} + +//protected +BigInteger$4.prototype.chunkSize = bnpChunkSize; +BigInteger$4.prototype.toRadix = bnpToRadix; +BigInteger$4.prototype.fromRadix = bnpFromRadix; +BigInteger$4.prototype.fromNumber = bnpFromNumber; +BigInteger$4.prototype.bitwiseTo = bnpBitwiseTo; +BigInteger$4.prototype.changeBit = bnpChangeBit; +BigInteger$4.prototype.addTo = bnpAddTo; +BigInteger$4.prototype.dMultiply = bnpDMultiply; +BigInteger$4.prototype.dAddOffset = bnpDAddOffset; +BigInteger$4.prototype.multiplyLowerTo = bnpMultiplyLowerTo; +BigInteger$4.prototype.multiplyUpperTo = bnpMultiplyUpperTo; +BigInteger$4.prototype.modInt = bnpModInt; +BigInteger$4.prototype.millerRabin = bnpMillerRabin; + +//public +BigInteger$4.prototype.clone = bnClone; +BigInteger$4.prototype.intValue = bnIntValue; +BigInteger$4.prototype.byteValue = bnByteValue; +BigInteger$4.prototype.shortValue = bnShortValue; +BigInteger$4.prototype.signum = bnSigNum; +BigInteger$4.prototype.toByteArray = bnToByteArray; +BigInteger$4.prototype.equals = bnEquals; +BigInteger$4.prototype.min = bnMin; +BigInteger$4.prototype.max = bnMax; +BigInteger$4.prototype.and = bnAnd; +BigInteger$4.prototype.or = bnOr; +BigInteger$4.prototype.xor = bnXor; +BigInteger$4.prototype.andNot = bnAndNot; +BigInteger$4.prototype.not = bnNot; +BigInteger$4.prototype.shiftLeft = bnShiftLeft; +BigInteger$4.prototype.shiftRight = bnShiftRight; +BigInteger$4.prototype.getLowestSetBit = bnGetLowestSetBit; +BigInteger$4.prototype.bitCount = bnBitCount; +BigInteger$4.prototype.testBit = bnTestBit; +BigInteger$4.prototype.setBit = bnSetBit; +BigInteger$4.prototype.clearBit = bnClearBit; +BigInteger$4.prototype.flipBit = bnFlipBit; +BigInteger$4.prototype.add = bnAdd; +BigInteger$4.prototype.subtract = bnSubtract; +BigInteger$4.prototype.multiply = bnMultiply; +BigInteger$4.prototype.divide = bnDivide; +BigInteger$4.prototype.remainder = bnRemainder; +BigInteger$4.prototype.divideAndRemainder = bnDivideAndRemainder; +BigInteger$4.prototype.modPow = bnModPow; +BigInteger$4.prototype.modInverse = bnModInverse; +BigInteger$4.prototype.pow = bnPow; +BigInteger$4.prototype.gcd = bnGCD; +BigInteger$4.prototype.isProbablePrime = bnIsProbablePrime; + +/** + * Secure Hash Algorithm with 160-bit digest (SHA-1) implementation. + * + * @author Dave Longley + * + * Copyright (c) 2010-2015 Digital Bazaar, Inc. + */ + +var forge$l = forge$D; + + + +var sha1 = forge$l.sha1 = forge$l.sha1 || {}; +forge$l.md.sha1 = forge$l.md.algorithms.sha1 = sha1; + +/** + * Creates a SHA-1 message digest object. + * + * @return a message digest object. + */ +sha1.create = function() { + // do initialization as necessary + if(!_initialized$1) { + _init$1(); + } + + // SHA-1 state contains five 32-bit integers + var _state = null; + + // input buffer + var _input = forge$l.util.createBuffer(); + + // used for word storage + var _w = new Array(80); + + // message digest object + var md = { + algorithm: 'sha1', + blockLength: 64, + digestLength: 20, + // 56-bit length of message so far (does not including padding) + messageLength: 0, + // true message length + fullMessageLength: null, + // size of message length in bytes + messageLengthSize: 8 + }; + + /** + * Starts the digest. + * + * @return this digest object. + */ + md.start = function() { + // up to 56-bit message length for convenience + md.messageLength = 0; + + // full message length (set md.messageLength64 for backwards-compatibility) + md.fullMessageLength = md.messageLength64 = []; + var int32s = md.messageLengthSize / 4; + for(var i = 0; i < int32s; ++i) { + md.fullMessageLength.push(0); + } + _input = forge$l.util.createBuffer(); + _state = { + h0: 0x67452301, + h1: 0xEFCDAB89, + h2: 0x98BADCFE, + h3: 0x10325476, + h4: 0xC3D2E1F0 + }; + return md; + }; + // start digest automatically for first time + md.start(); + + /** + * Updates the digest with the given message input. The given input can + * treated as raw input (no encoding will be applied) or an encoding of + * 'utf8' maybe given to encode the input using UTF-8. + * + * @param msg the message input to update with. + * @param encoding the encoding to use (default: 'raw', other: 'utf8'). + * + * @return this digest object. + */ + md.update = function(msg, encoding) { + if(encoding === 'utf8') { + msg = forge$l.util.encodeUtf8(msg); + } + + // update message length + var len = msg.length; + md.messageLength += len; + len = [(len / 0x100000000) >>> 0, len >>> 0]; + for(var i = md.fullMessageLength.length - 1; i >= 0; --i) { + md.fullMessageLength[i] += len[1]; + len[1] = len[0] + ((md.fullMessageLength[i] / 0x100000000) >>> 0); + md.fullMessageLength[i] = md.fullMessageLength[i] >>> 0; + len[0] = ((len[1] / 0x100000000) >>> 0); + } + + // add bytes to input buffer + _input.putBytes(msg); + + // process bytes + _update$1(_state, _w, _input); + + // compact input buffer every 2K or if empty + if(_input.read > 2048 || _input.length() === 0) { + _input.compact(); + } + + return md; + }; + + /** + * Produces the digest. + * + * @return a byte buffer containing the digest value. + */ + md.digest = function() { + /* Note: Here we copy the remaining bytes in the input buffer and + add the appropriate SHA-1 padding. Then we do the final update + on a copy of the state so that if the user wants to get + intermediate digests they can do so. */ + + /* Determine the number of bytes that must be added to the message + to ensure its length is congruent to 448 mod 512. In other words, + the data to be digested must be a multiple of 512 bits (or 128 bytes). + This data includes the message, some padding, and the length of the + message. Since the length of the message will be encoded as 8 bytes (64 + bits), that means that the last segment of the data must have 56 bytes + (448 bits) of message and padding. Therefore, the length of the message + plus the padding must be congruent to 448 mod 512 because + 512 - 128 = 448. + + In order to fill up the message length it must be filled with + padding that begins with 1 bit followed by all 0 bits. Padding + must *always* be present, so if the message length is already + congruent to 448 mod 512, then 512 padding bits must be added. */ + + var finalBlock = forge$l.util.createBuffer(); + finalBlock.putBytes(_input.bytes()); + + // compute remaining size to be digested (include message length size) + var remaining = ( + md.fullMessageLength[md.fullMessageLength.length - 1] + + md.messageLengthSize); + + // add padding for overflow blockSize - overflow + // _padding starts with 1 byte with first bit is set (byte value 128), then + // there may be up to (blockSize - 1) other pad bytes + var overflow = remaining & (md.blockLength - 1); + finalBlock.putBytes(_padding$1.substr(0, md.blockLength - overflow)); + + // serialize message length in bits in big-endian order; since length + // is stored in bytes we multiply by 8 and add carry from next int + var next, carry; + var bits = md.fullMessageLength[0] * 8; + for(var i = 0; i < md.fullMessageLength.length - 1; ++i) { + next = md.fullMessageLength[i + 1] * 8; + carry = (next / 0x100000000) >>> 0; + bits += carry; + finalBlock.putInt32(bits >>> 0); + bits = next >>> 0; + } + finalBlock.putInt32(bits); + + var s2 = { + h0: _state.h0, + h1: _state.h1, + h2: _state.h2, + h3: _state.h3, + h4: _state.h4 + }; + _update$1(s2, _w, finalBlock); + var rval = forge$l.util.createBuffer(); + rval.putInt32(s2.h0); + rval.putInt32(s2.h1); + rval.putInt32(s2.h2); + rval.putInt32(s2.h3); + rval.putInt32(s2.h4); + return rval; + }; + + return md; +}; + +// sha-1 padding bytes not initialized yet +var _padding$1 = null; +var _initialized$1 = false; + +/** + * Initializes the constant tables. + */ +function _init$1() { + // create padding + _padding$1 = String.fromCharCode(128); + _padding$1 += forge$l.util.fillString(String.fromCharCode(0x00), 64); + + // now initialized + _initialized$1 = true; +} + +/** + * Updates a SHA-1 state with the given byte buffer. + * + * @param s the SHA-1 state to update. + * @param w the array to use to store words. + * @param bytes the byte buffer to update with. + */ +function _update$1(s, w, bytes) { + // consume 512 bit (64 byte) chunks + var t, a, b, c, d, e, f, i; + var len = bytes.length(); + while(len >= 64) { + // the w array will be populated with sixteen 32-bit big-endian words + // and then extended into 80 32-bit words according to SHA-1 algorithm + // and for 32-79 using Max Locktyukhin's optimization + + // initialize hash value for this chunk + a = s.h0; + b = s.h1; + c = s.h2; + d = s.h3; + e = s.h4; + + // round 1 + for(i = 0; i < 16; ++i) { + t = bytes.getInt32(); + w[i] = t; + f = d ^ (b & (c ^ d)); + t = ((a << 5) | (a >>> 27)) + f + e + 0x5A827999 + t; + e = d; + d = c; + // `>>> 0` necessary to avoid iOS/Safari 10 optimization bug + c = ((b << 30) | (b >>> 2)) >>> 0; + b = a; + a = t; + } + for(; i < 20; ++i) { + t = (w[i - 3] ^ w[i - 8] ^ w[i - 14] ^ w[i - 16]); + t = (t << 1) | (t >>> 31); + w[i] = t; + f = d ^ (b & (c ^ d)); + t = ((a << 5) | (a >>> 27)) + f + e + 0x5A827999 + t; + e = d; + d = c; + // `>>> 0` necessary to avoid iOS/Safari 10 optimization bug + c = ((b << 30) | (b >>> 2)) >>> 0; + b = a; + a = t; + } + // round 2 + for(; i < 32; ++i) { + t = (w[i - 3] ^ w[i - 8] ^ w[i - 14] ^ w[i - 16]); + t = (t << 1) | (t >>> 31); + w[i] = t; + f = b ^ c ^ d; + t = ((a << 5) | (a >>> 27)) + f + e + 0x6ED9EBA1 + t; + e = d; + d = c; + // `>>> 0` necessary to avoid iOS/Safari 10 optimization bug + c = ((b << 30) | (b >>> 2)) >>> 0; + b = a; + a = t; + } + for(; i < 40; ++i) { + t = (w[i - 6] ^ w[i - 16] ^ w[i - 28] ^ w[i - 32]); + t = (t << 2) | (t >>> 30); + w[i] = t; + f = b ^ c ^ d; + t = ((a << 5) | (a >>> 27)) + f + e + 0x6ED9EBA1 + t; + e = d; + d = c; + // `>>> 0` necessary to avoid iOS/Safari 10 optimization bug + c = ((b << 30) | (b >>> 2)) >>> 0; + b = a; + a = t; + } + // round 3 + for(; i < 60; ++i) { + t = (w[i - 6] ^ w[i - 16] ^ w[i - 28] ^ w[i - 32]); + t = (t << 2) | (t >>> 30); + w[i] = t; + f = (b & c) | (d & (b ^ c)); + t = ((a << 5) | (a >>> 27)) + f + e + 0x8F1BBCDC + t; + e = d; + d = c; + // `>>> 0` necessary to avoid iOS/Safari 10 optimization bug + c = ((b << 30) | (b >>> 2)) >>> 0; + b = a; + a = t; + } + // round 4 + for(; i < 80; ++i) { + t = (w[i - 6] ^ w[i - 16] ^ w[i - 28] ^ w[i - 32]); + t = (t << 2) | (t >>> 30); + w[i] = t; + f = b ^ c ^ d; + t = ((a << 5) | (a >>> 27)) + f + e + 0xCA62C1D6 + t; + e = d; + d = c; + // `>>> 0` necessary to avoid iOS/Safari 10 optimization bug + c = ((b << 30) | (b >>> 2)) >>> 0; + b = a; + a = t; + } + + // update hash state + s.h0 = (s.h0 + a) | 0; + s.h1 = (s.h1 + b) | 0; + s.h2 = (s.h2 + c) | 0; + s.h3 = (s.h3 + d) | 0; + s.h4 = (s.h4 + e) | 0; + + len -= 64; + } +} + +/** + * Partial implementation of PKCS#1 v2.2: RSA-OEAP + * + * Modified but based on the following MIT and BSD licensed code: + * + * https://github.com/kjur/jsjws/blob/master/rsa.js: + * + * The 'jsjws'(JSON Web Signature JavaScript Library) License + * + * Copyright (c) 2012 Kenji Urushima + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + * + * http://webrsa.cvs.sourceforge.net/viewvc/webrsa/Client/RSAES-OAEP.js?content-type=text%2Fplain: + * + * RSAES-OAEP.js + * $Id: RSAES-OAEP.js,v 1.1.1.1 2003/03/19 15:37:20 ellispritchard Exp $ + * JavaScript Implementation of PKCS #1 v2.1 RSA CRYPTOGRAPHY STANDARD (RSA Laboratories, June 14, 2002) + * Copyright (C) Ellis Pritchard, Guardian Unlimited 2003. + * Contact: ellis@nukinetics.com + * Distributed under the BSD License. + * + * Official documentation: http://www.rsa.com/rsalabs/node.asp?id=2125 + * + * @author Evan Jones (http://evanjones.ca/) + * @author Dave Longley + * + * Copyright (c) 2013-2014 Digital Bazaar, Inc. + */ + +var forge$k = forge$D; + + + + +// shortcut for PKCS#1 API +var pkcs1 = forge$k.pkcs1 = forge$k.pkcs1 || {}; + +/** + * Encode the given RSAES-OAEP message (M) using key, with optional label (L) + * and seed. + * + * This method does not perform RSA encryption, it only encodes the message + * using RSAES-OAEP. + * + * @param key the RSA key to use. + * @param message the message to encode. + * @param options the options to use: + * label an optional label to use. + * seed the seed to use. + * md the message digest object to use, undefined for SHA-1. + * mgf1 optional mgf1 parameters: + * md the message digest object to use for MGF1. + * + * @return the encoded message bytes. + */ +pkcs1.encode_rsa_oaep = function(key, message, options) { + // parse arguments + var label; + var seed; + var md; + var mgf1Md; + // legacy args (label, seed, md) + if(typeof options === 'string') { + label = options; + seed = arguments[3] || undefined; + md = arguments[4] || undefined; + } else if(options) { + label = options.label || undefined; + seed = options.seed || undefined; + md = options.md || undefined; + if(options.mgf1 && options.mgf1.md) { + mgf1Md = options.mgf1.md; + } + } + + // default OAEP to SHA-1 message digest + if(!md) { + md = forge$k.md.sha1.create(); + } else { + md.start(); + } + + // default MGF-1 to same as OAEP + if(!mgf1Md) { + mgf1Md = md; + } + + // compute length in bytes and check output + var keyLength = Math.ceil(key.n.bitLength() / 8); + var maxLength = keyLength - 2 * md.digestLength - 2; + if(message.length > maxLength) { + var error = new Error('RSAES-OAEP input message length is too long.'); + error.length = message.length; + error.maxLength = maxLength; + throw error; + } + + if(!label) { + label = ''; + } + md.update(label, 'raw'); + var lHash = md.digest(); + + var PS = ''; + var PS_length = maxLength - message.length; + for(var i = 0; i < PS_length; i++) { + PS += '\x00'; + } + + var DB = lHash.getBytes() + PS + '\x01' + message; + + if(!seed) { + seed = forge$k.random.getBytes(md.digestLength); + } else if(seed.length !== md.digestLength) { + var error = new Error('Invalid RSAES-OAEP seed. The seed length must ' + + 'match the digest length.'); + error.seedLength = seed.length; + error.digestLength = md.digestLength; + throw error; + } + + var dbMask = rsa_mgf1(seed, keyLength - md.digestLength - 1, mgf1Md); + var maskedDB = forge$k.util.xorBytes(DB, dbMask, DB.length); + + var seedMask = rsa_mgf1(maskedDB, md.digestLength, mgf1Md); + var maskedSeed = forge$k.util.xorBytes(seed, seedMask, seed.length); + + // return encoded message + return '\x00' + maskedSeed + maskedDB; +}; + +/** + * Decode the given RSAES-OAEP encoded message (EM) using key, with optional + * label (L). + * + * This method does not perform RSA decryption, it only decodes the message + * using RSAES-OAEP. + * + * @param key the RSA key to use. + * @param em the encoded message to decode. + * @param options the options to use: + * label an optional label to use. + * md the message digest object to use for OAEP, undefined for SHA-1. + * mgf1 optional mgf1 parameters: + * md the message digest object to use for MGF1. + * + * @return the decoded message bytes. + */ +pkcs1.decode_rsa_oaep = function(key, em, options) { + // parse args + var label; + var md; + var mgf1Md; + // legacy args + if(typeof options === 'string') { + label = options; + md = arguments[3] || undefined; + } else if(options) { + label = options.label || undefined; + md = options.md || undefined; + if(options.mgf1 && options.mgf1.md) { + mgf1Md = options.mgf1.md; + } + } + + // compute length in bytes + var keyLength = Math.ceil(key.n.bitLength() / 8); + + if(em.length !== keyLength) { + var error = new Error('RSAES-OAEP encoded message length is invalid.'); + error.length = em.length; + error.expectedLength = keyLength; + throw error; + } + + // default OAEP to SHA-1 message digest + if(md === undefined) { + md = forge$k.md.sha1.create(); + } else { + md.start(); + } + + // default MGF-1 to same as OAEP + if(!mgf1Md) { + mgf1Md = md; + } + + if(keyLength < 2 * md.digestLength + 2) { + throw new Error('RSAES-OAEP key is too short for the hash function.'); + } + + if(!label) { + label = ''; + } + md.update(label, 'raw'); + var lHash = md.digest().getBytes(); + + // split the message into its parts + var y = em.charAt(0); + var maskedSeed = em.substring(1, md.digestLength + 1); + var maskedDB = em.substring(1 + md.digestLength); + + var seedMask = rsa_mgf1(maskedDB, md.digestLength, mgf1Md); + var seed = forge$k.util.xorBytes(maskedSeed, seedMask, maskedSeed.length); + + var dbMask = rsa_mgf1(seed, keyLength - md.digestLength - 1, mgf1Md); + var db = forge$k.util.xorBytes(maskedDB, dbMask, maskedDB.length); + + var lHashPrime = db.substring(0, md.digestLength); + + // constant time check that all values match what is expected + var error = (y !== '\x00'); + + // constant time check lHash vs lHashPrime + for(var i = 0; i < md.digestLength; ++i) { + error |= (lHash.charAt(i) !== lHashPrime.charAt(i)); + } + + // "constant time" find the 0x1 byte separating the padding (zeros) from the + // message + // TODO: It must be possible to do this in a better/smarter way? + var in_ps = 1; + var index = md.digestLength; + for(var j = md.digestLength; j < db.length; j++) { + var code = db.charCodeAt(j); + + var is_0 = (code & 0x1) ^ 0x1; + + // non-zero if not 0 or 1 in the ps section + var error_mask = in_ps ? 0xfffe : 0x0000; + error |= (code & error_mask); + + // latch in_ps to zero after we find 0x1 + in_ps = in_ps & is_0; + index += in_ps; + } + + if(error || db.charCodeAt(index) !== 0x1) { + throw new Error('Invalid RSAES-OAEP padding.'); + } + + return db.substring(index + 1); +}; + +function rsa_mgf1(seed, maskLength, hash) { + // default to SHA-1 message digest + if(!hash) { + hash = forge$k.md.sha1.create(); + } + var t = ''; + var count = Math.ceil(maskLength / hash.digestLength); + for(var i = 0; i < count; ++i) { + var c = String.fromCharCode( + (i >> 24) & 0xFF, (i >> 16) & 0xFF, (i >> 8) & 0xFF, i & 0xFF); + hash.start(); + hash.update(seed + c); + t += hash.digest().getBytes(); + } + return t.substring(0, maskLength); +} + +/** + * Prime number generation API. + * + * @author Dave Longley + * + * Copyright (c) 2014 Digital Bazaar, Inc. + */ + +var forge$j = forge$D; + + + + +(function() { + +// forge.prime already defined +if(forge$j.prime) { + forge$j.prime; + return; +} + +/* PRIME API */ +var prime = forge$j.prime = forge$j.prime || {}; + +var BigInteger = forge$j.jsbn.BigInteger; + +// primes are 30k+i for i = 1, 7, 11, 13, 17, 19, 23, 29 +var GCD_30_DELTA = [6, 4, 2, 4, 2, 4, 6, 2]; +var THIRTY = new BigInteger(null); +THIRTY.fromInt(30); +var op_or = function(x, y) {return x|y;}; + +/** + * Generates a random probable prime with the given number of bits. + * + * Alternative algorithms can be specified by name as a string or as an + * object with custom options like so: + * + * { + * name: 'PRIMEINC', + * options: { + * maxBlockTime: , + * millerRabinTests: , + * workerScript: , + * workers: . + * workLoad: the size of the work load, ie: number of possible prime + * numbers for each web worker to check per work assignment, + * (default: 100). + * } + * } + * + * @param bits the number of bits for the prime number. + * @param options the options to use. + * [algorithm] the algorithm to use (default: 'PRIMEINC'). + * [prng] a custom crypto-secure pseudo-random number generator to use, + * that must define "getBytesSync". + * + * @return callback(err, num) called once the operation completes. + */ +prime.generateProbablePrime = function(bits, options, callback) { + if(typeof options === 'function') { + callback = options; + options = {}; + } + options = options || {}; + + // default to PRIMEINC algorithm + var algorithm = options.algorithm || 'PRIMEINC'; + if(typeof algorithm === 'string') { + algorithm = {name: algorithm}; + } + algorithm.options = algorithm.options || {}; + + // create prng with api that matches BigInteger secure random + var prng = options.prng || forge$j.random; + var rng = { + // x is an array to fill with bytes + nextBytes: function(x) { + var b = prng.getBytesSync(x.length); + for(var i = 0; i < x.length; ++i) { + x[i] = b.charCodeAt(i); + } + } + }; + + if(algorithm.name === 'PRIMEINC') { + return primeincFindPrime(bits, rng, algorithm.options, callback); + } + + throw new Error('Invalid prime generation algorithm: ' + algorithm.name); +}; + +function primeincFindPrime(bits, rng, options, callback) { + if('workers' in options) { + return primeincFindPrimeWithWorkers(bits, rng, options, callback); + } + return primeincFindPrimeWithoutWorkers(bits, rng, options, callback); +} + +function primeincFindPrimeWithoutWorkers(bits, rng, options, callback) { + // initialize random number + var num = generateRandom(bits, rng); + + /* Note: All primes are of the form 30k+i for i < 30 and gcd(30, i)=1. The + number we are given is always aligned at 30k + 1. Each time the number is + determined not to be prime we add to get to the next 'i', eg: if the number + was at 30k + 1 we add 6. */ + var deltaIdx = 0; + + // get required number of MR tests + var mrTests = getMillerRabinTests(num.bitLength()); + if('millerRabinTests' in options) { + mrTests = options.millerRabinTests; + } + + // find prime nearest to 'num' for maxBlockTime ms + // 10 ms gives 5ms of leeway for other calculations before dropping + // below 60fps (1000/60 == 16.67), but in reality, the number will + // likely be higher due to an 'atomic' big int modPow + var maxBlockTime = 10; + if('maxBlockTime' in options) { + maxBlockTime = options.maxBlockTime; + } + + _primeinc(num, bits, rng, deltaIdx, mrTests, maxBlockTime, callback); +} + +function _primeinc(num, bits, rng, deltaIdx, mrTests, maxBlockTime, callback) { + var start = +new Date(); + do { + // overflow, regenerate random number + if(num.bitLength() > bits) { + num = generateRandom(bits, rng); + } + // do primality test + if(num.isProbablePrime(mrTests)) { + return callback(null, num); + } + // get next potential prime + num.dAddOffset(GCD_30_DELTA[deltaIdx++ % 8], 0); + } while(maxBlockTime < 0 || (+new Date() - start < maxBlockTime)); + + // keep trying later + forge$j.util.setImmediate(function() { + _primeinc(num, bits, rng, deltaIdx, mrTests, maxBlockTime, callback); + }); +} + +// NOTE: This algorithm is indeterminate in nature because workers +// run in parallel looking at different segments of numbers. Even if this +// algorithm is run twice with the same input from a predictable RNG, it +// may produce different outputs. +function primeincFindPrimeWithWorkers(bits, rng, options, callback) { + // web workers unavailable + if(typeof Worker === 'undefined') { + return primeincFindPrimeWithoutWorkers(bits, rng, options, callback); + } + + // initialize random number + var num = generateRandom(bits, rng); + + // use web workers to generate keys + var numWorkers = options.workers; + var workLoad = options.workLoad || 100; + var range = workLoad * 30 / 8; + var workerScript = options.workerScript || 'forge/prime.worker.js'; + if(numWorkers === -1) { + return forge$j.util.estimateCores(function(err, cores) { + if(err) { + // default to 2 + cores = 2; + } + numWorkers = cores - 1; + generate(); + }); + } + generate(); + + function generate() { + // require at least 1 worker + numWorkers = Math.max(1, numWorkers); + + // TODO: consider optimizing by starting workers outside getPrime() ... + // note that in order to clean up they will have to be made internally + // asynchronous which may actually be slower + + // start workers immediately + var workers = []; + for(var i = 0; i < numWorkers; ++i) { + // FIXME: fix path or use blob URLs + workers[i] = new Worker(workerScript); + } + + // listen for requests from workers and assign ranges to find prime + for(var i = 0; i < numWorkers; ++i) { + workers[i].addEventListener('message', workerMessage); + } + + /* Note: The distribution of random numbers is unknown. Therefore, each + web worker is continuously allocated a range of numbers to check for a + random number until one is found. + + Every 30 numbers will be checked just 8 times, because prime numbers + have the form: + + 30k+i, for i < 30 and gcd(30, i)=1 (there are 8 values of i for this) + + Therefore, if we want a web worker to run N checks before asking for + a new range of numbers, each range must contain N*30/8 numbers. + + For 100 checks (workLoad), this is a range of 375. */ + + var found = false; + function workerMessage(e) { + // ignore message, prime already found + if(found) { + return; + } + var data = e.data; + if(data.found) { + // terminate all workers + for(var i = 0; i < workers.length; ++i) { + workers[i].terminate(); + } + found = true; + return callback(null, new BigInteger(data.prime, 16)); + } + + // overflow, regenerate random number + if(num.bitLength() > bits) { + num = generateRandom(bits, rng); + } + + // assign new range to check + var hex = num.toString(16); + + // start prime search + e.target.postMessage({ + hex: hex, + workLoad: workLoad + }); + + num.dAddOffset(range, 0); + } + } +} + +/** + * Generates a random number using the given number of bits and RNG. + * + * @param bits the number of bits for the number. + * @param rng the random number generator to use. + * + * @return the random number. + */ +function generateRandom(bits, rng) { + var num = new BigInteger(bits, rng); + // force MSB set + var bits1 = bits - 1; + if(!num.testBit(bits1)) { + num.bitwiseTo(BigInteger.ONE.shiftLeft(bits1), op_or, num); + } + // align number on 30k+1 boundary + num.dAddOffset(31 - num.mod(THIRTY).byteValue(), 0); + return num; +} + +/** + * Returns the required number of Miller-Rabin tests to generate a + * prime with an error probability of (1/2)^80. + * + * See Handbook of Applied Cryptography Chapter 4, Table 4.4. + * + * @param bits the bit size. + * + * @return the required number of iterations. + */ +function getMillerRabinTests(bits) { + if(bits <= 100) return 27; + if(bits <= 150) return 18; + if(bits <= 200) return 15; + if(bits <= 250) return 12; + if(bits <= 300) return 9; + if(bits <= 350) return 8; + if(bits <= 400) return 7; + if(bits <= 500) return 6; + if(bits <= 600) return 5; + if(bits <= 800) return 4; + if(bits <= 1250) return 3; + return 2; +} + +})(); + +/** + * Javascript implementation of basic RSA algorithms. + * + * @author Dave Longley + * + * Copyright (c) 2010-2014 Digital Bazaar, Inc. + * + * The only algorithm currently supported for PKI is RSA. + * + * An RSA key is often stored in ASN.1 DER format. The SubjectPublicKeyInfo + * ASN.1 structure is composed of an algorithm of type AlgorithmIdentifier + * and a subjectPublicKey of type bit string. + * + * The AlgorithmIdentifier contains an Object Identifier (OID) and parameters + * for the algorithm, if any. In the case of RSA, there aren't any. + * + * SubjectPublicKeyInfo ::= SEQUENCE { + * algorithm AlgorithmIdentifier, + * subjectPublicKey BIT STRING + * } + * + * AlgorithmIdentifer ::= SEQUENCE { + * algorithm OBJECT IDENTIFIER, + * parameters ANY DEFINED BY algorithm OPTIONAL + * } + * + * For an RSA public key, the subjectPublicKey is: + * + * RSAPublicKey ::= SEQUENCE { + * modulus INTEGER, -- n + * publicExponent INTEGER -- e + * } + * + * PrivateKeyInfo ::= SEQUENCE { + * version Version, + * privateKeyAlgorithm PrivateKeyAlgorithmIdentifier, + * privateKey PrivateKey, + * attributes [0] IMPLICIT Attributes OPTIONAL + * } + * + * Version ::= INTEGER + * PrivateKeyAlgorithmIdentifier ::= AlgorithmIdentifier + * PrivateKey ::= OCTET STRING + * Attributes ::= SET OF Attribute + * + * An RSA private key as the following structure: + * + * RSAPrivateKey ::= SEQUENCE { + * version Version, + * modulus INTEGER, -- n + * publicExponent INTEGER, -- e + * privateExponent INTEGER, -- d + * prime1 INTEGER, -- p + * prime2 INTEGER, -- q + * exponent1 INTEGER, -- d mod (p-1) + * exponent2 INTEGER, -- d mod (q-1) + * coefficient INTEGER -- (inverse of q) mod p + * } + * + * Version ::= INTEGER + * + * The OID for the RSA key algorithm is: 1.2.840.113549.1.1.1 + */ + +var forge$i = forge$D; + + + + + + + + +if(typeof BigInteger$3 === 'undefined') { + var BigInteger$3 = forge$i.jsbn.BigInteger; +} + +var _crypto = forge$i.util.isNodejs ? require$$1$1 : null; + +// shortcut for asn.1 API +var asn1$7 = forge$i.asn1; + +// shortcut for util API +var util = forge$i.util; + +/* + * RSA encryption and decryption, see RFC 2313. + */ +forge$i.pki = forge$i.pki || {}; +forge$i.pki.rsa = forge$i.rsa = forge$i.rsa || {}; +var pki$4 = forge$i.pki; + +// for finding primes, which are 30k+i for i = 1, 7, 11, 13, 17, 19, 23, 29 +var GCD_30_DELTA = [6, 4, 2, 4, 2, 4, 6, 2]; + +// validator for a PrivateKeyInfo structure +var privateKeyValidator$1 = { + // PrivateKeyInfo + name: 'PrivateKeyInfo', + tagClass: asn1$7.Class.UNIVERSAL, + type: asn1$7.Type.SEQUENCE, + constructed: true, + value: [{ + // Version (INTEGER) + name: 'PrivateKeyInfo.version', + tagClass: asn1$7.Class.UNIVERSAL, + type: asn1$7.Type.INTEGER, + constructed: false, + capture: 'privateKeyVersion' + }, { + // privateKeyAlgorithm + name: 'PrivateKeyInfo.privateKeyAlgorithm', + tagClass: asn1$7.Class.UNIVERSAL, + type: asn1$7.Type.SEQUENCE, + constructed: true, + value: [{ + name: 'AlgorithmIdentifier.algorithm', + tagClass: asn1$7.Class.UNIVERSAL, + type: asn1$7.Type.OID, + constructed: false, + capture: 'privateKeyOid' + }] + }, { + // PrivateKey + name: 'PrivateKeyInfo', + tagClass: asn1$7.Class.UNIVERSAL, + type: asn1$7.Type.OCTETSTRING, + constructed: false, + capture: 'privateKey' + }] +}; + +// validator for an RSA private key +var rsaPrivateKeyValidator = { + // RSAPrivateKey + name: 'RSAPrivateKey', + tagClass: asn1$7.Class.UNIVERSAL, + type: asn1$7.Type.SEQUENCE, + constructed: true, + value: [{ + // Version (INTEGER) + name: 'RSAPrivateKey.version', + tagClass: asn1$7.Class.UNIVERSAL, + type: asn1$7.Type.INTEGER, + constructed: false, + capture: 'privateKeyVersion' + }, { + // modulus (n) + name: 'RSAPrivateKey.modulus', + tagClass: asn1$7.Class.UNIVERSAL, + type: asn1$7.Type.INTEGER, + constructed: false, + capture: 'privateKeyModulus' + }, { + // publicExponent (e) + name: 'RSAPrivateKey.publicExponent', + tagClass: asn1$7.Class.UNIVERSAL, + type: asn1$7.Type.INTEGER, + constructed: false, + capture: 'privateKeyPublicExponent' + }, { + // privateExponent (d) + name: 'RSAPrivateKey.privateExponent', + tagClass: asn1$7.Class.UNIVERSAL, + type: asn1$7.Type.INTEGER, + constructed: false, + capture: 'privateKeyPrivateExponent' + }, { + // prime1 (p) + name: 'RSAPrivateKey.prime1', + tagClass: asn1$7.Class.UNIVERSAL, + type: asn1$7.Type.INTEGER, + constructed: false, + capture: 'privateKeyPrime1' + }, { + // prime2 (q) + name: 'RSAPrivateKey.prime2', + tagClass: asn1$7.Class.UNIVERSAL, + type: asn1$7.Type.INTEGER, + constructed: false, + capture: 'privateKeyPrime2' + }, { + // exponent1 (d mod (p-1)) + name: 'RSAPrivateKey.exponent1', + tagClass: asn1$7.Class.UNIVERSAL, + type: asn1$7.Type.INTEGER, + constructed: false, + capture: 'privateKeyExponent1' + }, { + // exponent2 (d mod (q-1)) + name: 'RSAPrivateKey.exponent2', + tagClass: asn1$7.Class.UNIVERSAL, + type: asn1$7.Type.INTEGER, + constructed: false, + capture: 'privateKeyExponent2' + }, { + // coefficient ((inverse of q) mod p) + name: 'RSAPrivateKey.coefficient', + tagClass: asn1$7.Class.UNIVERSAL, + type: asn1$7.Type.INTEGER, + constructed: false, + capture: 'privateKeyCoefficient' + }] +}; + +// validator for an RSA public key +var rsaPublicKeyValidator = { + // RSAPublicKey + name: 'RSAPublicKey', + tagClass: asn1$7.Class.UNIVERSAL, + type: asn1$7.Type.SEQUENCE, + constructed: true, + value: [{ + // modulus (n) + name: 'RSAPublicKey.modulus', + tagClass: asn1$7.Class.UNIVERSAL, + type: asn1$7.Type.INTEGER, + constructed: false, + capture: 'publicKeyModulus' + }, { + // publicExponent (e) + name: 'RSAPublicKey.exponent', + tagClass: asn1$7.Class.UNIVERSAL, + type: asn1$7.Type.INTEGER, + constructed: false, + capture: 'publicKeyExponent' + }] +}; + +// validator for an SubjectPublicKeyInfo structure +// Note: Currently only works with an RSA public key +var publicKeyValidator$2 = forge$i.pki.rsa.publicKeyValidator = { + name: 'SubjectPublicKeyInfo', + tagClass: asn1$7.Class.UNIVERSAL, + type: asn1$7.Type.SEQUENCE, + constructed: true, + captureAsn1: 'subjectPublicKeyInfo', + value: [{ + name: 'SubjectPublicKeyInfo.AlgorithmIdentifier', + tagClass: asn1$7.Class.UNIVERSAL, + type: asn1$7.Type.SEQUENCE, + constructed: true, + value: [{ + name: 'AlgorithmIdentifier.algorithm', + tagClass: asn1$7.Class.UNIVERSAL, + type: asn1$7.Type.OID, + constructed: false, + capture: 'publicKeyOid' + }] + }, { + // subjectPublicKey + name: 'SubjectPublicKeyInfo.subjectPublicKey', + tagClass: asn1$7.Class.UNIVERSAL, + type: asn1$7.Type.BITSTRING, + constructed: false, + value: [{ + // RSAPublicKey + name: 'SubjectPublicKeyInfo.subjectPublicKey.RSAPublicKey', + tagClass: asn1$7.Class.UNIVERSAL, + type: asn1$7.Type.SEQUENCE, + constructed: true, + optional: true, + captureAsn1: 'rsaPublicKey' + }] + }] +}; + +// validator for a DigestInfo structure +var digestInfoValidator = { + name: 'DigestInfo', + tagClass: asn1$7.Class.UNIVERSAL, + type: asn1$7.Type.SEQUENCE, + constructed: true, + value: [{ + name: 'DigestInfo.DigestAlgorithm', + tagClass: asn1$7.Class.UNIVERSAL, + type: asn1$7.Type.SEQUENCE, + constructed: true, + value: [{ + name: 'DigestInfo.DigestAlgorithm.algorithmIdentifier', + tagClass: asn1$7.Class.UNIVERSAL, + type: asn1$7.Type.OID, + constructed: false, + capture: 'algorithmIdentifier' + }, { + // NULL paramters + name: 'DigestInfo.DigestAlgorithm.parameters', + tagClass: asn1$7.Class.UNIVERSAL, + type: asn1$7.Type.NULL, + // captured only to check existence for md2 and md5 + capture: 'parameters', + optional: true, + constructed: false + }] + }, { + // digest + name: 'DigestInfo.digest', + tagClass: asn1$7.Class.UNIVERSAL, + type: asn1$7.Type.OCTETSTRING, + constructed: false, + capture: 'digest' + }] +}; + +/** + * Wrap digest in DigestInfo object. + * + * This function implements EMSA-PKCS1-v1_5-ENCODE as per RFC 3447. + * + * DigestInfo ::= SEQUENCE { + * digestAlgorithm DigestAlgorithmIdentifier, + * digest Digest + * } + * + * DigestAlgorithmIdentifier ::= AlgorithmIdentifier + * Digest ::= OCTET STRING + * + * @param md the message digest object with the hash to sign. + * + * @return the encoded message (ready for RSA encrytion) + */ +var emsaPkcs1v15encode = function(md) { + // get the oid for the algorithm + var oid; + if(md.algorithm in pki$4.oids) { + oid = pki$4.oids[md.algorithm]; + } else { + var error = new Error('Unknown message digest algorithm.'); + error.algorithm = md.algorithm; + throw error; + } + var oidBytes = asn1$7.oidToDer(oid).getBytes(); + + // create the digest info + var digestInfo = asn1$7.create( + asn1$7.Class.UNIVERSAL, asn1$7.Type.SEQUENCE, true, []); + var digestAlgorithm = asn1$7.create( + asn1$7.Class.UNIVERSAL, asn1$7.Type.SEQUENCE, true, []); + digestAlgorithm.value.push(asn1$7.create( + asn1$7.Class.UNIVERSAL, asn1$7.Type.OID, false, oidBytes)); + digestAlgorithm.value.push(asn1$7.create( + asn1$7.Class.UNIVERSAL, asn1$7.Type.NULL, false, '')); + var digest = asn1$7.create( + asn1$7.Class.UNIVERSAL, asn1$7.Type.OCTETSTRING, + false, md.digest().getBytes()); + digestInfo.value.push(digestAlgorithm); + digestInfo.value.push(digest); + + // encode digest info + return asn1$7.toDer(digestInfo).getBytes(); +}; + +/** + * Performs x^c mod n (RSA encryption or decryption operation). + * + * @param x the number to raise and mod. + * @param key the key to use. + * @param pub true if the key is public, false if private. + * + * @return the result of x^c mod n. + */ +var _modPow = function(x, key, pub) { + if(pub) { + return x.modPow(key.e, key.n); + } + + if(!key.p || !key.q) { + // allow calculation without CRT params (slow) + return x.modPow(key.d, key.n); + } + + // pre-compute dP, dQ, and qInv if necessary + if(!key.dP) { + key.dP = key.d.mod(key.p.subtract(BigInteger$3.ONE)); + } + if(!key.dQ) { + key.dQ = key.d.mod(key.q.subtract(BigInteger$3.ONE)); + } + if(!key.qInv) { + key.qInv = key.q.modInverse(key.p); + } + + /* Chinese remainder theorem (CRT) states: + + Suppose n1, n2, ..., nk are positive integers which are pairwise + coprime (n1 and n2 have no common factors other than 1). For any + integers x1, x2, ..., xk there exists an integer x solving the + system of simultaneous congruences (where ~= means modularly + congruent so a ~= b mod n means a mod n = b mod n): + + x ~= x1 mod n1 + x ~= x2 mod n2 + ... + x ~= xk mod nk + + This system of congruences has a single simultaneous solution x + between 0 and n - 1. Furthermore, each xk solution and x itself + is congruent modulo the product n = n1*n2*...*nk. + So x1 mod n = x2 mod n = xk mod n = x mod n. + + The single simultaneous solution x can be solved with the following + equation: + + x = sum(xi*ri*si) mod n where ri = n/ni and si = ri^-1 mod ni. + + Where x is less than n, xi = x mod ni. + + For RSA we are only concerned with k = 2. The modulus n = pq, where + p and q are coprime. The RSA decryption algorithm is: + + y = x^d mod n + + Given the above: + + x1 = x^d mod p + r1 = n/p = q + s1 = q^-1 mod p + x2 = x^d mod q + r2 = n/q = p + s2 = p^-1 mod q + + So y = (x1r1s1 + x2r2s2) mod n + = ((x^d mod p)q(q^-1 mod p) + (x^d mod q)p(p^-1 mod q)) mod n + + According to Fermat's Little Theorem, if the modulus P is prime, + for any integer A not evenly divisible by P, A^(P-1) ~= 1 mod P. + Since A is not divisible by P it follows that if: + N ~= M mod (P - 1), then A^N mod P = A^M mod P. Therefore: + + A^N mod P = A^(M mod (P - 1)) mod P. (The latter takes less effort + to calculate). In order to calculate x^d mod p more quickly the + exponent d mod (p - 1) is stored in the RSA private key (the same + is done for x^d mod q). These values are referred to as dP and dQ + respectively. Therefore we now have: + + y = ((x^dP mod p)q(q^-1 mod p) + (x^dQ mod q)p(p^-1 mod q)) mod n + + Since we'll be reducing x^dP by modulo p (same for q) we can also + reduce x by p (and q respectively) before hand. Therefore, let + + xp = ((x mod p)^dP mod p), and + xq = ((x mod q)^dQ mod q), yielding: + + y = (xp*q*(q^-1 mod p) + xq*p*(p^-1 mod q)) mod n + + This can be further reduced to a simple algorithm that only + requires 1 inverse (the q inverse is used) to be used and stored. + The algorithm is called Garner's algorithm. If qInv is the + inverse of q, we simply calculate: + + y = (qInv*(xp - xq) mod p) * q + xq + + However, there are two further complications. First, we need to + ensure that xp > xq to prevent signed BigIntegers from being used + so we add p until this is true (since we will be mod'ing with + p anyway). Then, there is a known timing attack on algorithms + using the CRT. To mitigate this risk, "cryptographic blinding" + should be used. This requires simply generating a random number r + between 0 and n-1 and its inverse and multiplying x by r^e before + calculating y and then multiplying y by r^-1 afterwards. Note that + r must be coprime with n (gcd(r, n) === 1) in order to have an + inverse. + */ + + // cryptographic blinding + var r; + do { + r = new BigInteger$3( + forge$i.util.bytesToHex(forge$i.random.getBytes(key.n.bitLength() / 8)), + 16); + } while(r.compareTo(key.n) >= 0 || !r.gcd(key.n).equals(BigInteger$3.ONE)); + x = x.multiply(r.modPow(key.e, key.n)).mod(key.n); + + // calculate xp and xq + var xp = x.mod(key.p).modPow(key.dP, key.p); + var xq = x.mod(key.q).modPow(key.dQ, key.q); + + // xp must be larger than xq to avoid signed bit usage + while(xp.compareTo(xq) < 0) { + xp = xp.add(key.p); + } + + // do last step + var y = xp.subtract(xq) + .multiply(key.qInv).mod(key.p) + .multiply(key.q).add(xq); + + // remove effect of random for cryptographic blinding + y = y.multiply(r.modInverse(key.n)).mod(key.n); + + return y; +}; + +/** + * NOTE: THIS METHOD IS DEPRECATED, use 'sign' on a private key object or + * 'encrypt' on a public key object instead. + * + * Performs RSA encryption. + * + * The parameter bt controls whether to put padding bytes before the + * message passed in. Set bt to either true or false to disable padding + * completely (in order to handle e.g. EMSA-PSS encoding seperately before), + * signaling whether the encryption operation is a public key operation + * (i.e. encrypting data) or not, i.e. private key operation (data signing). + * + * For PKCS#1 v1.5 padding pass in the block type to use, i.e. either 0x01 + * (for signing) or 0x02 (for encryption). The key operation mode (private + * or public) is derived from this flag in that case). + * + * @param m the message to encrypt as a byte string. + * @param key the RSA key to use. + * @param bt for PKCS#1 v1.5 padding, the block type to use + * (0x01 for private key, 0x02 for public), + * to disable padding: true = public key, false = private key. + * + * @return the encrypted bytes as a string. + */ +pki$4.rsa.encrypt = function(m, key, bt) { + var pub = bt; + var eb; + + // get the length of the modulus in bytes + var k = Math.ceil(key.n.bitLength() / 8); + + if(bt !== false && bt !== true) { + // legacy, default to PKCS#1 v1.5 padding + pub = (bt === 0x02); + eb = _encodePkcs1_v1_5(m, key, bt); + } else { + eb = forge$i.util.createBuffer(); + eb.putBytes(m); + } + + // load encryption block as big integer 'x' + // FIXME: hex conversion inefficient, get BigInteger w/byte strings + var x = new BigInteger$3(eb.toHex(), 16); + + // do RSA encryption + var y = _modPow(x, key, pub); + + // convert y into the encrypted data byte string, if y is shorter in + // bytes than k, then prepend zero bytes to fill up ed + // FIXME: hex conversion inefficient, get BigInteger w/byte strings + var yhex = y.toString(16); + var ed = forge$i.util.createBuffer(); + var zeros = k - Math.ceil(yhex.length / 2); + while(zeros > 0) { + ed.putByte(0x00); + --zeros; + } + ed.putBytes(forge$i.util.hexToBytes(yhex)); + return ed.getBytes(); +}; + +/** + * NOTE: THIS METHOD IS DEPRECATED, use 'decrypt' on a private key object or + * 'verify' on a public key object instead. + * + * Performs RSA decryption. + * + * The parameter ml controls whether to apply PKCS#1 v1.5 padding + * or not. Set ml = false to disable padding removal completely + * (in order to handle e.g. EMSA-PSS later on) and simply pass back + * the RSA encryption block. + * + * @param ed the encrypted data to decrypt in as a byte string. + * @param key the RSA key to use. + * @param pub true for a public key operation, false for private. + * @param ml the message length, if known, false to disable padding. + * + * @return the decrypted message as a byte string. + */ +pki$4.rsa.decrypt = function(ed, key, pub, ml) { + // get the length of the modulus in bytes + var k = Math.ceil(key.n.bitLength() / 8); + + // error if the length of the encrypted data ED is not k + if(ed.length !== k) { + var error = new Error('Encrypted message length is invalid.'); + error.length = ed.length; + error.expected = k; + throw error; + } + + // convert encrypted data into a big integer + // FIXME: hex conversion inefficient, get BigInteger w/byte strings + var y = new BigInteger$3(forge$i.util.createBuffer(ed).toHex(), 16); + + // y must be less than the modulus or it wasn't the result of + // a previous mod operation (encryption) using that modulus + if(y.compareTo(key.n) >= 0) { + throw new Error('Encrypted message is invalid.'); + } + + // do RSA decryption + var x = _modPow(y, key, pub); + + // create the encryption block, if x is shorter in bytes than k, then + // prepend zero bytes to fill up eb + // FIXME: hex conversion inefficient, get BigInteger w/byte strings + var xhex = x.toString(16); + var eb = forge$i.util.createBuffer(); + var zeros = k - Math.ceil(xhex.length / 2); + while(zeros > 0) { + eb.putByte(0x00); + --zeros; + } + eb.putBytes(forge$i.util.hexToBytes(xhex)); + + if(ml !== false) { + // legacy, default to PKCS#1 v1.5 padding + return _decodePkcs1_v1_5(eb.getBytes(), key, pub); + } + + // return message + return eb.getBytes(); +}; + +/** + * Creates an RSA key-pair generation state object. It is used to allow + * key-generation to be performed in steps. It also allows for a UI to + * display progress updates. + * + * @param bits the size for the private key in bits, defaults to 2048. + * @param e the public exponent to use, defaults to 65537 (0x10001). + * @param [options] the options to use. + * prng a custom crypto-secure pseudo-random number generator to use, + * that must define "getBytesSync". + * algorithm the algorithm to use (default: 'PRIMEINC'). + * + * @return the state object to use to generate the key-pair. + */ +pki$4.rsa.createKeyPairGenerationState = function(bits, e, options) { + // TODO: migrate step-based prime generation code to forge.prime + + // set default bits + if(typeof(bits) === 'string') { + bits = parseInt(bits, 10); + } + bits = bits || 2048; + + // create prng with api that matches BigInteger secure random + options = options || {}; + var prng = options.prng || forge$i.random; + var rng = { + // x is an array to fill with bytes + nextBytes: function(x) { + var b = prng.getBytesSync(x.length); + for(var i = 0; i < x.length; ++i) { + x[i] = b.charCodeAt(i); + } + } + }; + + var algorithm = options.algorithm || 'PRIMEINC'; + + // create PRIMEINC algorithm state + var rval; + if(algorithm === 'PRIMEINC') { + rval = { + algorithm: algorithm, + state: 0, + bits: bits, + rng: rng, + eInt: e || 65537, + e: new BigInteger$3(null), + p: null, + q: null, + qBits: bits >> 1, + pBits: bits - (bits >> 1), + pqState: 0, + num: null, + keys: null + }; + rval.e.fromInt(rval.eInt); + } else { + throw new Error('Invalid key generation algorithm: ' + algorithm); + } + + return rval; +}; + +/** + * Attempts to runs the key-generation algorithm for at most n seconds + * (approximately) using the given state. When key-generation has completed, + * the keys will be stored in state.keys. + * + * To use this function to update a UI while generating a key or to prevent + * causing browser lockups/warnings, set "n" to a value other than 0. A + * simple pattern for generating a key and showing a progress indicator is: + * + * var state = pki.rsa.createKeyPairGenerationState(2048); + * var step = function() { + * // step key-generation, run algorithm for 100 ms, repeat + * if(!forge.pki.rsa.stepKeyPairGenerationState(state, 100)) { + * setTimeout(step, 1); + * } else { + * // key-generation complete + * // TODO: turn off progress indicator here + * // TODO: use the generated key-pair in "state.keys" + * } + * }; + * // TODO: turn on progress indicator here + * setTimeout(step, 0); + * + * @param state the state to use. + * @param n the maximum number of milliseconds to run the algorithm for, 0 + * to run the algorithm to completion. + * + * @return true if the key-generation completed, false if not. + */ +pki$4.rsa.stepKeyPairGenerationState = function(state, n) { + // set default algorithm if not set + if(!('algorithm' in state)) { + state.algorithm = 'PRIMEINC'; + } + + // TODO: migrate step-based prime generation code to forge.prime + // TODO: abstract as PRIMEINC algorithm + + // do key generation (based on Tom Wu's rsa.js, see jsbn.js license) + // with some minor optimizations and designed to run in steps + + // local state vars + var THIRTY = new BigInteger$3(null); + THIRTY.fromInt(30); + var deltaIdx = 0; + var op_or = function(x, y) {return x | y;}; + + // keep stepping until time limit is reached or done + var t1 = +new Date(); + var t2; + var total = 0; + while(state.keys === null && (n <= 0 || total < n)) { + // generate p or q + if(state.state === 0) { + /* Note: All primes are of the form: + + 30k+i, for i < 30 and gcd(30, i)=1, where there are 8 values for i + + When we generate a random number, we always align it at 30k + 1. Each + time the number is determined not to be prime we add to get to the + next 'i', eg: if the number was at 30k + 1 we add 6. */ + var bits = (state.p === null) ? state.pBits : state.qBits; + var bits1 = bits - 1; + + // get a random number + if(state.pqState === 0) { + state.num = new BigInteger$3(bits, state.rng); + // force MSB set + if(!state.num.testBit(bits1)) { + state.num.bitwiseTo( + BigInteger$3.ONE.shiftLeft(bits1), op_or, state.num); + } + // align number on 30k+1 boundary + state.num.dAddOffset(31 - state.num.mod(THIRTY).byteValue(), 0); + deltaIdx = 0; + + ++state.pqState; + } else if(state.pqState === 1) { + // try to make the number a prime + if(state.num.bitLength() > bits) { + // overflow, try again + state.pqState = 0; + // do primality test + } else if(state.num.isProbablePrime( + _getMillerRabinTests(state.num.bitLength()))) { + ++state.pqState; + } else { + // get next potential prime + state.num.dAddOffset(GCD_30_DELTA[deltaIdx++ % 8], 0); + } + } else if(state.pqState === 2) { + // ensure number is coprime with e + state.pqState = + (state.num.subtract(BigInteger$3.ONE).gcd(state.e) + .compareTo(BigInteger$3.ONE) === 0) ? 3 : 0; + } else if(state.pqState === 3) { + // store p or q + state.pqState = 0; + if(state.p === null) { + state.p = state.num; + } else { + state.q = state.num; + } + + // advance state if both p and q are ready + if(state.p !== null && state.q !== null) { + ++state.state; + } + state.num = null; + } + } else if(state.state === 1) { + // ensure p is larger than q (swap them if not) + if(state.p.compareTo(state.q) < 0) { + state.num = state.p; + state.p = state.q; + state.q = state.num; + } + ++state.state; + } else if(state.state === 2) { + // compute phi: (p - 1)(q - 1) (Euler's totient function) + state.p1 = state.p.subtract(BigInteger$3.ONE); + state.q1 = state.q.subtract(BigInteger$3.ONE); + state.phi = state.p1.multiply(state.q1); + ++state.state; + } else if(state.state === 3) { + // ensure e and phi are coprime + if(state.phi.gcd(state.e).compareTo(BigInteger$3.ONE) === 0) { + // phi and e are coprime, advance + ++state.state; + } else { + // phi and e aren't coprime, so generate a new p and q + state.p = null; + state.q = null; + state.state = 0; + } + } else if(state.state === 4) { + // create n, ensure n is has the right number of bits + state.n = state.p.multiply(state.q); + + // ensure n is right number of bits + if(state.n.bitLength() === state.bits) { + // success, advance + ++state.state; + } else { + // failed, get new q + state.q = null; + state.state = 0; + } + } else if(state.state === 5) { + // set keys + var d = state.e.modInverse(state.phi); + state.keys = { + privateKey: pki$4.rsa.setPrivateKey( + state.n, state.e, d, state.p, state.q, + d.mod(state.p1), d.mod(state.q1), + state.q.modInverse(state.p)), + publicKey: pki$4.rsa.setPublicKey(state.n, state.e) + }; + } + + // update timing + t2 = +new Date(); + total += t2 - t1; + t1 = t2; + } + + return state.keys !== null; +}; + +/** + * Generates an RSA public-private key pair in a single call. + * + * To generate a key-pair in steps (to allow for progress updates and to + * prevent blocking or warnings in slow browsers) then use the key-pair + * generation state functions. + * + * To generate a key-pair asynchronously (either through web-workers, if + * available, or by breaking up the work on the main thread), pass a + * callback function. + * + * @param [bits] the size for the private key in bits, defaults to 2048. + * @param [e] the public exponent to use, defaults to 65537. + * @param [options] options for key-pair generation, if given then 'bits' + * and 'e' must *not* be given: + * bits the size for the private key in bits, (default: 2048). + * e the public exponent to use, (default: 65537 (0x10001)). + * workerScript the worker script URL. + * workers the number of web workers (if supported) to use, + * (default: 2). + * workLoad the size of the work load, ie: number of possible prime + * numbers for each web worker to check per work assignment, + * (default: 100). + * prng a custom crypto-secure pseudo-random number generator to use, + * that must define "getBytesSync". Disables use of native APIs. + * algorithm the algorithm to use (default: 'PRIMEINC'). + * @param [callback(err, keypair)] called once the operation completes. + * + * @return an object with privateKey and publicKey properties. + */ +pki$4.rsa.generateKeyPair = function(bits, e, options, callback) { + // (bits), (options), (callback) + if(arguments.length === 1) { + if(typeof bits === 'object') { + options = bits; + bits = undefined; + } else if(typeof bits === 'function') { + callback = bits; + bits = undefined; + } + } else if(arguments.length === 2) { + // (bits, e), (bits, options), (bits, callback), (options, callback) + if(typeof bits === 'number') { + if(typeof e === 'function') { + callback = e; + e = undefined; + } else if(typeof e !== 'number') { + options = e; + e = undefined; + } + } else { + options = bits; + callback = e; + bits = undefined; + e = undefined; + } + } else if(arguments.length === 3) { + // (bits, e, options), (bits, e, callback), (bits, options, callback) + if(typeof e === 'number') { + if(typeof options === 'function') { + callback = options; + options = undefined; + } + } else { + callback = options; + options = e; + e = undefined; + } + } + options = options || {}; + if(bits === undefined) { + bits = options.bits || 2048; + } + if(e === undefined) { + e = options.e || 0x10001; + } + + // use native code if permitted, available, and parameters are acceptable + if(!forge$i.options.usePureJavaScript && !options.prng && + bits >= 256 && bits <= 16384 && (e === 0x10001 || e === 3)) { + if(callback) { + // try native async + if(_detectNodeCrypto('generateKeyPair')) { + return _crypto.generateKeyPair('rsa', { + modulusLength: bits, + publicExponent: e, + publicKeyEncoding: { + type: 'spki', + format: 'pem' + }, + privateKeyEncoding: { + type: 'pkcs8', + format: 'pem' + } + }, function(err, pub, priv) { + if(err) { + return callback(err); + } + callback(null, { + privateKey: pki$4.privateKeyFromPem(priv), + publicKey: pki$4.publicKeyFromPem(pub) + }); + }); + } + if(_detectSubtleCrypto('generateKey') && + _detectSubtleCrypto('exportKey')) { + // use standard native generateKey + return util.globalScope.crypto.subtle.generateKey({ + name: 'RSASSA-PKCS1-v1_5', + modulusLength: bits, + publicExponent: _intToUint8Array(e), + hash: {name: 'SHA-256'} + }, true /* key can be exported*/, ['sign', 'verify']) + .then(function(pair) { + return util.globalScope.crypto.subtle.exportKey( + 'pkcs8', pair.privateKey); + // avoiding catch(function(err) {...}) to support IE <= 8 + }).then(undefined, function(err) { + callback(err); + }).then(function(pkcs8) { + if(pkcs8) { + var privateKey = pki$4.privateKeyFromAsn1( + asn1$7.fromDer(forge$i.util.createBuffer(pkcs8))); + callback(null, { + privateKey: privateKey, + publicKey: pki$4.setRsaPublicKey(privateKey.n, privateKey.e) + }); + } + }); + } + if(_detectSubtleMsCrypto('generateKey') && + _detectSubtleMsCrypto('exportKey')) { + var genOp = util.globalScope.msCrypto.subtle.generateKey({ + name: 'RSASSA-PKCS1-v1_5', + modulusLength: bits, + publicExponent: _intToUint8Array(e), + hash: {name: 'SHA-256'} + }, true /* key can be exported*/, ['sign', 'verify']); + genOp.oncomplete = function(e) { + var pair = e.target.result; + var exportOp = util.globalScope.msCrypto.subtle.exportKey( + 'pkcs8', pair.privateKey); + exportOp.oncomplete = function(e) { + var pkcs8 = e.target.result; + var privateKey = pki$4.privateKeyFromAsn1( + asn1$7.fromDer(forge$i.util.createBuffer(pkcs8))); + callback(null, { + privateKey: privateKey, + publicKey: pki$4.setRsaPublicKey(privateKey.n, privateKey.e) + }); + }; + exportOp.onerror = function(err) { + callback(err); + }; + }; + genOp.onerror = function(err) { + callback(err); + }; + return; + } + } else { + // try native sync + if(_detectNodeCrypto('generateKeyPairSync')) { + var keypair = _crypto.generateKeyPairSync('rsa', { + modulusLength: bits, + publicExponent: e, + publicKeyEncoding: { + type: 'spki', + format: 'pem' + }, + privateKeyEncoding: { + type: 'pkcs8', + format: 'pem' + } + }); + return { + privateKey: pki$4.privateKeyFromPem(keypair.privateKey), + publicKey: pki$4.publicKeyFromPem(keypair.publicKey) + }; + } + } + } + + // use JavaScript implementation + var state = pki$4.rsa.createKeyPairGenerationState(bits, e, options); + if(!callback) { + pki$4.rsa.stepKeyPairGenerationState(state, 0); + return state.keys; + } + _generateKeyPair(state, options, callback); +}; + +/** + * Sets an RSA public key from BigIntegers modulus and exponent. + * + * @param n the modulus. + * @param e the exponent. + * + * @return the public key. + */ +pki$4.setRsaPublicKey = pki$4.rsa.setPublicKey = function(n, e) { + var key = { + n: n, + e: e + }; + + /** + * Encrypts the given data with this public key. Newer applications + * should use the 'RSA-OAEP' decryption scheme, 'RSAES-PKCS1-V1_5' is for + * legacy applications. + * + * @param data the byte string to encrypt. + * @param scheme the encryption scheme to use: + * 'RSAES-PKCS1-V1_5' (default), + * 'RSA-OAEP', + * 'RAW', 'NONE', or null to perform raw RSA encryption, + * an object with an 'encode' property set to a function + * with the signature 'function(data, key)' that returns + * a binary-encoded string representing the encoded data. + * @param schemeOptions any scheme-specific options. + * + * @return the encrypted byte string. + */ + key.encrypt = function(data, scheme, schemeOptions) { + if(typeof scheme === 'string') { + scheme = scheme.toUpperCase(); + } else if(scheme === undefined) { + scheme = 'RSAES-PKCS1-V1_5'; + } + + if(scheme === 'RSAES-PKCS1-V1_5') { + scheme = { + encode: function(m, key, pub) { + return _encodePkcs1_v1_5(m, key, 0x02).getBytes(); + } + }; + } else if(scheme === 'RSA-OAEP' || scheme === 'RSAES-OAEP') { + scheme = { + encode: function(m, key) { + return forge$i.pkcs1.encode_rsa_oaep(key, m, schemeOptions); + } + }; + } else if(['RAW', 'NONE', 'NULL', null].indexOf(scheme) !== -1) { + scheme = {encode: function(e) {return e;}}; + } else if(typeof scheme === 'string') { + throw new Error('Unsupported encryption scheme: "' + scheme + '".'); + } + + // do scheme-based encoding then rsa encryption + var e = scheme.encode(data, key, true); + return pki$4.rsa.encrypt(e, key, true); + }; + + /** + * Verifies the given signature against the given digest. + * + * PKCS#1 supports multiple (currently two) signature schemes: + * RSASSA-PKCS1-V1_5 and RSASSA-PSS. + * + * By default this implementation uses the "old scheme", i.e. + * RSASSA-PKCS1-V1_5, in which case once RSA-decrypted, the + * signature is an OCTET STRING that holds a DigestInfo. + * + * DigestInfo ::= SEQUENCE { + * digestAlgorithm DigestAlgorithmIdentifier, + * digest Digest + * } + * DigestAlgorithmIdentifier ::= AlgorithmIdentifier + * Digest ::= OCTET STRING + * + * To perform PSS signature verification, provide an instance + * of Forge PSS object as the scheme parameter. + * + * @param digest the message digest hash to compare against the signature, + * as a binary-encoded string. + * @param signature the signature to verify, as a binary-encoded string. + * @param scheme signature verification scheme to use: + * 'RSASSA-PKCS1-V1_5' or undefined for RSASSA PKCS#1 v1.5, + * a Forge PSS object for RSASSA-PSS, + * 'NONE' or null for none, DigestInfo will not be expected, but + * PKCS#1 v1.5 padding will still be used. + * @param options optional verify options + * _parseAllDigestBytes testing flag to control parsing of all + * digest bytes. Unsupported and not for general usage. + * (default: true) + * + * @return true if the signature was verified, false if not. + */ + key.verify = function(digest, signature, scheme, options) { + if(typeof scheme === 'string') { + scheme = scheme.toUpperCase(); + } else if(scheme === undefined) { + scheme = 'RSASSA-PKCS1-V1_5'; + } + if(options === undefined) { + options = { + _parseAllDigestBytes: true + }; + } + if(!('_parseAllDigestBytes' in options)) { + options._parseAllDigestBytes = true; + } + + if(scheme === 'RSASSA-PKCS1-V1_5') { + scheme = { + verify: function(digest, d) { + // remove padding + d = _decodePkcs1_v1_5(d, key, true); + // d is ASN.1 BER-encoded DigestInfo + var obj = asn1$7.fromDer(d, { + parseAllBytes: options._parseAllDigestBytes + }); + + // validate DigestInfo + var capture = {}; + var errors = []; + if(!asn1$7.validate(obj, digestInfoValidator, capture, errors)) { + var error = new Error( + 'ASN.1 object does not contain a valid RSASSA-PKCS1-v1_5 ' + + 'DigestInfo value.'); + error.errors = errors; + throw error; + } + // check hash algorithm identifier + // see PKCS1-v1-5DigestAlgorithms in RFC 8017 + // FIXME: add support to vaidator for strict value choices + var oid = asn1$7.derToOid(capture.algorithmIdentifier); + if(!(oid === forge$i.oids.md2 || + oid === forge$i.oids.md5 || + oid === forge$i.oids.sha1 || + oid === forge$i.oids.sha224 || + oid === forge$i.oids.sha256 || + oid === forge$i.oids.sha384 || + oid === forge$i.oids.sha512 || + oid === forge$i.oids['sha512-224'] || + oid === forge$i.oids['sha512-256'])) { + var error = new Error( + 'Unknown RSASSA-PKCS1-v1_5 DigestAlgorithm identifier.'); + error.oid = oid; + throw error; + } + + // special check for md2 and md5 that NULL parameters exist + if(oid === forge$i.oids.md2 || oid === forge$i.oids.md5) { + if(!('parameters' in capture)) { + throw new Error( + 'ASN.1 object does not contain a valid RSASSA-PKCS1-v1_5 ' + + 'DigestInfo value. ' + + 'Missing algorithm identifer NULL parameters.'); + } + } + + // compare the given digest to the decrypted one + return digest === capture.digest; + } + }; + } else if(scheme === 'NONE' || scheme === 'NULL' || scheme === null) { + scheme = { + verify: function(digest, d) { + // remove padding + d = _decodePkcs1_v1_5(d, key, true); + return digest === d; + } + }; + } + + // do rsa decryption w/o any decoding, then verify -- which does decoding + var d = pki$4.rsa.decrypt(signature, key, true, false); + return scheme.verify(digest, d, key.n.bitLength()); + }; + + return key; +}; + +/** + * Sets an RSA private key from BigIntegers modulus, exponent, primes, + * prime exponents, and modular multiplicative inverse. + * + * @param n the modulus. + * @param e the public exponent. + * @param d the private exponent ((inverse of e) mod n). + * @param p the first prime. + * @param q the second prime. + * @param dP exponent1 (d mod (p-1)). + * @param dQ exponent2 (d mod (q-1)). + * @param qInv ((inverse of q) mod p) + * + * @return the private key. + */ +pki$4.setRsaPrivateKey = pki$4.rsa.setPrivateKey = function( + n, e, d, p, q, dP, dQ, qInv) { + var key = { + n: n, + e: e, + d: d, + p: p, + q: q, + dP: dP, + dQ: dQ, + qInv: qInv + }; + + /** + * Decrypts the given data with this private key. The decryption scheme + * must match the one used to encrypt the data. + * + * @param data the byte string to decrypt. + * @param scheme the decryption scheme to use: + * 'RSAES-PKCS1-V1_5' (default), + * 'RSA-OAEP', + * 'RAW', 'NONE', or null to perform raw RSA decryption. + * @param schemeOptions any scheme-specific options. + * + * @return the decrypted byte string. + */ + key.decrypt = function(data, scheme, schemeOptions) { + if(typeof scheme === 'string') { + scheme = scheme.toUpperCase(); + } else if(scheme === undefined) { + scheme = 'RSAES-PKCS1-V1_5'; + } + + // do rsa decryption w/o any decoding + var d = pki$4.rsa.decrypt(data, key, false, false); + + if(scheme === 'RSAES-PKCS1-V1_5') { + scheme = {decode: _decodePkcs1_v1_5}; + } else if(scheme === 'RSA-OAEP' || scheme === 'RSAES-OAEP') { + scheme = { + decode: function(d, key) { + return forge$i.pkcs1.decode_rsa_oaep(key, d, schemeOptions); + } + }; + } else if(['RAW', 'NONE', 'NULL', null].indexOf(scheme) !== -1) { + scheme = {decode: function(d) {return d;}}; + } else { + throw new Error('Unsupported encryption scheme: "' + scheme + '".'); + } + + // decode according to scheme + return scheme.decode(d, key, false); + }; + + /** + * Signs the given digest, producing a signature. + * + * PKCS#1 supports multiple (currently two) signature schemes: + * RSASSA-PKCS1-V1_5 and RSASSA-PSS. + * + * By default this implementation uses the "old scheme", i.e. + * RSASSA-PKCS1-V1_5. In order to generate a PSS signature, provide + * an instance of Forge PSS object as the scheme parameter. + * + * @param md the message digest object with the hash to sign. + * @param scheme the signature scheme to use: + * 'RSASSA-PKCS1-V1_5' or undefined for RSASSA PKCS#1 v1.5, + * a Forge PSS object for RSASSA-PSS, + * 'NONE' or null for none, DigestInfo will not be used but + * PKCS#1 v1.5 padding will still be used. + * + * @return the signature as a byte string. + */ + key.sign = function(md, scheme) { + /* Note: The internal implementation of RSA operations is being + transitioned away from a PKCS#1 v1.5 hard-coded scheme. Some legacy + code like the use of an encoding block identifier 'bt' will eventually + be removed. */ + + // private key operation + var bt = false; + + if(typeof scheme === 'string') { + scheme = scheme.toUpperCase(); + } + + if(scheme === undefined || scheme === 'RSASSA-PKCS1-V1_5') { + scheme = {encode: emsaPkcs1v15encode}; + bt = 0x01; + } else if(scheme === 'NONE' || scheme === 'NULL' || scheme === null) { + scheme = {encode: function() {return md;}}; + bt = 0x01; + } + + // encode and then encrypt + var d = scheme.encode(md, key.n.bitLength()); + return pki$4.rsa.encrypt(d, key, bt); + }; + + return key; +}; + +/** + * Wraps an RSAPrivateKey ASN.1 object in an ASN.1 PrivateKeyInfo object. + * + * @param rsaKey the ASN.1 RSAPrivateKey. + * + * @return the ASN.1 PrivateKeyInfo. + */ +pki$4.wrapRsaPrivateKey = function(rsaKey) { + // PrivateKeyInfo + return asn1$7.create(asn1$7.Class.UNIVERSAL, asn1$7.Type.SEQUENCE, true, [ + // version (0) + asn1$7.create(asn1$7.Class.UNIVERSAL, asn1$7.Type.INTEGER, false, + asn1$7.integerToDer(0).getBytes()), + // privateKeyAlgorithm + asn1$7.create(asn1$7.Class.UNIVERSAL, asn1$7.Type.SEQUENCE, true, [ + asn1$7.create( + asn1$7.Class.UNIVERSAL, asn1$7.Type.OID, false, + asn1$7.oidToDer(pki$4.oids.rsaEncryption).getBytes()), + asn1$7.create(asn1$7.Class.UNIVERSAL, asn1$7.Type.NULL, false, '') + ]), + // PrivateKey + asn1$7.create(asn1$7.Class.UNIVERSAL, asn1$7.Type.OCTETSTRING, false, + asn1$7.toDer(rsaKey).getBytes()) + ]); +}; + +/** + * Converts a private key from an ASN.1 object. + * + * @param obj the ASN.1 representation of a PrivateKeyInfo containing an + * RSAPrivateKey or an RSAPrivateKey. + * + * @return the private key. + */ +pki$4.privateKeyFromAsn1 = function(obj) { + // get PrivateKeyInfo + var capture = {}; + var errors = []; + if(asn1$7.validate(obj, privateKeyValidator$1, capture, errors)) { + obj = asn1$7.fromDer(forge$i.util.createBuffer(capture.privateKey)); + } + + // get RSAPrivateKey + capture = {}; + errors = []; + if(!asn1$7.validate(obj, rsaPrivateKeyValidator, capture, errors)) { + var error = new Error('Cannot read private key. ' + + 'ASN.1 object does not contain an RSAPrivateKey.'); + error.errors = errors; + throw error; + } + + // Note: Version is currently ignored. + // capture.privateKeyVersion + // FIXME: inefficient, get a BigInteger that uses byte strings + var n, e, d, p, q, dP, dQ, qInv; + n = forge$i.util.createBuffer(capture.privateKeyModulus).toHex(); + e = forge$i.util.createBuffer(capture.privateKeyPublicExponent).toHex(); + d = forge$i.util.createBuffer(capture.privateKeyPrivateExponent).toHex(); + p = forge$i.util.createBuffer(capture.privateKeyPrime1).toHex(); + q = forge$i.util.createBuffer(capture.privateKeyPrime2).toHex(); + dP = forge$i.util.createBuffer(capture.privateKeyExponent1).toHex(); + dQ = forge$i.util.createBuffer(capture.privateKeyExponent2).toHex(); + qInv = forge$i.util.createBuffer(capture.privateKeyCoefficient).toHex(); + + // set private key + return pki$4.setRsaPrivateKey( + new BigInteger$3(n, 16), + new BigInteger$3(e, 16), + new BigInteger$3(d, 16), + new BigInteger$3(p, 16), + new BigInteger$3(q, 16), + new BigInteger$3(dP, 16), + new BigInteger$3(dQ, 16), + new BigInteger$3(qInv, 16)); +}; + +/** + * Converts a private key to an ASN.1 RSAPrivateKey. + * + * @param key the private key. + * + * @return the ASN.1 representation of an RSAPrivateKey. + */ +pki$4.privateKeyToAsn1 = pki$4.privateKeyToRSAPrivateKey = function(key) { + // RSAPrivateKey + return asn1$7.create(asn1$7.Class.UNIVERSAL, asn1$7.Type.SEQUENCE, true, [ + // version (0 = only 2 primes, 1 multiple primes) + asn1$7.create(asn1$7.Class.UNIVERSAL, asn1$7.Type.INTEGER, false, + asn1$7.integerToDer(0).getBytes()), + // modulus (n) + asn1$7.create(asn1$7.Class.UNIVERSAL, asn1$7.Type.INTEGER, false, + _bnToBytes(key.n)), + // publicExponent (e) + asn1$7.create(asn1$7.Class.UNIVERSAL, asn1$7.Type.INTEGER, false, + _bnToBytes(key.e)), + // privateExponent (d) + asn1$7.create(asn1$7.Class.UNIVERSAL, asn1$7.Type.INTEGER, false, + _bnToBytes(key.d)), + // privateKeyPrime1 (p) + asn1$7.create(asn1$7.Class.UNIVERSAL, asn1$7.Type.INTEGER, false, + _bnToBytes(key.p)), + // privateKeyPrime2 (q) + asn1$7.create(asn1$7.Class.UNIVERSAL, asn1$7.Type.INTEGER, false, + _bnToBytes(key.q)), + // privateKeyExponent1 (dP) + asn1$7.create(asn1$7.Class.UNIVERSAL, asn1$7.Type.INTEGER, false, + _bnToBytes(key.dP)), + // privateKeyExponent2 (dQ) + asn1$7.create(asn1$7.Class.UNIVERSAL, asn1$7.Type.INTEGER, false, + _bnToBytes(key.dQ)), + // coefficient (qInv) + asn1$7.create(asn1$7.Class.UNIVERSAL, asn1$7.Type.INTEGER, false, + _bnToBytes(key.qInv)) + ]); +}; + +/** + * Converts a public key from an ASN.1 SubjectPublicKeyInfo or RSAPublicKey. + * + * @param obj the asn1 representation of a SubjectPublicKeyInfo or RSAPublicKey. + * + * @return the public key. + */ +pki$4.publicKeyFromAsn1 = function(obj) { + // get SubjectPublicKeyInfo + var capture = {}; + var errors = []; + if(asn1$7.validate(obj, publicKeyValidator$2, capture, errors)) { + // get oid + var oid = asn1$7.derToOid(capture.publicKeyOid); + if(oid !== pki$4.oids.rsaEncryption) { + var error = new Error('Cannot read public key. Unknown OID.'); + error.oid = oid; + throw error; + } + obj = capture.rsaPublicKey; + } + + // get RSA params + errors = []; + if(!asn1$7.validate(obj, rsaPublicKeyValidator, capture, errors)) { + var error = new Error('Cannot read public key. ' + + 'ASN.1 object does not contain an RSAPublicKey.'); + error.errors = errors; + throw error; + } + + // FIXME: inefficient, get a BigInteger that uses byte strings + var n = forge$i.util.createBuffer(capture.publicKeyModulus).toHex(); + var e = forge$i.util.createBuffer(capture.publicKeyExponent).toHex(); + + // set public key + return pki$4.setRsaPublicKey( + new BigInteger$3(n, 16), + new BigInteger$3(e, 16)); +}; + +/** + * Converts a public key to an ASN.1 SubjectPublicKeyInfo. + * + * @param key the public key. + * + * @return the asn1 representation of a SubjectPublicKeyInfo. + */ +pki$4.publicKeyToAsn1 = pki$4.publicKeyToSubjectPublicKeyInfo = function(key) { + // SubjectPublicKeyInfo + return asn1$7.create(asn1$7.Class.UNIVERSAL, asn1$7.Type.SEQUENCE, true, [ + // AlgorithmIdentifier + asn1$7.create(asn1$7.Class.UNIVERSAL, asn1$7.Type.SEQUENCE, true, [ + // algorithm + asn1$7.create(asn1$7.Class.UNIVERSAL, asn1$7.Type.OID, false, + asn1$7.oidToDer(pki$4.oids.rsaEncryption).getBytes()), + // parameters (null) + asn1$7.create(asn1$7.Class.UNIVERSAL, asn1$7.Type.NULL, false, '') + ]), + // subjectPublicKey + asn1$7.create(asn1$7.Class.UNIVERSAL, asn1$7.Type.BITSTRING, false, [ + pki$4.publicKeyToRSAPublicKey(key) + ]) + ]); +}; + +/** + * Converts a public key to an ASN.1 RSAPublicKey. + * + * @param key the public key. + * + * @return the asn1 representation of a RSAPublicKey. + */ +pki$4.publicKeyToRSAPublicKey = function(key) { + // RSAPublicKey + return asn1$7.create(asn1$7.Class.UNIVERSAL, asn1$7.Type.SEQUENCE, true, [ + // modulus (n) + asn1$7.create(asn1$7.Class.UNIVERSAL, asn1$7.Type.INTEGER, false, + _bnToBytes(key.n)), + // publicExponent (e) + asn1$7.create(asn1$7.Class.UNIVERSAL, asn1$7.Type.INTEGER, false, + _bnToBytes(key.e)) + ]); +}; + +/** + * Encodes a message using PKCS#1 v1.5 padding. + * + * @param m the message to encode. + * @param key the RSA key to use. + * @param bt the block type to use, i.e. either 0x01 (for signing) or 0x02 + * (for encryption). + * + * @return the padded byte buffer. + */ +function _encodePkcs1_v1_5(m, key, bt) { + var eb = forge$i.util.createBuffer(); + + // get the length of the modulus in bytes + var k = Math.ceil(key.n.bitLength() / 8); + + /* use PKCS#1 v1.5 padding */ + if(m.length > (k - 11)) { + var error = new Error('Message is too long for PKCS#1 v1.5 padding.'); + error.length = m.length; + error.max = k - 11; + throw error; + } + + /* A block type BT, a padding string PS, and the data D shall be + formatted into an octet string EB, the encryption block: + + EB = 00 || BT || PS || 00 || D + + The block type BT shall be a single octet indicating the structure of + the encryption block. For this version of the document it shall have + value 00, 01, or 02. For a private-key operation, the block type + shall be 00 or 01. For a public-key operation, it shall be 02. + + The padding string PS shall consist of k-3-||D|| octets. For block + type 00, the octets shall have value 00; for block type 01, they + shall have value FF; and for block type 02, they shall be + pseudorandomly generated and nonzero. This makes the length of the + encryption block EB equal to k. */ + + // build the encryption block + eb.putByte(0x00); + eb.putByte(bt); + + // create the padding + var padNum = k - 3 - m.length; + var padByte; + // private key op + if(bt === 0x00 || bt === 0x01) { + padByte = (bt === 0x00) ? 0x00 : 0xFF; + for(var i = 0; i < padNum; ++i) { + eb.putByte(padByte); + } + } else { + // public key op + // pad with random non-zero values + while(padNum > 0) { + var numZeros = 0; + var padBytes = forge$i.random.getBytes(padNum); + for(var i = 0; i < padNum; ++i) { + padByte = padBytes.charCodeAt(i); + if(padByte === 0) { + ++numZeros; + } else { + eb.putByte(padByte); + } + } + padNum = numZeros; + } + } + + // zero followed by message + eb.putByte(0x00); + eb.putBytes(m); + + return eb; +} + +/** + * Decodes a message using PKCS#1 v1.5 padding. + * + * @param em the message to decode. + * @param key the RSA key to use. + * @param pub true if the key is a public key, false if it is private. + * @param ml the message length, if specified. + * + * @return the decoded bytes. + */ +function _decodePkcs1_v1_5(em, key, pub, ml) { + // get the length of the modulus in bytes + var k = Math.ceil(key.n.bitLength() / 8); + + /* It is an error if any of the following conditions occurs: + + 1. The encryption block EB cannot be parsed unambiguously. + 2. The padding string PS consists of fewer than eight octets + or is inconsisent with the block type BT. + 3. The decryption process is a public-key operation and the block + type BT is not 00 or 01, or the decryption process is a + private-key operation and the block type is not 02. + */ + + // parse the encryption block + var eb = forge$i.util.createBuffer(em); + var first = eb.getByte(); + var bt = eb.getByte(); + if(first !== 0x00 || + (pub && bt !== 0x00 && bt !== 0x01) || + (!pub && bt != 0x02) || + (pub && bt === 0x00 && typeof(ml) === 'undefined')) { + throw new Error('Encryption block is invalid.'); + } + + var padNum = 0; + if(bt === 0x00) { + // check all padding bytes for 0x00 + padNum = k - 3 - ml; + for(var i = 0; i < padNum; ++i) { + if(eb.getByte() !== 0x00) { + throw new Error('Encryption block is invalid.'); + } + } + } else if(bt === 0x01) { + // find the first byte that isn't 0xFF, should be after all padding + padNum = 0; + while(eb.length() > 1) { + if(eb.getByte() !== 0xFF) { + --eb.read; + break; + } + ++padNum; + } + } else if(bt === 0x02) { + // look for 0x00 byte + padNum = 0; + while(eb.length() > 1) { + if(eb.getByte() === 0x00) { + --eb.read; + break; + } + ++padNum; + } + } + + // zero must be 0x00 and padNum must be (k - 3 - message length) + var zero = eb.getByte(); + if(zero !== 0x00 || padNum !== (k - 3 - eb.length())) { + throw new Error('Encryption block is invalid.'); + } + + return eb.getBytes(); +} + +/** + * Runs the key-generation algorithm asynchronously, either in the background + * via Web Workers, or using the main thread and setImmediate. + * + * @param state the key-pair generation state. + * @param [options] options for key-pair generation: + * workerScript the worker script URL. + * workers the number of web workers (if supported) to use, + * (default: 2, -1 to use estimated cores minus one). + * workLoad the size of the work load, ie: number of possible prime + * numbers for each web worker to check per work assignment, + * (default: 100). + * @param callback(err, keypair) called once the operation completes. + */ +function _generateKeyPair(state, options, callback) { + if(typeof options === 'function') { + callback = options; + options = {}; + } + options = options || {}; + + var opts = { + algorithm: { + name: options.algorithm || 'PRIMEINC', + options: { + workers: options.workers || 2, + workLoad: options.workLoad || 100, + workerScript: options.workerScript + } + } + }; + if('prng' in options) { + opts.prng = options.prng; + } + + generate(); + + function generate() { + // find p and then q (done in series to simplify) + getPrime(state.pBits, function(err, num) { + if(err) { + return callback(err); + } + state.p = num; + if(state.q !== null) { + return finish(err, state.q); + } + getPrime(state.qBits, finish); + }); + } + + function getPrime(bits, callback) { + forge$i.prime.generateProbablePrime(bits, opts, callback); + } + + function finish(err, num) { + if(err) { + return callback(err); + } + + // set q + state.q = num; + + // ensure p is larger than q (swap them if not) + if(state.p.compareTo(state.q) < 0) { + var tmp = state.p; + state.p = state.q; + state.q = tmp; + } + + // ensure p is coprime with e + if(state.p.subtract(BigInteger$3.ONE).gcd(state.e) + .compareTo(BigInteger$3.ONE) !== 0) { + state.p = null; + generate(); + return; + } + + // ensure q is coprime with e + if(state.q.subtract(BigInteger$3.ONE).gcd(state.e) + .compareTo(BigInteger$3.ONE) !== 0) { + state.q = null; + getPrime(state.qBits, finish); + return; + } + + // compute phi: (p - 1)(q - 1) (Euler's totient function) + state.p1 = state.p.subtract(BigInteger$3.ONE); + state.q1 = state.q.subtract(BigInteger$3.ONE); + state.phi = state.p1.multiply(state.q1); + + // ensure e and phi are coprime + if(state.phi.gcd(state.e).compareTo(BigInteger$3.ONE) !== 0) { + // phi and e aren't coprime, so generate a new p and q + state.p = state.q = null; + generate(); + return; + } + + // create n, ensure n is has the right number of bits + state.n = state.p.multiply(state.q); + if(state.n.bitLength() !== state.bits) { + // failed, get new q + state.q = null; + getPrime(state.qBits, finish); + return; + } + + // set keys + var d = state.e.modInverse(state.phi); + state.keys = { + privateKey: pki$4.rsa.setPrivateKey( + state.n, state.e, d, state.p, state.q, + d.mod(state.p1), d.mod(state.q1), + state.q.modInverse(state.p)), + publicKey: pki$4.rsa.setPublicKey(state.n, state.e) + }; + + callback(null, state.keys); + } +} + +/** + * Converts a positive BigInteger into 2's-complement big-endian bytes. + * + * @param b the big integer to convert. + * + * @return the bytes. + */ +function _bnToBytes(b) { + // prepend 0x00 if first byte >= 0x80 + var hex = b.toString(16); + if(hex[0] >= '8') { + hex = '00' + hex; + } + var bytes = forge$i.util.hexToBytes(hex); + + // ensure integer is minimally-encoded + if(bytes.length > 1 && + // leading 0x00 for positive integer + ((bytes.charCodeAt(0) === 0 && + (bytes.charCodeAt(1) & 0x80) === 0) || + // leading 0xFF for negative integer + (bytes.charCodeAt(0) === 0xFF && + (bytes.charCodeAt(1) & 0x80) === 0x80))) { + return bytes.substr(1); + } + return bytes; +} + +/** + * Returns the required number of Miller-Rabin tests to generate a + * prime with an error probability of (1/2)^80. + * + * See Handbook of Applied Cryptography Chapter 4, Table 4.4. + * + * @param bits the bit size. + * + * @return the required number of iterations. + */ +function _getMillerRabinTests(bits) { + if(bits <= 100) return 27; + if(bits <= 150) return 18; + if(bits <= 200) return 15; + if(bits <= 250) return 12; + if(bits <= 300) return 9; + if(bits <= 350) return 8; + if(bits <= 400) return 7; + if(bits <= 500) return 6; + if(bits <= 600) return 5; + if(bits <= 800) return 4; + if(bits <= 1250) return 3; + return 2; +} + +/** + * Performs feature detection on the Node crypto interface. + * + * @param fn the feature (function) to detect. + * + * @return true if detected, false if not. + */ +function _detectNodeCrypto(fn) { + return forge$i.util.isNodejs && typeof _crypto[fn] === 'function'; +} + +/** + * Performs feature detection on the SubtleCrypto interface. + * + * @param fn the feature (function) to detect. + * + * @return true if detected, false if not. + */ +function _detectSubtleCrypto(fn) { + return (typeof util.globalScope !== 'undefined' && + typeof util.globalScope.crypto === 'object' && + typeof util.globalScope.crypto.subtle === 'object' && + typeof util.globalScope.crypto.subtle[fn] === 'function'); +} + +/** + * Performs feature detection on the deprecated Microsoft Internet Explorer + * outdated SubtleCrypto interface. This function should only be used after + * checking for the modern, standard SubtleCrypto interface. + * + * @param fn the feature (function) to detect. + * + * @return true if detected, false if not. + */ +function _detectSubtleMsCrypto(fn) { + return (typeof util.globalScope !== 'undefined' && + typeof util.globalScope.msCrypto === 'object' && + typeof util.globalScope.msCrypto.subtle === 'object' && + typeof util.globalScope.msCrypto.subtle[fn] === 'function'); +} + +function _intToUint8Array(x) { + var bytes = forge$i.util.hexToBytes(x.toString(16)); + var buffer = new Uint8Array(bytes.length); + for(var i = 0; i < bytes.length; ++i) { + buffer[i] = bytes.charCodeAt(i); + } + return buffer; +} + +/** + * Password-based encryption functions. + * + * @author Dave Longley + * @author Stefan Siegl + * + * Copyright (c) 2010-2013 Digital Bazaar, Inc. + * Copyright (c) 2012 Stefan Siegl + * + * An EncryptedPrivateKeyInfo: + * + * EncryptedPrivateKeyInfo ::= SEQUENCE { + * encryptionAlgorithm EncryptionAlgorithmIdentifier, + * encryptedData EncryptedData } + * + * EncryptionAlgorithmIdentifier ::= AlgorithmIdentifier + * + * EncryptedData ::= OCTET STRING + */ + +var forge$h = forge$D; + + + + + + + + + + + + +if(typeof BigInteger$2 === 'undefined') { + var BigInteger$2 = forge$h.jsbn.BigInteger; +} + +// shortcut for asn.1 API +var asn1$6 = forge$h.asn1; + +/* Password-based encryption implementation. */ +var pki$3 = forge$h.pki = forge$h.pki || {}; +pki$3.pbe = forge$h.pbe = forge$h.pbe || {}; +var oids$1 = pki$3.oids; + +// validator for an EncryptedPrivateKeyInfo structure +// Note: Currently only works w/algorithm params +var encryptedPrivateKeyValidator = { + name: 'EncryptedPrivateKeyInfo', + tagClass: asn1$6.Class.UNIVERSAL, + type: asn1$6.Type.SEQUENCE, + constructed: true, + value: [{ + name: 'EncryptedPrivateKeyInfo.encryptionAlgorithm', + tagClass: asn1$6.Class.UNIVERSAL, + type: asn1$6.Type.SEQUENCE, + constructed: true, + value: [{ + name: 'AlgorithmIdentifier.algorithm', + tagClass: asn1$6.Class.UNIVERSAL, + type: asn1$6.Type.OID, + constructed: false, + capture: 'encryptionOid' + }, { + name: 'AlgorithmIdentifier.parameters', + tagClass: asn1$6.Class.UNIVERSAL, + type: asn1$6.Type.SEQUENCE, + constructed: true, + captureAsn1: 'encryptionParams' + }] + }, { + // encryptedData + name: 'EncryptedPrivateKeyInfo.encryptedData', + tagClass: asn1$6.Class.UNIVERSAL, + type: asn1$6.Type.OCTETSTRING, + constructed: false, + capture: 'encryptedData' + }] +}; + +// validator for a PBES2Algorithms structure +// Note: Currently only works w/PBKDF2 + AES encryption schemes +var PBES2AlgorithmsValidator = { + name: 'PBES2Algorithms', + tagClass: asn1$6.Class.UNIVERSAL, + type: asn1$6.Type.SEQUENCE, + constructed: true, + value: [{ + name: 'PBES2Algorithms.keyDerivationFunc', + tagClass: asn1$6.Class.UNIVERSAL, + type: asn1$6.Type.SEQUENCE, + constructed: true, + value: [{ + name: 'PBES2Algorithms.keyDerivationFunc.oid', + tagClass: asn1$6.Class.UNIVERSAL, + type: asn1$6.Type.OID, + constructed: false, + capture: 'kdfOid' + }, { + name: 'PBES2Algorithms.params', + tagClass: asn1$6.Class.UNIVERSAL, + type: asn1$6.Type.SEQUENCE, + constructed: true, + value: [{ + name: 'PBES2Algorithms.params.salt', + tagClass: asn1$6.Class.UNIVERSAL, + type: asn1$6.Type.OCTETSTRING, + constructed: false, + capture: 'kdfSalt' + }, { + name: 'PBES2Algorithms.params.iterationCount', + tagClass: asn1$6.Class.UNIVERSAL, + type: asn1$6.Type.INTEGER, + constructed: false, + capture: 'kdfIterationCount' + }, { + name: 'PBES2Algorithms.params.keyLength', + tagClass: asn1$6.Class.UNIVERSAL, + type: asn1$6.Type.INTEGER, + constructed: false, + optional: true, + capture: 'keyLength' + }, { + // prf + name: 'PBES2Algorithms.params.prf', + tagClass: asn1$6.Class.UNIVERSAL, + type: asn1$6.Type.SEQUENCE, + constructed: true, + optional: true, + value: [{ + name: 'PBES2Algorithms.params.prf.algorithm', + tagClass: asn1$6.Class.UNIVERSAL, + type: asn1$6.Type.OID, + constructed: false, + capture: 'prfOid' + }] + }] + }] + }, { + name: 'PBES2Algorithms.encryptionScheme', + tagClass: asn1$6.Class.UNIVERSAL, + type: asn1$6.Type.SEQUENCE, + constructed: true, + value: [{ + name: 'PBES2Algorithms.encryptionScheme.oid', + tagClass: asn1$6.Class.UNIVERSAL, + type: asn1$6.Type.OID, + constructed: false, + capture: 'encOid' + }, { + name: 'PBES2Algorithms.encryptionScheme.iv', + tagClass: asn1$6.Class.UNIVERSAL, + type: asn1$6.Type.OCTETSTRING, + constructed: false, + capture: 'encIv' + }] + }] +}; + +var pkcs12PbeParamsValidator = { + name: 'pkcs-12PbeParams', + tagClass: asn1$6.Class.UNIVERSAL, + type: asn1$6.Type.SEQUENCE, + constructed: true, + value: [{ + name: 'pkcs-12PbeParams.salt', + tagClass: asn1$6.Class.UNIVERSAL, + type: asn1$6.Type.OCTETSTRING, + constructed: false, + capture: 'salt' + }, { + name: 'pkcs-12PbeParams.iterations', + tagClass: asn1$6.Class.UNIVERSAL, + type: asn1$6.Type.INTEGER, + constructed: false, + capture: 'iterations' + }] +}; + +/** + * Encrypts a ASN.1 PrivateKeyInfo object, producing an EncryptedPrivateKeyInfo. + * + * PBES2Algorithms ALGORITHM-IDENTIFIER ::= + * { {PBES2-params IDENTIFIED BY id-PBES2}, ...} + * + * id-PBES2 OBJECT IDENTIFIER ::= {pkcs-5 13} + * + * PBES2-params ::= SEQUENCE { + * keyDerivationFunc AlgorithmIdentifier {{PBES2-KDFs}}, + * encryptionScheme AlgorithmIdentifier {{PBES2-Encs}} + * } + * + * PBES2-KDFs ALGORITHM-IDENTIFIER ::= + * { {PBKDF2-params IDENTIFIED BY id-PBKDF2}, ... } + * + * PBES2-Encs ALGORITHM-IDENTIFIER ::= { ... } + * + * PBKDF2-params ::= SEQUENCE { + * salt CHOICE { + * specified OCTET STRING, + * otherSource AlgorithmIdentifier {{PBKDF2-SaltSources}} + * }, + * iterationCount INTEGER (1..MAX), + * keyLength INTEGER (1..MAX) OPTIONAL, + * prf AlgorithmIdentifier {{PBKDF2-PRFs}} DEFAULT algid-hmacWithSHA1 + * } + * + * @param obj the ASN.1 PrivateKeyInfo object. + * @param password the password to encrypt with. + * @param options: + * algorithm the encryption algorithm to use + * ('aes128', 'aes192', 'aes256', '3des'), defaults to 'aes128'. + * count the iteration count to use. + * saltSize the salt size to use. + * prfAlgorithm the PRF message digest algorithm to use + * ('sha1', 'sha224', 'sha256', 'sha384', 'sha512') + * + * @return the ASN.1 EncryptedPrivateKeyInfo. + */ +pki$3.encryptPrivateKeyInfo = function(obj, password, options) { + // set default options + options = options || {}; + options.saltSize = options.saltSize || 8; + options.count = options.count || 2048; + options.algorithm = options.algorithm || 'aes128'; + options.prfAlgorithm = options.prfAlgorithm || 'sha1'; + + // generate PBE params + var salt = forge$h.random.getBytesSync(options.saltSize); + var count = options.count; + var countBytes = asn1$6.integerToDer(count); + var dkLen; + var encryptionAlgorithm; + var encryptedData; + if(options.algorithm.indexOf('aes') === 0 || options.algorithm === 'des') { + // do PBES2 + var ivLen, encOid, cipherFn; + switch(options.algorithm) { + case 'aes128': + dkLen = 16; + ivLen = 16; + encOid = oids$1['aes128-CBC']; + cipherFn = forge$h.aes.createEncryptionCipher; + break; + case 'aes192': + dkLen = 24; + ivLen = 16; + encOid = oids$1['aes192-CBC']; + cipherFn = forge$h.aes.createEncryptionCipher; + break; + case 'aes256': + dkLen = 32; + ivLen = 16; + encOid = oids$1['aes256-CBC']; + cipherFn = forge$h.aes.createEncryptionCipher; + break; + case 'des': + dkLen = 8; + ivLen = 8; + encOid = oids$1['desCBC']; + cipherFn = forge$h.des.createEncryptionCipher; + break; + default: + var error = new Error('Cannot encrypt private key. Unknown encryption algorithm.'); + error.algorithm = options.algorithm; + throw error; + } + + // get PRF message digest + var prfAlgorithm = 'hmacWith' + options.prfAlgorithm.toUpperCase(); + var md = prfAlgorithmToMessageDigest(prfAlgorithm); + + // encrypt private key using pbe SHA-1 and AES/DES + var dk = forge$h.pkcs5.pbkdf2(password, salt, count, dkLen, md); + var iv = forge$h.random.getBytesSync(ivLen); + var cipher = cipherFn(dk); + cipher.start(iv); + cipher.update(asn1$6.toDer(obj)); + cipher.finish(); + encryptedData = cipher.output.getBytes(); + + // get PBKDF2-params + var params = createPbkdf2Params(salt, countBytes, dkLen, prfAlgorithm); + + encryptionAlgorithm = asn1$6.create( + asn1$6.Class.UNIVERSAL, asn1$6.Type.SEQUENCE, true, [ + asn1$6.create(asn1$6.Class.UNIVERSAL, asn1$6.Type.OID, false, + asn1$6.oidToDer(oids$1['pkcs5PBES2']).getBytes()), + asn1$6.create(asn1$6.Class.UNIVERSAL, asn1$6.Type.SEQUENCE, true, [ + // keyDerivationFunc + asn1$6.create(asn1$6.Class.UNIVERSAL, asn1$6.Type.SEQUENCE, true, [ + asn1$6.create(asn1$6.Class.UNIVERSAL, asn1$6.Type.OID, false, + asn1$6.oidToDer(oids$1['pkcs5PBKDF2']).getBytes()), + // PBKDF2-params + params + ]), + // encryptionScheme + asn1$6.create(asn1$6.Class.UNIVERSAL, asn1$6.Type.SEQUENCE, true, [ + asn1$6.create(asn1$6.Class.UNIVERSAL, asn1$6.Type.OID, false, + asn1$6.oidToDer(encOid).getBytes()), + // iv + asn1$6.create( + asn1$6.Class.UNIVERSAL, asn1$6.Type.OCTETSTRING, false, iv) + ]) + ]) + ]); + } else if(options.algorithm === '3des') { + // Do PKCS12 PBE + dkLen = 24; + + var saltBytes = new forge$h.util.ByteBuffer(salt); + var dk = pki$3.pbe.generatePkcs12Key(password, saltBytes, 1, count, dkLen); + var iv = pki$3.pbe.generatePkcs12Key(password, saltBytes, 2, count, dkLen); + var cipher = forge$h.des.createEncryptionCipher(dk); + cipher.start(iv); + cipher.update(asn1$6.toDer(obj)); + cipher.finish(); + encryptedData = cipher.output.getBytes(); + + encryptionAlgorithm = asn1$6.create( + asn1$6.Class.UNIVERSAL, asn1$6.Type.SEQUENCE, true, [ + asn1$6.create(asn1$6.Class.UNIVERSAL, asn1$6.Type.OID, false, + asn1$6.oidToDer(oids$1['pbeWithSHAAnd3-KeyTripleDES-CBC']).getBytes()), + // pkcs-12PbeParams + asn1$6.create(asn1$6.Class.UNIVERSAL, asn1$6.Type.SEQUENCE, true, [ + // salt + asn1$6.create(asn1$6.Class.UNIVERSAL, asn1$6.Type.OCTETSTRING, false, salt), + // iteration count + asn1$6.create(asn1$6.Class.UNIVERSAL, asn1$6.Type.INTEGER, false, + countBytes.getBytes()) + ]) + ]); + } else { + var error = new Error('Cannot encrypt private key. Unknown encryption algorithm.'); + error.algorithm = options.algorithm; + throw error; + } + + // EncryptedPrivateKeyInfo + var rval = asn1$6.create(asn1$6.Class.UNIVERSAL, asn1$6.Type.SEQUENCE, true, [ + // encryptionAlgorithm + encryptionAlgorithm, + // encryptedData + asn1$6.create( + asn1$6.Class.UNIVERSAL, asn1$6.Type.OCTETSTRING, false, encryptedData) + ]); + return rval; +}; + +/** + * Decrypts a ASN.1 PrivateKeyInfo object. + * + * @param obj the ASN.1 EncryptedPrivateKeyInfo object. + * @param password the password to decrypt with. + * + * @return the ASN.1 PrivateKeyInfo on success, null on failure. + */ +pki$3.decryptPrivateKeyInfo = function(obj, password) { + var rval = null; + + // get PBE params + var capture = {}; + var errors = []; + if(!asn1$6.validate(obj, encryptedPrivateKeyValidator, capture, errors)) { + var error = new Error('Cannot read encrypted private key. ' + + 'ASN.1 object is not a supported EncryptedPrivateKeyInfo.'); + error.errors = errors; + throw error; + } + + // get cipher + var oid = asn1$6.derToOid(capture.encryptionOid); + var cipher = pki$3.pbe.getCipher(oid, capture.encryptionParams, password); + + // get encrypted data + var encrypted = forge$h.util.createBuffer(capture.encryptedData); + + cipher.update(encrypted); + if(cipher.finish()) { + rval = asn1$6.fromDer(cipher.output); + } + + return rval; +}; + +/** + * Converts a EncryptedPrivateKeyInfo to PEM format. + * + * @param epki the EncryptedPrivateKeyInfo. + * @param maxline the maximum characters per line, defaults to 64. + * + * @return the PEM-formatted encrypted private key. + */ +pki$3.encryptedPrivateKeyToPem = function(epki, maxline) { + // convert to DER, then PEM-encode + var msg = { + type: 'ENCRYPTED PRIVATE KEY', + body: asn1$6.toDer(epki).getBytes() + }; + return forge$h.pem.encode(msg, {maxline: maxline}); +}; + +/** + * Converts a PEM-encoded EncryptedPrivateKeyInfo to ASN.1 format. Decryption + * is not performed. + * + * @param pem the EncryptedPrivateKeyInfo in PEM-format. + * + * @return the ASN.1 EncryptedPrivateKeyInfo. + */ +pki$3.encryptedPrivateKeyFromPem = function(pem) { + var msg = forge$h.pem.decode(pem)[0]; + + if(msg.type !== 'ENCRYPTED PRIVATE KEY') { + var error = new Error('Could not convert encrypted private key from PEM; ' + + 'PEM header type is "ENCRYPTED PRIVATE KEY".'); + error.headerType = msg.type; + throw error; + } + if(msg.procType && msg.procType.type === 'ENCRYPTED') { + throw new Error('Could not convert encrypted private key from PEM; ' + + 'PEM is encrypted.'); + } + + // convert DER to ASN.1 object + return asn1$6.fromDer(msg.body); +}; + +/** + * Encrypts an RSA private key. By default, the key will be wrapped in + * a PrivateKeyInfo and encrypted to produce a PKCS#8 EncryptedPrivateKeyInfo. + * This is the standard, preferred way to encrypt a private key. + * + * To produce a non-standard PEM-encrypted private key that uses encapsulated + * headers to indicate the encryption algorithm (old-style non-PKCS#8 OpenSSL + * private key encryption), set the 'legacy' option to true. Note: Using this + * option will cause the iteration count to be forced to 1. + * + * Note: The 'des' algorithm is supported, but it is not considered to be + * secure because it only uses a single 56-bit key. If possible, it is highly + * recommended that a different algorithm be used. + * + * @param rsaKey the RSA key to encrypt. + * @param password the password to use. + * @param options: + * algorithm: the encryption algorithm to use + * ('aes128', 'aes192', 'aes256', '3des', 'des'). + * count: the iteration count to use. + * saltSize: the salt size to use. + * legacy: output an old non-PKCS#8 PEM-encrypted+encapsulated + * headers (DEK-Info) private key. + * + * @return the PEM-encoded ASN.1 EncryptedPrivateKeyInfo. + */ +pki$3.encryptRsaPrivateKey = function(rsaKey, password, options) { + // standard PKCS#8 + options = options || {}; + if(!options.legacy) { + // encrypt PrivateKeyInfo + var rval = pki$3.wrapRsaPrivateKey(pki$3.privateKeyToAsn1(rsaKey)); + rval = pki$3.encryptPrivateKeyInfo(rval, password, options); + return pki$3.encryptedPrivateKeyToPem(rval); + } + + // legacy non-PKCS#8 + var algorithm; + var iv; + var dkLen; + var cipherFn; + switch(options.algorithm) { + case 'aes128': + algorithm = 'AES-128-CBC'; + dkLen = 16; + iv = forge$h.random.getBytesSync(16); + cipherFn = forge$h.aes.createEncryptionCipher; + break; + case 'aes192': + algorithm = 'AES-192-CBC'; + dkLen = 24; + iv = forge$h.random.getBytesSync(16); + cipherFn = forge$h.aes.createEncryptionCipher; + break; + case 'aes256': + algorithm = 'AES-256-CBC'; + dkLen = 32; + iv = forge$h.random.getBytesSync(16); + cipherFn = forge$h.aes.createEncryptionCipher; + break; + case '3des': + algorithm = 'DES-EDE3-CBC'; + dkLen = 24; + iv = forge$h.random.getBytesSync(8); + cipherFn = forge$h.des.createEncryptionCipher; + break; + case 'des': + algorithm = 'DES-CBC'; + dkLen = 8; + iv = forge$h.random.getBytesSync(8); + cipherFn = forge$h.des.createEncryptionCipher; + break; + default: + var error = new Error('Could not encrypt RSA private key; unsupported ' + + 'encryption algorithm "' + options.algorithm + '".'); + error.algorithm = options.algorithm; + throw error; + } + + // encrypt private key using OpenSSL legacy key derivation + var dk = forge$h.pbe.opensslDeriveBytes(password, iv.substr(0, 8), dkLen); + var cipher = cipherFn(dk); + cipher.start(iv); + cipher.update(asn1$6.toDer(pki$3.privateKeyToAsn1(rsaKey))); + cipher.finish(); + + var msg = { + type: 'RSA PRIVATE KEY', + procType: { + version: '4', + type: 'ENCRYPTED' + }, + dekInfo: { + algorithm: algorithm, + parameters: forge$h.util.bytesToHex(iv).toUpperCase() + }, + body: cipher.output.getBytes() + }; + return forge$h.pem.encode(msg); +}; + +/** + * Decrypts an RSA private key. + * + * @param pem the PEM-formatted EncryptedPrivateKeyInfo to decrypt. + * @param password the password to use. + * + * @return the RSA key on success, null on failure. + */ +pki$3.decryptRsaPrivateKey = function(pem, password) { + var rval = null; + + var msg = forge$h.pem.decode(pem)[0]; + + if(msg.type !== 'ENCRYPTED PRIVATE KEY' && + msg.type !== 'PRIVATE KEY' && + msg.type !== 'RSA PRIVATE KEY') { + var error = new Error('Could not convert private key from PEM; PEM header type ' + + 'is not "ENCRYPTED PRIVATE KEY", "PRIVATE KEY", or "RSA PRIVATE KEY".'); + error.headerType = error; + throw error; + } + + if(msg.procType && msg.procType.type === 'ENCRYPTED') { + var dkLen; + var cipherFn; + switch(msg.dekInfo.algorithm) { + case 'DES-CBC': + dkLen = 8; + cipherFn = forge$h.des.createDecryptionCipher; + break; + case 'DES-EDE3-CBC': + dkLen = 24; + cipherFn = forge$h.des.createDecryptionCipher; + break; + case 'AES-128-CBC': + dkLen = 16; + cipherFn = forge$h.aes.createDecryptionCipher; + break; + case 'AES-192-CBC': + dkLen = 24; + cipherFn = forge$h.aes.createDecryptionCipher; + break; + case 'AES-256-CBC': + dkLen = 32; + cipherFn = forge$h.aes.createDecryptionCipher; + break; + case 'RC2-40-CBC': + dkLen = 5; + cipherFn = function(key) { + return forge$h.rc2.createDecryptionCipher(key, 40); + }; + break; + case 'RC2-64-CBC': + dkLen = 8; + cipherFn = function(key) { + return forge$h.rc2.createDecryptionCipher(key, 64); + }; + break; + case 'RC2-128-CBC': + dkLen = 16; + cipherFn = function(key) { + return forge$h.rc2.createDecryptionCipher(key, 128); + }; + break; + default: + var error = new Error('Could not decrypt private key; unsupported ' + + 'encryption algorithm "' + msg.dekInfo.algorithm + '".'); + error.algorithm = msg.dekInfo.algorithm; + throw error; + } + + // use OpenSSL legacy key derivation + var iv = forge$h.util.hexToBytes(msg.dekInfo.parameters); + var dk = forge$h.pbe.opensslDeriveBytes(password, iv.substr(0, 8), dkLen); + var cipher = cipherFn(dk); + cipher.start(iv); + cipher.update(forge$h.util.createBuffer(msg.body)); + if(cipher.finish()) { + rval = cipher.output.getBytes(); + } else { + return rval; + } + } else { + rval = msg.body; + } + + if(msg.type === 'ENCRYPTED PRIVATE KEY') { + rval = pki$3.decryptPrivateKeyInfo(asn1$6.fromDer(rval), password); + } else { + // decryption already performed above + rval = asn1$6.fromDer(rval); + } + + if(rval !== null) { + rval = pki$3.privateKeyFromAsn1(rval); + } + + return rval; +}; + +/** + * Derives a PKCS#12 key. + * + * @param password the password to derive the key material from, null or + * undefined for none. + * @param salt the salt, as a ByteBuffer, to use. + * @param id the PKCS#12 ID byte (1 = key material, 2 = IV, 3 = MAC). + * @param iter the iteration count. + * @param n the number of bytes to derive from the password. + * @param md the message digest to use, defaults to SHA-1. + * + * @return a ByteBuffer with the bytes derived from the password. + */ +pki$3.pbe.generatePkcs12Key = function(password, salt, id, iter, n, md) { + var j, l; + + if(typeof md === 'undefined' || md === null) { + if(!('sha1' in forge$h.md)) { + throw new Error('"sha1" hash algorithm unavailable.'); + } + md = forge$h.md.sha1.create(); + } + + var u = md.digestLength; + var v = md.blockLength; + var result = new forge$h.util.ByteBuffer(); + + /* Convert password to Unicode byte buffer + trailing 0-byte. */ + var passBuf = new forge$h.util.ByteBuffer(); + if(password !== null && password !== undefined) { + for(l = 0; l < password.length; l++) { + passBuf.putInt16(password.charCodeAt(l)); + } + passBuf.putInt16(0); + } + + /* Length of salt and password in BYTES. */ + var p = passBuf.length(); + var s = salt.length(); + + /* 1. Construct a string, D (the "diversifier"), by concatenating + v copies of ID. */ + var D = new forge$h.util.ByteBuffer(); + D.fillWithByte(id, v); + + /* 2. Concatenate copies of the salt together to create a string S of length + v * ceil(s / v) bytes (the final copy of the salt may be trunacted + to create S). + Note that if the salt is the empty string, then so is S. */ + var Slen = v * Math.ceil(s / v); + var S = new forge$h.util.ByteBuffer(); + for(l = 0; l < Slen; l++) { + S.putByte(salt.at(l % s)); + } + + /* 3. Concatenate copies of the password together to create a string P of + length v * ceil(p / v) bytes (the final copy of the password may be + truncated to create P). + Note that if the password is the empty string, then so is P. */ + var Plen = v * Math.ceil(p / v); + var P = new forge$h.util.ByteBuffer(); + for(l = 0; l < Plen; l++) { + P.putByte(passBuf.at(l % p)); + } + + /* 4. Set I=S||P to be the concatenation of S and P. */ + var I = S; + I.putBuffer(P); + + /* 5. Set c=ceil(n / u). */ + var c = Math.ceil(n / u); + + /* 6. For i=1, 2, ..., c, do the following: */ + for(var i = 1; i <= c; i++) { + /* a) Set Ai=H^r(D||I). (l.e. the rth hash of D||I, H(H(H(...H(D||I)))) */ + var buf = new forge$h.util.ByteBuffer(); + buf.putBytes(D.bytes()); + buf.putBytes(I.bytes()); + for(var round = 0; round < iter; round++) { + md.start(); + md.update(buf.getBytes()); + buf = md.digest(); + } + + /* b) Concatenate copies of Ai to create a string B of length v bytes (the + final copy of Ai may be truncated to create B). */ + var B = new forge$h.util.ByteBuffer(); + for(l = 0; l < v; l++) { + B.putByte(buf.at(l % u)); + } + + /* c) Treating I as a concatenation I0, I1, ..., Ik-1 of v-byte blocks, + where k=ceil(s / v) + ceil(p / v), modify I by setting + Ij=(Ij+B+1) mod 2v for each j. */ + var k = Math.ceil(s / v) + Math.ceil(p / v); + var Inew = new forge$h.util.ByteBuffer(); + for(j = 0; j < k; j++) { + var chunk = new forge$h.util.ByteBuffer(I.getBytes(v)); + var x = 0x1ff; + for(l = B.length() - 1; l >= 0; l--) { + x = x >> 8; + x += B.at(l) + chunk.at(l); + chunk.setAt(l, x & 0xff); + } + Inew.putBuffer(chunk); + } + I = Inew; + + /* Add Ai to A. */ + result.putBuffer(buf); + } + + result.truncate(result.length() - n); + return result; +}; + +/** + * Get new Forge cipher object instance. + * + * @param oid the OID (in string notation). + * @param params the ASN.1 params object. + * @param password the password to decrypt with. + * + * @return new cipher object instance. + */ +pki$3.pbe.getCipher = function(oid, params, password) { + switch(oid) { + case pki$3.oids['pkcs5PBES2']: + return pki$3.pbe.getCipherForPBES2(oid, params, password); + + case pki$3.oids['pbeWithSHAAnd3-KeyTripleDES-CBC']: + case pki$3.oids['pbewithSHAAnd40BitRC2-CBC']: + return pki$3.pbe.getCipherForPKCS12PBE(oid, params, password); + + default: + var error = new Error('Cannot read encrypted PBE data block. Unsupported OID.'); + error.oid = oid; + error.supportedOids = [ + 'pkcs5PBES2', + 'pbeWithSHAAnd3-KeyTripleDES-CBC', + 'pbewithSHAAnd40BitRC2-CBC' + ]; + throw error; + } +}; + +/** + * Get new Forge cipher object instance according to PBES2 params block. + * + * The returned cipher instance is already started using the IV + * from PBES2 parameter block. + * + * @param oid the PKCS#5 PBKDF2 OID (in string notation). + * @param params the ASN.1 PBES2-params object. + * @param password the password to decrypt with. + * + * @return new cipher object instance. + */ +pki$3.pbe.getCipherForPBES2 = function(oid, params, password) { + // get PBE params + var capture = {}; + var errors = []; + if(!asn1$6.validate(params, PBES2AlgorithmsValidator, capture, errors)) { + var error = new Error('Cannot read password-based-encryption algorithm ' + + 'parameters. ASN.1 object is not a supported EncryptedPrivateKeyInfo.'); + error.errors = errors; + throw error; + } + + // check oids + oid = asn1$6.derToOid(capture.kdfOid); + if(oid !== pki$3.oids['pkcs5PBKDF2']) { + var error = new Error('Cannot read encrypted private key. ' + + 'Unsupported key derivation function OID.'); + error.oid = oid; + error.supportedOids = ['pkcs5PBKDF2']; + throw error; + } + oid = asn1$6.derToOid(capture.encOid); + if(oid !== pki$3.oids['aes128-CBC'] && + oid !== pki$3.oids['aes192-CBC'] && + oid !== pki$3.oids['aes256-CBC'] && + oid !== pki$3.oids['des-EDE3-CBC'] && + oid !== pki$3.oids['desCBC']) { + var error = new Error('Cannot read encrypted private key. ' + + 'Unsupported encryption scheme OID.'); + error.oid = oid; + error.supportedOids = [ + 'aes128-CBC', 'aes192-CBC', 'aes256-CBC', 'des-EDE3-CBC', 'desCBC']; + throw error; + } + + // set PBE params + var salt = capture.kdfSalt; + var count = forge$h.util.createBuffer(capture.kdfIterationCount); + count = count.getInt(count.length() << 3); + var dkLen; + var cipherFn; + switch(pki$3.oids[oid]) { + case 'aes128-CBC': + dkLen = 16; + cipherFn = forge$h.aes.createDecryptionCipher; + break; + case 'aes192-CBC': + dkLen = 24; + cipherFn = forge$h.aes.createDecryptionCipher; + break; + case 'aes256-CBC': + dkLen = 32; + cipherFn = forge$h.aes.createDecryptionCipher; + break; + case 'des-EDE3-CBC': + dkLen = 24; + cipherFn = forge$h.des.createDecryptionCipher; + break; + case 'desCBC': + dkLen = 8; + cipherFn = forge$h.des.createDecryptionCipher; + break; + } + + // get PRF message digest + var md = prfOidToMessageDigest(capture.prfOid); + + // decrypt private key using pbe with chosen PRF and AES/DES + var dk = forge$h.pkcs5.pbkdf2(password, salt, count, dkLen, md); + var iv = capture.encIv; + var cipher = cipherFn(dk); + cipher.start(iv); + + return cipher; +}; + +/** + * Get new Forge cipher object instance for PKCS#12 PBE. + * + * The returned cipher instance is already started using the key & IV + * derived from the provided password and PKCS#12 PBE salt. + * + * @param oid The PKCS#12 PBE OID (in string notation). + * @param params The ASN.1 PKCS#12 PBE-params object. + * @param password The password to decrypt with. + * + * @return the new cipher object instance. + */ +pki$3.pbe.getCipherForPKCS12PBE = function(oid, params, password) { + // get PBE params + var capture = {}; + var errors = []; + if(!asn1$6.validate(params, pkcs12PbeParamsValidator, capture, errors)) { + var error = new Error('Cannot read password-based-encryption algorithm ' + + 'parameters. ASN.1 object is not a supported EncryptedPrivateKeyInfo.'); + error.errors = errors; + throw error; + } + + var salt = forge$h.util.createBuffer(capture.salt); + var count = forge$h.util.createBuffer(capture.iterations); + count = count.getInt(count.length() << 3); + + var dkLen, dIvLen, cipherFn; + switch(oid) { + case pki$3.oids['pbeWithSHAAnd3-KeyTripleDES-CBC']: + dkLen = 24; + dIvLen = 8; + cipherFn = forge$h.des.startDecrypting; + break; + + case pki$3.oids['pbewithSHAAnd40BitRC2-CBC']: + dkLen = 5; + dIvLen = 8; + cipherFn = function(key, iv) { + var cipher = forge$h.rc2.createDecryptionCipher(key, 40); + cipher.start(iv, null); + return cipher; + }; + break; + + default: + var error = new Error('Cannot read PKCS #12 PBE data block. Unsupported OID.'); + error.oid = oid; + throw error; + } + + // get PRF message digest + var md = prfOidToMessageDigest(capture.prfOid); + var key = pki$3.pbe.generatePkcs12Key(password, salt, 1, count, dkLen, md); + md.start(); + var iv = pki$3.pbe.generatePkcs12Key(password, salt, 2, count, dIvLen, md); + + return cipherFn(key, iv); +}; + +/** + * OpenSSL's legacy key derivation function. + * + * See: http://www.openssl.org/docs/crypto/EVP_BytesToKey.html + * + * @param password the password to derive the key from. + * @param salt the salt to use, null for none. + * @param dkLen the number of bytes needed for the derived key. + * @param [options] the options to use: + * [md] an optional message digest object to use. + */ +pki$3.pbe.opensslDeriveBytes = function(password, salt, dkLen, md) { + if(typeof md === 'undefined' || md === null) { + if(!('md5' in forge$h.md)) { + throw new Error('"md5" hash algorithm unavailable.'); + } + md = forge$h.md.md5.create(); + } + if(salt === null) { + salt = ''; + } + var digests = [hash(md, password + salt)]; + for(var length = 16, i = 1; length < dkLen; ++i, length += 16) { + digests.push(hash(md, digests[i - 1] + password + salt)); + } + return digests.join('').substr(0, dkLen); +}; + +function hash(md, bytes) { + return md.start().update(bytes).digest().getBytes(); +} + +function prfOidToMessageDigest(prfOid) { + // get PRF algorithm, default to SHA-1 + var prfAlgorithm; + if(!prfOid) { + prfAlgorithm = 'hmacWithSHA1'; + } else { + prfAlgorithm = pki$3.oids[asn1$6.derToOid(prfOid)]; + if(!prfAlgorithm) { + var error = new Error('Unsupported PRF OID.'); + error.oid = prfOid; + error.supported = [ + 'hmacWithSHA1', 'hmacWithSHA224', 'hmacWithSHA256', 'hmacWithSHA384', + 'hmacWithSHA512']; + throw error; + } + } + return prfAlgorithmToMessageDigest(prfAlgorithm); +} + +function prfAlgorithmToMessageDigest(prfAlgorithm) { + var factory = forge$h.md; + switch(prfAlgorithm) { + case 'hmacWithSHA224': + factory = forge$h.md.sha512; + case 'hmacWithSHA1': + case 'hmacWithSHA256': + case 'hmacWithSHA384': + case 'hmacWithSHA512': + prfAlgorithm = prfAlgorithm.substr(8).toLowerCase(); + break; + default: + var error = new Error('Unsupported PRF algorithm.'); + error.algorithm = prfAlgorithm; + error.supported = [ + 'hmacWithSHA1', 'hmacWithSHA224', 'hmacWithSHA256', 'hmacWithSHA384', + 'hmacWithSHA512']; + throw error; + } + if(!factory || !(prfAlgorithm in factory)) { + throw new Error('Unknown hash algorithm: ' + prfAlgorithm); + } + return factory[prfAlgorithm].create(); +} + +function createPbkdf2Params(salt, countBytes, dkLen, prfAlgorithm) { + var params = asn1$6.create(asn1$6.Class.UNIVERSAL, asn1$6.Type.SEQUENCE, true, [ + // salt + asn1$6.create( + asn1$6.Class.UNIVERSAL, asn1$6.Type.OCTETSTRING, false, salt), + // iteration count + asn1$6.create(asn1$6.Class.UNIVERSAL, asn1$6.Type.INTEGER, false, + countBytes.getBytes()) + ]); + // when PRF algorithm is not SHA-1 default, add key length and PRF algorithm + if(prfAlgorithm !== 'hmacWithSHA1') { + params.value.push( + // key length + asn1$6.create(asn1$6.Class.UNIVERSAL, asn1$6.Type.INTEGER, false, + forge$h.util.hexToBytes(dkLen.toString(16))), + // AlgorithmIdentifier + asn1$6.create(asn1$6.Class.UNIVERSAL, asn1$6.Type.SEQUENCE, true, [ + // algorithm + asn1$6.create(asn1$6.Class.UNIVERSAL, asn1$6.Type.OID, false, + asn1$6.oidToDer(pki$3.oids[prfAlgorithm]).getBytes()), + // parameters (null) + asn1$6.create(asn1$6.Class.UNIVERSAL, asn1$6.Type.NULL, false, '') + ])); + } + return params; +} + +/** + * Javascript implementation of ASN.1 validators for PKCS#7 v1.5. + * + * @author Dave Longley + * @author Stefan Siegl + * + * Copyright (c) 2012-2015 Digital Bazaar, Inc. + * Copyright (c) 2012 Stefan Siegl + * + * The ASN.1 representation of PKCS#7 is as follows + * (see RFC #2315 for details, http://www.ietf.org/rfc/rfc2315.txt): + * + * A PKCS#7 message consists of a ContentInfo on root level, which may + * contain any number of further ContentInfo nested into it. + * + * ContentInfo ::= SEQUENCE { + * contentType ContentType, + * content [0] EXPLICIT ANY DEFINED BY contentType OPTIONAL + * } + * + * ContentType ::= OBJECT IDENTIFIER + * + * EnvelopedData ::= SEQUENCE { + * version Version, + * recipientInfos RecipientInfos, + * encryptedContentInfo EncryptedContentInfo + * } + * + * EncryptedData ::= SEQUENCE { + * version Version, + * encryptedContentInfo EncryptedContentInfo + * } + * + * id-signedData OBJECT IDENTIFIER ::= { iso(1) member-body(2) + * us(840) rsadsi(113549) pkcs(1) pkcs7(7) 2 } + * + * SignedData ::= SEQUENCE { + * version INTEGER, + * digestAlgorithms DigestAlgorithmIdentifiers, + * contentInfo ContentInfo, + * certificates [0] IMPLICIT Certificates OPTIONAL, + * crls [1] IMPLICIT CertificateRevocationLists OPTIONAL, + * signerInfos SignerInfos + * } + * + * SignerInfos ::= SET OF SignerInfo + * + * SignerInfo ::= SEQUENCE { + * version Version, + * issuerAndSerialNumber IssuerAndSerialNumber, + * digestAlgorithm DigestAlgorithmIdentifier, + * authenticatedAttributes [0] IMPLICIT Attributes OPTIONAL, + * digestEncryptionAlgorithm DigestEncryptionAlgorithmIdentifier, + * encryptedDigest EncryptedDigest, + * unauthenticatedAttributes [1] IMPLICIT Attributes OPTIONAL + * } + * + * EncryptedDigest ::= OCTET STRING + * + * Attributes ::= SET OF Attribute + * + * Attribute ::= SEQUENCE { + * attrType OBJECT IDENTIFIER, + * attrValues SET OF AttributeValue + * } + * + * AttributeValue ::= ANY + * + * Version ::= INTEGER + * + * RecipientInfos ::= SET OF RecipientInfo + * + * EncryptedContentInfo ::= SEQUENCE { + * contentType ContentType, + * contentEncryptionAlgorithm ContentEncryptionAlgorithmIdentifier, + * encryptedContent [0] IMPLICIT EncryptedContent OPTIONAL + * } + * + * ContentEncryptionAlgorithmIdentifier ::= AlgorithmIdentifier + * + * The AlgorithmIdentifier contains an Object Identifier (OID) and parameters + * for the algorithm, if any. In the case of AES and DES3, there is only one, + * the IV. + * + * AlgorithmIdentifer ::= SEQUENCE { + * algorithm OBJECT IDENTIFIER, + * parameters ANY DEFINED BY algorithm OPTIONAL + * } + * + * EncryptedContent ::= OCTET STRING + * + * RecipientInfo ::= SEQUENCE { + * version Version, + * issuerAndSerialNumber IssuerAndSerialNumber, + * keyEncryptionAlgorithm KeyEncryptionAlgorithmIdentifier, + * encryptedKey EncryptedKey + * } + * + * IssuerAndSerialNumber ::= SEQUENCE { + * issuer Name, + * serialNumber CertificateSerialNumber + * } + * + * CertificateSerialNumber ::= INTEGER + * + * KeyEncryptionAlgorithmIdentifier ::= AlgorithmIdentifier + * + * EncryptedKey ::= OCTET STRING + */ + +var forge$g = forge$D; + + + +// shortcut for ASN.1 API +var asn1$5 = forge$g.asn1; + +// shortcut for PKCS#7 API +var p7v = forge$g.pkcs7asn1 = forge$g.pkcs7asn1 || {}; +forge$g.pkcs7 = forge$g.pkcs7 || {}; +forge$g.pkcs7.asn1 = p7v; + +var contentInfoValidator$1 = { + name: 'ContentInfo', + tagClass: asn1$5.Class.UNIVERSAL, + type: asn1$5.Type.SEQUENCE, + constructed: true, + value: [{ + name: 'ContentInfo.ContentType', + tagClass: asn1$5.Class.UNIVERSAL, + type: asn1$5.Type.OID, + constructed: false, + capture: 'contentType' + }, { + name: 'ContentInfo.content', + tagClass: asn1$5.Class.CONTEXT_SPECIFIC, + type: 0, + constructed: true, + optional: true, + captureAsn1: 'content' + }] +}; +p7v.contentInfoValidator = contentInfoValidator$1; + +var encryptedContentInfoValidator = { + name: 'EncryptedContentInfo', + tagClass: asn1$5.Class.UNIVERSAL, + type: asn1$5.Type.SEQUENCE, + constructed: true, + value: [{ + name: 'EncryptedContentInfo.contentType', + tagClass: asn1$5.Class.UNIVERSAL, + type: asn1$5.Type.OID, + constructed: false, + capture: 'contentType' + }, { + name: 'EncryptedContentInfo.contentEncryptionAlgorithm', + tagClass: asn1$5.Class.UNIVERSAL, + type: asn1$5.Type.SEQUENCE, + constructed: true, + value: [{ + name: 'EncryptedContentInfo.contentEncryptionAlgorithm.algorithm', + tagClass: asn1$5.Class.UNIVERSAL, + type: asn1$5.Type.OID, + constructed: false, + capture: 'encAlgorithm' + }, { + name: 'EncryptedContentInfo.contentEncryptionAlgorithm.parameter', + tagClass: asn1$5.Class.UNIVERSAL, + captureAsn1: 'encParameter' + }] + }, { + name: 'EncryptedContentInfo.encryptedContent', + tagClass: asn1$5.Class.CONTEXT_SPECIFIC, + type: 0, + /* The PKCS#7 structure output by OpenSSL somewhat differs from what + * other implementations do generate. + * + * OpenSSL generates a structure like this: + * SEQUENCE { + * ... + * [0] + * 26 DA 67 D2 17 9C 45 3C B1 2A A8 59 2F 29 33 38 + * C3 C3 DF 86 71 74 7A 19 9F 40 D0 29 BE 85 90 45 + * ... + * } + * + * Whereas other implementations (and this PKCS#7 module) generate: + * SEQUENCE { + * ... + * [0] { + * OCTET STRING + * 26 DA 67 D2 17 9C 45 3C B1 2A A8 59 2F 29 33 38 + * C3 C3 DF 86 71 74 7A 19 9F 40 D0 29 BE 85 90 45 + * ... + * } + * } + * + * In order to support both, we just capture the context specific + * field here. The OCTET STRING bit is removed below. + */ + capture: 'encryptedContent', + captureAsn1: 'encryptedContentAsn1' + }] +}; + +p7v.envelopedDataValidator = { + name: 'EnvelopedData', + tagClass: asn1$5.Class.UNIVERSAL, + type: asn1$5.Type.SEQUENCE, + constructed: true, + value: [{ + name: 'EnvelopedData.Version', + tagClass: asn1$5.Class.UNIVERSAL, + type: asn1$5.Type.INTEGER, + constructed: false, + capture: 'version' + }, { + name: 'EnvelopedData.RecipientInfos', + tagClass: asn1$5.Class.UNIVERSAL, + type: asn1$5.Type.SET, + constructed: true, + captureAsn1: 'recipientInfos' + }].concat(encryptedContentInfoValidator) +}; + +p7v.encryptedDataValidator = { + name: 'EncryptedData', + tagClass: asn1$5.Class.UNIVERSAL, + type: asn1$5.Type.SEQUENCE, + constructed: true, + value: [{ + name: 'EncryptedData.Version', + tagClass: asn1$5.Class.UNIVERSAL, + type: asn1$5.Type.INTEGER, + constructed: false, + capture: 'version' + }].concat(encryptedContentInfoValidator) +}; + +var signerValidator = { + name: 'SignerInfo', + tagClass: asn1$5.Class.UNIVERSAL, + type: asn1$5.Type.SEQUENCE, + constructed: true, + value: [{ + name: 'SignerInfo.version', + tagClass: asn1$5.Class.UNIVERSAL, + type: asn1$5.Type.INTEGER, + constructed: false + }, { + name: 'SignerInfo.issuerAndSerialNumber', + tagClass: asn1$5.Class.UNIVERSAL, + type: asn1$5.Type.SEQUENCE, + constructed: true, + value: [{ + name: 'SignerInfo.issuerAndSerialNumber.issuer', + tagClass: asn1$5.Class.UNIVERSAL, + type: asn1$5.Type.SEQUENCE, + constructed: true, + captureAsn1: 'issuer' + }, { + name: 'SignerInfo.issuerAndSerialNumber.serialNumber', + tagClass: asn1$5.Class.UNIVERSAL, + type: asn1$5.Type.INTEGER, + constructed: false, + capture: 'serial' + }] + }, { + name: 'SignerInfo.digestAlgorithm', + tagClass: asn1$5.Class.UNIVERSAL, + type: asn1$5.Type.SEQUENCE, + constructed: true, + value: [{ + name: 'SignerInfo.digestAlgorithm.algorithm', + tagClass: asn1$5.Class.UNIVERSAL, + type: asn1$5.Type.OID, + constructed: false, + capture: 'digestAlgorithm' + }, { + name: 'SignerInfo.digestAlgorithm.parameter', + tagClass: asn1$5.Class.UNIVERSAL, + constructed: false, + captureAsn1: 'digestParameter', + optional: true + }] + }, { + name: 'SignerInfo.authenticatedAttributes', + tagClass: asn1$5.Class.CONTEXT_SPECIFIC, + type: 0, + constructed: true, + optional: true, + capture: 'authenticatedAttributes' + }, { + name: 'SignerInfo.digestEncryptionAlgorithm', + tagClass: asn1$5.Class.UNIVERSAL, + type: asn1$5.Type.SEQUENCE, + constructed: true, + capture: 'signatureAlgorithm' + }, { + name: 'SignerInfo.encryptedDigest', + tagClass: asn1$5.Class.UNIVERSAL, + type: asn1$5.Type.OCTETSTRING, + constructed: false, + capture: 'signature' + }, { + name: 'SignerInfo.unauthenticatedAttributes', + tagClass: asn1$5.Class.CONTEXT_SPECIFIC, + type: 1, + constructed: true, + optional: true, + capture: 'unauthenticatedAttributes' + }] +}; + +p7v.signedDataValidator = { + name: 'SignedData', + tagClass: asn1$5.Class.UNIVERSAL, + type: asn1$5.Type.SEQUENCE, + constructed: true, + value: [{ + name: 'SignedData.Version', + tagClass: asn1$5.Class.UNIVERSAL, + type: asn1$5.Type.INTEGER, + constructed: false, + capture: 'version' + }, { + name: 'SignedData.DigestAlgorithms', + tagClass: asn1$5.Class.UNIVERSAL, + type: asn1$5.Type.SET, + constructed: true, + captureAsn1: 'digestAlgorithms' + }, + contentInfoValidator$1, + { + name: 'SignedData.Certificates', + tagClass: asn1$5.Class.CONTEXT_SPECIFIC, + type: 0, + optional: true, + captureAsn1: 'certificates' + }, { + name: 'SignedData.CertificateRevocationLists', + tagClass: asn1$5.Class.CONTEXT_SPECIFIC, + type: 1, + optional: true, + captureAsn1: 'crls' + }, { + name: 'SignedData.SignerInfos', + tagClass: asn1$5.Class.UNIVERSAL, + type: asn1$5.Type.SET, + capture: 'signerInfos', + optional: true, + value: [signerValidator] + }] +}; + +p7v.recipientInfoValidator = { + name: 'RecipientInfo', + tagClass: asn1$5.Class.UNIVERSAL, + type: asn1$5.Type.SEQUENCE, + constructed: true, + value: [{ + name: 'RecipientInfo.version', + tagClass: asn1$5.Class.UNIVERSAL, + type: asn1$5.Type.INTEGER, + constructed: false, + capture: 'version' + }, { + name: 'RecipientInfo.issuerAndSerial', + tagClass: asn1$5.Class.UNIVERSAL, + type: asn1$5.Type.SEQUENCE, + constructed: true, + value: [{ + name: 'RecipientInfo.issuerAndSerial.issuer', + tagClass: asn1$5.Class.UNIVERSAL, + type: asn1$5.Type.SEQUENCE, + constructed: true, + captureAsn1: 'issuer' + }, { + name: 'RecipientInfo.issuerAndSerial.serialNumber', + tagClass: asn1$5.Class.UNIVERSAL, + type: asn1$5.Type.INTEGER, + constructed: false, + capture: 'serial' + }] + }, { + name: 'RecipientInfo.keyEncryptionAlgorithm', + tagClass: asn1$5.Class.UNIVERSAL, + type: asn1$5.Type.SEQUENCE, + constructed: true, + value: [{ + name: 'RecipientInfo.keyEncryptionAlgorithm.algorithm', + tagClass: asn1$5.Class.UNIVERSAL, + type: asn1$5.Type.OID, + constructed: false, + capture: 'encAlgorithm' + }, { + name: 'RecipientInfo.keyEncryptionAlgorithm.parameter', + tagClass: asn1$5.Class.UNIVERSAL, + constructed: false, + captureAsn1: 'encParameter', + optional: true + }] + }, { + name: 'RecipientInfo.encryptedKey', + tagClass: asn1$5.Class.UNIVERSAL, + type: asn1$5.Type.OCTETSTRING, + constructed: false, + capture: 'encKey' + }] +}; + +/** + * Javascript implementation of mask generation function MGF1. + * + * @author Stefan Siegl + * @author Dave Longley + * + * Copyright (c) 2012 Stefan Siegl + * Copyright (c) 2014 Digital Bazaar, Inc. + */ + +var forge$f = forge$D; + + +forge$f.mgf = forge$f.mgf || {}; +var mgf1 = forge$f.mgf.mgf1 = forge$f.mgf1 = forge$f.mgf1 || {}; + +/** + * Creates a MGF1 mask generation function object. + * + * @param md the message digest API to use (eg: forge.md.sha1.create()). + * + * @return a mask generation function object. + */ +mgf1.create = function(md) { + var mgf = { + /** + * Generate mask of specified length. + * + * @param {String} seed The seed for mask generation. + * @param maskLen Number of bytes to generate. + * @return {String} The generated mask. + */ + generate: function(seed, maskLen) { + /* 2. Let T be the empty octet string. */ + var t = new forge$f.util.ByteBuffer(); + + /* 3. For counter from 0 to ceil(maskLen / hLen), do the following: */ + var len = Math.ceil(maskLen / md.digestLength); + for(var i = 0; i < len; i++) { + /* a. Convert counter to an octet string C of length 4 octets */ + var c = new forge$f.util.ByteBuffer(); + c.putInt32(i); + + /* b. Concatenate the hash of the seed mgfSeed and C to the octet + * string T: */ + md.start(); + md.update(seed + c.getBytes()); + t.putBuffer(md.digest()); + } + + /* Output the leading maskLen octets of T as the octet string mask. */ + t.truncate(t.length() - maskLen); + return t.getBytes(); + } + }; + + return mgf; +}; + +/** + * Node.js module for Forge mask generation functions. + * + * @author Stefan Siegl + * + * Copyright 2012 Stefan Siegl + */ + +var forge$e = forge$D; + + +forge$e.mgf = forge$e.mgf || {}; +forge$e.mgf.mgf1 = forge$e.mgf1; + +/** + * Javascript implementation of PKCS#1 PSS signature padding. + * + * @author Stefan Siegl + * + * Copyright (c) 2012 Stefan Siegl + */ + +var forge$d = forge$D; + + + +// shortcut for PSS API +var pss = forge$d.pss = forge$d.pss || {}; + +/** + * Creates a PSS signature scheme object. + * + * There are several ways to provide a salt for encoding: + * + * 1. Specify the saltLength only and the built-in PRNG will generate it. + * 2. Specify the saltLength and a custom PRNG with 'getBytesSync' defined that + * will be used. + * 3. Specify the salt itself as a forge.util.ByteBuffer. + * + * @param options the options to use: + * md the message digest object to use, a forge md instance. + * mgf the mask generation function to use, a forge mgf instance. + * [saltLength] the length of the salt in octets. + * [prng] the pseudo-random number generator to use to produce a salt. + * [salt] the salt to use when encoding. + * + * @return a signature scheme object. + */ +pss.create = function(options) { + // backwards compatibility w/legacy args: hash, mgf, sLen + if(arguments.length === 3) { + options = { + md: arguments[0], + mgf: arguments[1], + saltLength: arguments[2] + }; + } + + var hash = options.md; + var mgf = options.mgf; + var hLen = hash.digestLength; + + var salt_ = options.salt || null; + if(typeof salt_ === 'string') { + // assume binary-encoded string + salt_ = forge$d.util.createBuffer(salt_); + } + + var sLen; + if('saltLength' in options) { + sLen = options.saltLength; + } else if(salt_ !== null) { + sLen = salt_.length(); + } else { + throw new Error('Salt length not specified or specific salt not given.'); + } + + if(salt_ !== null && salt_.length() !== sLen) { + throw new Error('Given salt length does not match length of given salt.'); + } + + var prng = options.prng || forge$d.random; + + var pssobj = {}; + + /** + * Encodes a PSS signature. + * + * This function implements EMSA-PSS-ENCODE as per RFC 3447, section 9.1.1. + * + * @param md the message digest object with the hash to sign. + * @param modsBits the length of the RSA modulus in bits. + * + * @return the encoded message as a binary-encoded string of length + * ceil((modBits - 1) / 8). + */ + pssobj.encode = function(md, modBits) { + var i; + var emBits = modBits - 1; + var emLen = Math.ceil(emBits / 8); + + /* 2. Let mHash = Hash(M), an octet string of length hLen. */ + var mHash = md.digest().getBytes(); + + /* 3. If emLen < hLen + sLen + 2, output "encoding error" and stop. */ + if(emLen < hLen + sLen + 2) { + throw new Error('Message is too long to encrypt.'); + } + + /* 4. Generate a random octet string salt of length sLen; if sLen = 0, + * then salt is the empty string. */ + var salt; + if(salt_ === null) { + salt = prng.getBytesSync(sLen); + } else { + salt = salt_.bytes(); + } + + /* 5. Let M' = (0x)00 00 00 00 00 00 00 00 || mHash || salt; */ + var m_ = new forge$d.util.ByteBuffer(); + m_.fillWithByte(0, 8); + m_.putBytes(mHash); + m_.putBytes(salt); + + /* 6. Let H = Hash(M'), an octet string of length hLen. */ + hash.start(); + hash.update(m_.getBytes()); + var h = hash.digest().getBytes(); + + /* 7. Generate an octet string PS consisting of emLen - sLen - hLen - 2 + * zero octets. The length of PS may be 0. */ + var ps = new forge$d.util.ByteBuffer(); + ps.fillWithByte(0, emLen - sLen - hLen - 2); + + /* 8. Let DB = PS || 0x01 || salt; DB is an octet string of length + * emLen - hLen - 1. */ + ps.putByte(0x01); + ps.putBytes(salt); + var db = ps.getBytes(); + + /* 9. Let dbMask = MGF(H, emLen - hLen - 1). */ + var maskLen = emLen - hLen - 1; + var dbMask = mgf.generate(h, maskLen); + + /* 10. Let maskedDB = DB \xor dbMask. */ + var maskedDB = ''; + for(i = 0; i < maskLen; i++) { + maskedDB += String.fromCharCode(db.charCodeAt(i) ^ dbMask.charCodeAt(i)); + } + + /* 11. Set the leftmost 8emLen - emBits bits of the leftmost octet in + * maskedDB to zero. */ + var mask = (0xFF00 >> (8 * emLen - emBits)) & 0xFF; + maskedDB = String.fromCharCode(maskedDB.charCodeAt(0) & ~mask) + + maskedDB.substr(1); + + /* 12. Let EM = maskedDB || H || 0xbc. + * 13. Output EM. */ + return maskedDB + h + String.fromCharCode(0xbc); + }; + + /** + * Verifies a PSS signature. + * + * This function implements EMSA-PSS-VERIFY as per RFC 3447, section 9.1.2. + * + * @param mHash the message digest hash, as a binary-encoded string, to + * compare against the signature. + * @param em the encoded message, as a binary-encoded string + * (RSA decryption result). + * @param modsBits the length of the RSA modulus in bits. + * + * @return true if the signature was verified, false if not. + */ + pssobj.verify = function(mHash, em, modBits) { + var i; + var emBits = modBits - 1; + var emLen = Math.ceil(emBits / 8); + + /* c. Convert the message representative m to an encoded message EM + * of length emLen = ceil((modBits - 1) / 8) octets, where modBits + * is the length in bits of the RSA modulus n */ + em = em.substr(-emLen); + + /* 3. If emLen < hLen + sLen + 2, output "inconsistent" and stop. */ + if(emLen < hLen + sLen + 2) { + throw new Error('Inconsistent parameters to PSS signature verification.'); + } + + /* 4. If the rightmost octet of EM does not have hexadecimal value + * 0xbc, output "inconsistent" and stop. */ + if(em.charCodeAt(emLen - 1) !== 0xbc) { + throw new Error('Encoded message does not end in 0xBC.'); + } + + /* 5. Let maskedDB be the leftmost emLen - hLen - 1 octets of EM, and + * let H be the next hLen octets. */ + var maskLen = emLen - hLen - 1; + var maskedDB = em.substr(0, maskLen); + var h = em.substr(maskLen, hLen); + + /* 6. If the leftmost 8emLen - emBits bits of the leftmost octet in + * maskedDB are not all equal to zero, output "inconsistent" and stop. */ + var mask = (0xFF00 >> (8 * emLen - emBits)) & 0xFF; + if((maskedDB.charCodeAt(0) & mask) !== 0) { + throw new Error('Bits beyond keysize not zero as expected.'); + } + + /* 7. Let dbMask = MGF(H, emLen - hLen - 1). */ + var dbMask = mgf.generate(h, maskLen); + + /* 8. Let DB = maskedDB \xor dbMask. */ + var db = ''; + for(i = 0; i < maskLen; i++) { + db += String.fromCharCode(maskedDB.charCodeAt(i) ^ dbMask.charCodeAt(i)); + } + + /* 9. Set the leftmost 8emLen - emBits bits of the leftmost octet + * in DB to zero. */ + db = String.fromCharCode(db.charCodeAt(0) & ~mask) + db.substr(1); + + /* 10. If the emLen - hLen - sLen - 2 leftmost octets of DB are not zero + * or if the octet at position emLen - hLen - sLen - 1 (the leftmost + * position is "position 1") does not have hexadecimal value 0x01, + * output "inconsistent" and stop. */ + var checkLen = emLen - hLen - sLen - 2; + for(i = 0; i < checkLen; i++) { + if(db.charCodeAt(i) !== 0x00) { + throw new Error('Leftmost octets not zero as expected'); + } + } + + if(db.charCodeAt(checkLen) !== 0x01) { + throw new Error('Inconsistent PSS signature, 0x01 marker not found'); + } + + /* 11. Let salt be the last sLen octets of DB. */ + var salt = db.substr(-sLen); + + /* 12. Let M' = (0x)00 00 00 00 00 00 00 00 || mHash || salt */ + var m_ = new forge$d.util.ByteBuffer(); + m_.fillWithByte(0, 8); + m_.putBytes(mHash); + m_.putBytes(salt); + + /* 13. Let H' = Hash(M'), an octet string of length hLen. */ + hash.start(); + hash.update(m_.getBytes()); + var h_ = hash.digest().getBytes(); + + /* 14. If H = H', output "consistent." Otherwise, output "inconsistent." */ + return h === h_; + }; + + return pssobj; +}; + +/** + * Javascript implementation of X.509 and related components (such as + * Certification Signing Requests) of a Public Key Infrastructure. + * + * @author Dave Longley + * + * Copyright (c) 2010-2014 Digital Bazaar, Inc. + * + * The ASN.1 representation of an X.509v3 certificate is as follows + * (see RFC 2459): + * + * Certificate ::= SEQUENCE { + * tbsCertificate TBSCertificate, + * signatureAlgorithm AlgorithmIdentifier, + * signatureValue BIT STRING + * } + * + * TBSCertificate ::= SEQUENCE { + * version [0] EXPLICIT Version DEFAULT v1, + * serialNumber CertificateSerialNumber, + * signature AlgorithmIdentifier, + * issuer Name, + * validity Validity, + * subject Name, + * subjectPublicKeyInfo SubjectPublicKeyInfo, + * issuerUniqueID [1] IMPLICIT UniqueIdentifier OPTIONAL, + * -- If present, version shall be v2 or v3 + * subjectUniqueID [2] IMPLICIT UniqueIdentifier OPTIONAL, + * -- If present, version shall be v2 or v3 + * extensions [3] EXPLICIT Extensions OPTIONAL + * -- If present, version shall be v3 + * } + * + * Version ::= INTEGER { v1(0), v2(1), v3(2) } + * + * CertificateSerialNumber ::= INTEGER + * + * Name ::= CHOICE { + * // only one possible choice for now + * RDNSequence + * } + * + * RDNSequence ::= SEQUENCE OF RelativeDistinguishedName + * + * RelativeDistinguishedName ::= SET OF AttributeTypeAndValue + * + * AttributeTypeAndValue ::= SEQUENCE { + * type AttributeType, + * value AttributeValue + * } + * AttributeType ::= OBJECT IDENTIFIER + * AttributeValue ::= ANY DEFINED BY AttributeType + * + * Validity ::= SEQUENCE { + * notBefore Time, + * notAfter Time + * } + * + * Time ::= CHOICE { + * utcTime UTCTime, + * generalTime GeneralizedTime + * } + * + * UniqueIdentifier ::= BIT STRING + * + * SubjectPublicKeyInfo ::= SEQUENCE { + * algorithm AlgorithmIdentifier, + * subjectPublicKey BIT STRING + * } + * + * Extensions ::= SEQUENCE SIZE (1..MAX) OF Extension + * + * Extension ::= SEQUENCE { + * extnID OBJECT IDENTIFIER, + * critical BOOLEAN DEFAULT FALSE, + * extnValue OCTET STRING + * } + * + * The only key algorithm currently supported for PKI is RSA. + * + * RSASSA-PSS signatures are described in RFC 3447 and RFC 4055. + * + * PKCS#10 v1.7 describes certificate signing requests: + * + * CertificationRequestInfo: + * + * CertificationRequestInfo ::= SEQUENCE { + * version INTEGER { v1(0) } (v1,...), + * subject Name, + * subjectPKInfo SubjectPublicKeyInfo{{ PKInfoAlgorithms }}, + * attributes [0] Attributes{{ CRIAttributes }} + * } + * + * Attributes { ATTRIBUTE:IOSet } ::= SET OF Attribute{{ IOSet }} + * + * CRIAttributes ATTRIBUTE ::= { + * ... -- add any locally defined attributes here -- } + * + * Attribute { ATTRIBUTE:IOSet } ::= SEQUENCE { + * type ATTRIBUTE.&id({IOSet}), + * values SET SIZE(1..MAX) OF ATTRIBUTE.&Type({IOSet}{@type}) + * } + * + * CertificationRequest ::= SEQUENCE { + * certificationRequestInfo CertificationRequestInfo, + * signatureAlgorithm AlgorithmIdentifier{{ SignatureAlgorithms }}, + * signature BIT STRING + * } + */ + +var forge$c = forge$D; + + + + + + + + + + + +// shortcut for asn.1 API +var asn1$4 = forge$c.asn1; + +/* Public Key Infrastructure (PKI) implementation. */ +var pki$2 = forge$c.pki = forge$c.pki || {}; +var oids = pki$2.oids; + +// short name OID mappings +var _shortNames = {}; +_shortNames['CN'] = oids['commonName']; +_shortNames['commonName'] = 'CN'; +_shortNames['C'] = oids['countryName']; +_shortNames['countryName'] = 'C'; +_shortNames['L'] = oids['localityName']; +_shortNames['localityName'] = 'L'; +_shortNames['ST'] = oids['stateOrProvinceName']; +_shortNames['stateOrProvinceName'] = 'ST'; +_shortNames['O'] = oids['organizationName']; +_shortNames['organizationName'] = 'O'; +_shortNames['OU'] = oids['organizationalUnitName']; +_shortNames['organizationalUnitName'] = 'OU'; +_shortNames['E'] = oids['emailAddress']; +_shortNames['emailAddress'] = 'E'; + +// validator for an SubjectPublicKeyInfo structure +// Note: Currently only works with an RSA public key +var publicKeyValidator$1 = forge$c.pki.rsa.publicKeyValidator; + +// validator for an X.509v3 certificate +var x509CertificateValidator = { + name: 'Certificate', + tagClass: asn1$4.Class.UNIVERSAL, + type: asn1$4.Type.SEQUENCE, + constructed: true, + value: [{ + name: 'Certificate.TBSCertificate', + tagClass: asn1$4.Class.UNIVERSAL, + type: asn1$4.Type.SEQUENCE, + constructed: true, + captureAsn1: 'tbsCertificate', + value: [{ + name: 'Certificate.TBSCertificate.version', + tagClass: asn1$4.Class.CONTEXT_SPECIFIC, + type: 0, + constructed: true, + optional: true, + value: [{ + name: 'Certificate.TBSCertificate.version.integer', + tagClass: asn1$4.Class.UNIVERSAL, + type: asn1$4.Type.INTEGER, + constructed: false, + capture: 'certVersion' + }] + }, { + name: 'Certificate.TBSCertificate.serialNumber', + tagClass: asn1$4.Class.UNIVERSAL, + type: asn1$4.Type.INTEGER, + constructed: false, + capture: 'certSerialNumber' + }, { + name: 'Certificate.TBSCertificate.signature', + tagClass: asn1$4.Class.UNIVERSAL, + type: asn1$4.Type.SEQUENCE, + constructed: true, + value: [{ + name: 'Certificate.TBSCertificate.signature.algorithm', + tagClass: asn1$4.Class.UNIVERSAL, + type: asn1$4.Type.OID, + constructed: false, + capture: 'certinfoSignatureOid' + }, { + name: 'Certificate.TBSCertificate.signature.parameters', + tagClass: asn1$4.Class.UNIVERSAL, + optional: true, + captureAsn1: 'certinfoSignatureParams' + }] + }, { + name: 'Certificate.TBSCertificate.issuer', + tagClass: asn1$4.Class.UNIVERSAL, + type: asn1$4.Type.SEQUENCE, + constructed: true, + captureAsn1: 'certIssuer' + }, { + name: 'Certificate.TBSCertificate.validity', + tagClass: asn1$4.Class.UNIVERSAL, + type: asn1$4.Type.SEQUENCE, + constructed: true, + // Note: UTC and generalized times may both appear so the capture + // names are based on their detected order, the names used below + // are only for the common case, which validity time really means + // "notBefore" and which means "notAfter" will be determined by order + value: [{ + // notBefore (Time) (UTC time case) + name: 'Certificate.TBSCertificate.validity.notBefore (utc)', + tagClass: asn1$4.Class.UNIVERSAL, + type: asn1$4.Type.UTCTIME, + constructed: false, + optional: true, + capture: 'certValidity1UTCTime' + }, { + // notBefore (Time) (generalized time case) + name: 'Certificate.TBSCertificate.validity.notBefore (generalized)', + tagClass: asn1$4.Class.UNIVERSAL, + type: asn1$4.Type.GENERALIZEDTIME, + constructed: false, + optional: true, + capture: 'certValidity2GeneralizedTime' + }, { + // notAfter (Time) (only UTC time is supported) + name: 'Certificate.TBSCertificate.validity.notAfter (utc)', + tagClass: asn1$4.Class.UNIVERSAL, + type: asn1$4.Type.UTCTIME, + constructed: false, + optional: true, + capture: 'certValidity3UTCTime' + }, { + // notAfter (Time) (only UTC time is supported) + name: 'Certificate.TBSCertificate.validity.notAfter (generalized)', + tagClass: asn1$4.Class.UNIVERSAL, + type: asn1$4.Type.GENERALIZEDTIME, + constructed: false, + optional: true, + capture: 'certValidity4GeneralizedTime' + }] + }, { + // Name (subject) (RDNSequence) + name: 'Certificate.TBSCertificate.subject', + tagClass: asn1$4.Class.UNIVERSAL, + type: asn1$4.Type.SEQUENCE, + constructed: true, + captureAsn1: 'certSubject' + }, + // SubjectPublicKeyInfo + publicKeyValidator$1, + { + // issuerUniqueID (optional) + name: 'Certificate.TBSCertificate.issuerUniqueID', + tagClass: asn1$4.Class.CONTEXT_SPECIFIC, + type: 1, + constructed: true, + optional: true, + value: [{ + name: 'Certificate.TBSCertificate.issuerUniqueID.id', + tagClass: asn1$4.Class.UNIVERSAL, + type: asn1$4.Type.BITSTRING, + constructed: false, + // TODO: support arbitrary bit length ids + captureBitStringValue: 'certIssuerUniqueId' + }] + }, { + // subjectUniqueID (optional) + name: 'Certificate.TBSCertificate.subjectUniqueID', + tagClass: asn1$4.Class.CONTEXT_SPECIFIC, + type: 2, + constructed: true, + optional: true, + value: [{ + name: 'Certificate.TBSCertificate.subjectUniqueID.id', + tagClass: asn1$4.Class.UNIVERSAL, + type: asn1$4.Type.BITSTRING, + constructed: false, + // TODO: support arbitrary bit length ids + captureBitStringValue: 'certSubjectUniqueId' + }] + }, { + // Extensions (optional) + name: 'Certificate.TBSCertificate.extensions', + tagClass: asn1$4.Class.CONTEXT_SPECIFIC, + type: 3, + constructed: true, + captureAsn1: 'certExtensions', + optional: true + }] + }, { + // AlgorithmIdentifier (signature algorithm) + name: 'Certificate.signatureAlgorithm', + tagClass: asn1$4.Class.UNIVERSAL, + type: asn1$4.Type.SEQUENCE, + constructed: true, + value: [{ + // algorithm + name: 'Certificate.signatureAlgorithm.algorithm', + tagClass: asn1$4.Class.UNIVERSAL, + type: asn1$4.Type.OID, + constructed: false, + capture: 'certSignatureOid' + }, { + name: 'Certificate.TBSCertificate.signature.parameters', + tagClass: asn1$4.Class.UNIVERSAL, + optional: true, + captureAsn1: 'certSignatureParams' + }] + }, { + // SignatureValue + name: 'Certificate.signatureValue', + tagClass: asn1$4.Class.UNIVERSAL, + type: asn1$4.Type.BITSTRING, + constructed: false, + captureBitStringValue: 'certSignature' + }] +}; + +var rsassaPssParameterValidator = { + name: 'rsapss', + tagClass: asn1$4.Class.UNIVERSAL, + type: asn1$4.Type.SEQUENCE, + constructed: true, + value: [{ + name: 'rsapss.hashAlgorithm', + tagClass: asn1$4.Class.CONTEXT_SPECIFIC, + type: 0, + constructed: true, + value: [{ + name: 'rsapss.hashAlgorithm.AlgorithmIdentifier', + tagClass: asn1$4.Class.UNIVERSAL, + type: asn1$4.Class.SEQUENCE, + constructed: true, + optional: true, + value: [{ + name: 'rsapss.hashAlgorithm.AlgorithmIdentifier.algorithm', + tagClass: asn1$4.Class.UNIVERSAL, + type: asn1$4.Type.OID, + constructed: false, + capture: 'hashOid' + /* parameter block omitted, for SHA1 NULL anyhow. */ + }] + }] + }, { + name: 'rsapss.maskGenAlgorithm', + tagClass: asn1$4.Class.CONTEXT_SPECIFIC, + type: 1, + constructed: true, + value: [{ + name: 'rsapss.maskGenAlgorithm.AlgorithmIdentifier', + tagClass: asn1$4.Class.UNIVERSAL, + type: asn1$4.Class.SEQUENCE, + constructed: true, + optional: true, + value: [{ + name: 'rsapss.maskGenAlgorithm.AlgorithmIdentifier.algorithm', + tagClass: asn1$4.Class.UNIVERSAL, + type: asn1$4.Type.OID, + constructed: false, + capture: 'maskGenOid' + }, { + name: 'rsapss.maskGenAlgorithm.AlgorithmIdentifier.params', + tagClass: asn1$4.Class.UNIVERSAL, + type: asn1$4.Type.SEQUENCE, + constructed: true, + value: [{ + name: 'rsapss.maskGenAlgorithm.AlgorithmIdentifier.params.algorithm', + tagClass: asn1$4.Class.UNIVERSAL, + type: asn1$4.Type.OID, + constructed: false, + capture: 'maskGenHashOid' + /* parameter block omitted, for SHA1 NULL anyhow. */ + }] + }] + }] + }, { + name: 'rsapss.saltLength', + tagClass: asn1$4.Class.CONTEXT_SPECIFIC, + type: 2, + optional: true, + value: [{ + name: 'rsapss.saltLength.saltLength', + tagClass: asn1$4.Class.UNIVERSAL, + type: asn1$4.Class.INTEGER, + constructed: false, + capture: 'saltLength' + }] + }, { + name: 'rsapss.trailerField', + tagClass: asn1$4.Class.CONTEXT_SPECIFIC, + type: 3, + optional: true, + value: [{ + name: 'rsapss.trailer.trailer', + tagClass: asn1$4.Class.UNIVERSAL, + type: asn1$4.Class.INTEGER, + constructed: false, + capture: 'trailer' + }] + }] +}; + +// validator for a CertificationRequestInfo structure +var certificationRequestInfoValidator = { + name: 'CertificationRequestInfo', + tagClass: asn1$4.Class.UNIVERSAL, + type: asn1$4.Type.SEQUENCE, + constructed: true, + captureAsn1: 'certificationRequestInfo', + value: [{ + name: 'CertificationRequestInfo.integer', + tagClass: asn1$4.Class.UNIVERSAL, + type: asn1$4.Type.INTEGER, + constructed: false, + capture: 'certificationRequestInfoVersion' + }, { + // Name (subject) (RDNSequence) + name: 'CertificationRequestInfo.subject', + tagClass: asn1$4.Class.UNIVERSAL, + type: asn1$4.Type.SEQUENCE, + constructed: true, + captureAsn1: 'certificationRequestInfoSubject' + }, + // SubjectPublicKeyInfo + publicKeyValidator$1, + { + name: 'CertificationRequestInfo.attributes', + tagClass: asn1$4.Class.CONTEXT_SPECIFIC, + type: 0, + constructed: true, + optional: true, + capture: 'certificationRequestInfoAttributes', + value: [{ + name: 'CertificationRequestInfo.attributes', + tagClass: asn1$4.Class.UNIVERSAL, + type: asn1$4.Type.SEQUENCE, + constructed: true, + value: [{ + name: 'CertificationRequestInfo.attributes.type', + tagClass: asn1$4.Class.UNIVERSAL, + type: asn1$4.Type.OID, + constructed: false + }, { + name: 'CertificationRequestInfo.attributes.value', + tagClass: asn1$4.Class.UNIVERSAL, + type: asn1$4.Type.SET, + constructed: true + }] + }] + }] +}; + +// validator for a CertificationRequest structure +var certificationRequestValidator = { + name: 'CertificationRequest', + tagClass: asn1$4.Class.UNIVERSAL, + type: asn1$4.Type.SEQUENCE, + constructed: true, + captureAsn1: 'csr', + value: [ + certificationRequestInfoValidator, { + // AlgorithmIdentifier (signature algorithm) + name: 'CertificationRequest.signatureAlgorithm', + tagClass: asn1$4.Class.UNIVERSAL, + type: asn1$4.Type.SEQUENCE, + constructed: true, + value: [{ + // algorithm + name: 'CertificationRequest.signatureAlgorithm.algorithm', + tagClass: asn1$4.Class.UNIVERSAL, + type: asn1$4.Type.OID, + constructed: false, + capture: 'csrSignatureOid' + }, { + name: 'CertificationRequest.signatureAlgorithm.parameters', + tagClass: asn1$4.Class.UNIVERSAL, + optional: true, + captureAsn1: 'csrSignatureParams' + }] + }, { + // signature + name: 'CertificationRequest.signature', + tagClass: asn1$4.Class.UNIVERSAL, + type: asn1$4.Type.BITSTRING, + constructed: false, + captureBitStringValue: 'csrSignature' + } + ] +}; + +/** + * Converts an RDNSequence of ASN.1 DER-encoded RelativeDistinguishedName + * sets into an array with objects that have type and value properties. + * + * @param rdn the RDNSequence to convert. + * @param md a message digest to append type and value to if provided. + */ +pki$2.RDNAttributesAsArray = function(rdn, md) { + var rval = []; + + // each value in 'rdn' in is a SET of RelativeDistinguishedName + var set, attr, obj; + for(var si = 0; si < rdn.value.length; ++si) { + // get the RelativeDistinguishedName set + set = rdn.value[si]; + + // each value in the SET is an AttributeTypeAndValue sequence + // containing first a type (an OID) and second a value (defined by + // the OID) + for(var i = 0; i < set.value.length; ++i) { + obj = {}; + attr = set.value[i]; + obj.type = asn1$4.derToOid(attr.value[0].value); + obj.value = attr.value[1].value; + obj.valueTagClass = attr.value[1].type; + // if the OID is known, get its name and short name + if(obj.type in oids) { + obj.name = oids[obj.type]; + if(obj.name in _shortNames) { + obj.shortName = _shortNames[obj.name]; + } + } + if(md) { + md.update(obj.type); + md.update(obj.value); + } + rval.push(obj); + } + } + + return rval; +}; + +/** + * Converts ASN.1 CRIAttributes into an array with objects that have type and + * value properties. + * + * @param attributes the CRIAttributes to convert. + */ +pki$2.CRIAttributesAsArray = function(attributes) { + var rval = []; + + // each value in 'attributes' in is a SEQUENCE with an OID and a SET + for(var si = 0; si < attributes.length; ++si) { + // get the attribute sequence + var seq = attributes[si]; + + // each value in the SEQUENCE containing first a type (an OID) and + // second a set of values (defined by the OID) + var type = asn1$4.derToOid(seq.value[0].value); + var values = seq.value[1].value; + for(var vi = 0; vi < values.length; ++vi) { + var obj = {}; + obj.type = type; + obj.value = values[vi].value; + obj.valueTagClass = values[vi].type; + // if the OID is known, get its name and short name + if(obj.type in oids) { + obj.name = oids[obj.type]; + if(obj.name in _shortNames) { + obj.shortName = _shortNames[obj.name]; + } + } + // parse extensions + if(obj.type === oids.extensionRequest) { + obj.extensions = []; + for(var ei = 0; ei < obj.value.length; ++ei) { + obj.extensions.push(pki$2.certificateExtensionFromAsn1(obj.value[ei])); + } + } + rval.push(obj); + } + } + + return rval; +}; + +/** + * Gets an issuer or subject attribute from its name, type, or short name. + * + * @param obj the issuer or subject object. + * @param options a short name string or an object with: + * shortName the short name for the attribute. + * name the name for the attribute. + * type the type for the attribute. + * + * @return the attribute. + */ +function _getAttribute(obj, options) { + if(typeof options === 'string') { + options = {shortName: options}; + } + + var rval = null; + var attr; + for(var i = 0; rval === null && i < obj.attributes.length; ++i) { + attr = obj.attributes[i]; + if(options.type && options.type === attr.type) { + rval = attr; + } else if(options.name && options.name === attr.name) { + rval = attr; + } else if(options.shortName && options.shortName === attr.shortName) { + rval = attr; + } + } + return rval; +} + +/** + * Converts signature parameters from ASN.1 structure. + * + * Currently only RSASSA-PSS supported. The PKCS#1 v1.5 signature scheme had + * no parameters. + * + * RSASSA-PSS-params ::= SEQUENCE { + * hashAlgorithm [0] HashAlgorithm DEFAULT + * sha1Identifier, + * maskGenAlgorithm [1] MaskGenAlgorithm DEFAULT + * mgf1SHA1Identifier, + * saltLength [2] INTEGER DEFAULT 20, + * trailerField [3] INTEGER DEFAULT 1 + * } + * + * HashAlgorithm ::= AlgorithmIdentifier + * + * MaskGenAlgorithm ::= AlgorithmIdentifier + * + * AlgorithmIdentifer ::= SEQUENCE { + * algorithm OBJECT IDENTIFIER, + * parameters ANY DEFINED BY algorithm OPTIONAL + * } + * + * @param oid The OID specifying the signature algorithm + * @param obj The ASN.1 structure holding the parameters + * @param fillDefaults Whether to use return default values where omitted + * @return signature parameter object + */ +var _readSignatureParameters = function(oid, obj, fillDefaults) { + var params = {}; + + if(oid !== oids['RSASSA-PSS']) { + return params; + } + + if(fillDefaults) { + params = { + hash: { + algorithmOid: oids['sha1'] + }, + mgf: { + algorithmOid: oids['mgf1'], + hash: { + algorithmOid: oids['sha1'] + } + }, + saltLength: 20 + }; + } + + var capture = {}; + var errors = []; + if(!asn1$4.validate(obj, rsassaPssParameterValidator, capture, errors)) { + var error = new Error('Cannot read RSASSA-PSS parameter block.'); + error.errors = errors; + throw error; + } + + if(capture.hashOid !== undefined) { + params.hash = params.hash || {}; + params.hash.algorithmOid = asn1$4.derToOid(capture.hashOid); + } + + if(capture.maskGenOid !== undefined) { + params.mgf = params.mgf || {}; + params.mgf.algorithmOid = asn1$4.derToOid(capture.maskGenOid); + params.mgf.hash = params.mgf.hash || {}; + params.mgf.hash.algorithmOid = asn1$4.derToOid(capture.maskGenHashOid); + } + + if(capture.saltLength !== undefined) { + params.saltLength = capture.saltLength.charCodeAt(0); + } + + return params; +}; + +/** + * Create signature digest for OID. + * + * @param options + * signatureOid: the OID specifying the signature algorithm. + * type: a human readable type for error messages + * @return a created md instance. throws if unknown oid. + */ +var _createSignatureDigest = function(options) { + switch(oids[options.signatureOid]) { + case 'sha1WithRSAEncryption': + // deprecated alias + case 'sha1WithRSASignature': + return forge$c.md.sha1.create(); + case 'md5WithRSAEncryption': + return forge$c.md.md5.create(); + case 'sha256WithRSAEncryption': + return forge$c.md.sha256.create(); + case 'sha384WithRSAEncryption': + return forge$c.md.sha384.create(); + case 'sha512WithRSAEncryption': + return forge$c.md.sha512.create(); + case 'RSASSA-PSS': + return forge$c.md.sha256.create(); + default: + var error = new Error( + 'Could not compute ' + options.type + ' digest. ' + + 'Unknown signature OID.'); + error.signatureOid = options.signatureOid; + throw error; + } +}; + +/** + * Verify signature on certificate or CSR. + * + * @param options: + * certificate the certificate or CSR to verify. + * md the signature digest. + * signature the signature + * @return a created md instance. throws if unknown oid. + */ +var _verifySignature = function(options) { + var cert = options.certificate; + var scheme; + + switch(cert.signatureOid) { + case oids.sha1WithRSAEncryption: + // deprecated alias + case oids.sha1WithRSASignature: + /* use PKCS#1 v1.5 padding scheme */ + break; + case oids['RSASSA-PSS']: + var hash, mgf; + + /* initialize mgf */ + hash = oids[cert.signatureParameters.mgf.hash.algorithmOid]; + if(hash === undefined || forge$c.md[hash] === undefined) { + var error = new Error('Unsupported MGF hash function.'); + error.oid = cert.signatureParameters.mgf.hash.algorithmOid; + error.name = hash; + throw error; + } + + mgf = oids[cert.signatureParameters.mgf.algorithmOid]; + if(mgf === undefined || forge$c.mgf[mgf] === undefined) { + var error = new Error('Unsupported MGF function.'); + error.oid = cert.signatureParameters.mgf.algorithmOid; + error.name = mgf; + throw error; + } + + mgf = forge$c.mgf[mgf].create(forge$c.md[hash].create()); + + /* initialize hash function */ + hash = oids[cert.signatureParameters.hash.algorithmOid]; + if(hash === undefined || forge$c.md[hash] === undefined) { + var error = new Error('Unsupported RSASSA-PSS hash function.'); + error.oid = cert.signatureParameters.hash.algorithmOid; + error.name = hash; + throw error; + } + + scheme = forge$c.pss.create( + forge$c.md[hash].create(), mgf, cert.signatureParameters.saltLength + ); + break; + } + + // verify signature on cert using public key + return cert.publicKey.verify( + options.md.digest().getBytes(), options.signature, scheme + ); +}; + +/** + * Converts an X.509 certificate from PEM format. + * + * Note: If the certificate is to be verified then compute hash should + * be set to true. This will scan the TBSCertificate part of the ASN.1 + * object while it is converted so it doesn't need to be converted back + * to ASN.1-DER-encoding later. + * + * @param pem the PEM-formatted certificate. + * @param computeHash true to compute the hash for verification. + * @param strict true to be strict when checking ASN.1 value lengths, false to + * allow truncated values (default: true). + * + * @return the certificate. + */ +pki$2.certificateFromPem = function(pem, computeHash, strict) { + var msg = forge$c.pem.decode(pem)[0]; + + if(msg.type !== 'CERTIFICATE' && + msg.type !== 'X509 CERTIFICATE' && + msg.type !== 'TRUSTED CERTIFICATE') { + var error = new Error( + 'Could not convert certificate from PEM; PEM header type ' + + 'is not "CERTIFICATE", "X509 CERTIFICATE", or "TRUSTED CERTIFICATE".'); + error.headerType = msg.type; + throw error; + } + if(msg.procType && msg.procType.type === 'ENCRYPTED') { + throw new Error( + 'Could not convert certificate from PEM; PEM is encrypted.'); + } + + // convert DER to ASN.1 object + var obj = asn1$4.fromDer(msg.body, strict); + + return pki$2.certificateFromAsn1(obj, computeHash); +}; + +/** + * Converts an X.509 certificate to PEM format. + * + * @param cert the certificate. + * @param maxline the maximum characters per line, defaults to 64. + * + * @return the PEM-formatted certificate. + */ +pki$2.certificateToPem = function(cert, maxline) { + // convert to ASN.1, then DER, then PEM-encode + var msg = { + type: 'CERTIFICATE', + body: asn1$4.toDer(pki$2.certificateToAsn1(cert)).getBytes() + }; + return forge$c.pem.encode(msg, {maxline: maxline}); +}; + +/** + * Converts an RSA public key from PEM format. + * + * @param pem the PEM-formatted public key. + * + * @return the public key. + */ +pki$2.publicKeyFromPem = function(pem) { + var msg = forge$c.pem.decode(pem)[0]; + + if(msg.type !== 'PUBLIC KEY' && msg.type !== 'RSA PUBLIC KEY') { + var error = new Error('Could not convert public key from PEM; PEM header ' + + 'type is not "PUBLIC KEY" or "RSA PUBLIC KEY".'); + error.headerType = msg.type; + throw error; + } + if(msg.procType && msg.procType.type === 'ENCRYPTED') { + throw new Error('Could not convert public key from PEM; PEM is encrypted.'); + } + + // convert DER to ASN.1 object + var obj = asn1$4.fromDer(msg.body); + + return pki$2.publicKeyFromAsn1(obj); +}; + +/** + * Converts an RSA public key to PEM format (using a SubjectPublicKeyInfo). + * + * @param key the public key. + * @param maxline the maximum characters per line, defaults to 64. + * + * @return the PEM-formatted public key. + */ +pki$2.publicKeyToPem = function(key, maxline) { + // convert to ASN.1, then DER, then PEM-encode + var msg = { + type: 'PUBLIC KEY', + body: asn1$4.toDer(pki$2.publicKeyToAsn1(key)).getBytes() + }; + return forge$c.pem.encode(msg, {maxline: maxline}); +}; + +/** + * Converts an RSA public key to PEM format (using an RSAPublicKey). + * + * @param key the public key. + * @param maxline the maximum characters per line, defaults to 64. + * + * @return the PEM-formatted public key. + */ +pki$2.publicKeyToRSAPublicKeyPem = function(key, maxline) { + // convert to ASN.1, then DER, then PEM-encode + var msg = { + type: 'RSA PUBLIC KEY', + body: asn1$4.toDer(pki$2.publicKeyToRSAPublicKey(key)).getBytes() + }; + return forge$c.pem.encode(msg, {maxline: maxline}); +}; + +/** + * Gets a fingerprint for the given public key. + * + * @param options the options to use. + * [md] the message digest object to use (defaults to forge.md.sha1). + * [type] the type of fingerprint, such as 'RSAPublicKey', + * 'SubjectPublicKeyInfo' (defaults to 'RSAPublicKey'). + * [encoding] an alternative output encoding, such as 'hex' + * (defaults to none, outputs a byte buffer). + * [delimiter] the delimiter to use between bytes for 'hex' encoded + * output, eg: ':' (defaults to none). + * + * @return the fingerprint as a byte buffer or other encoding based on options. + */ +pki$2.getPublicKeyFingerprint = function(key, options) { + options = options || {}; + var md = options.md || forge$c.md.sha1.create(); + var type = options.type || 'RSAPublicKey'; + + var bytes; + switch(type) { + case 'RSAPublicKey': + bytes = asn1$4.toDer(pki$2.publicKeyToRSAPublicKey(key)).getBytes(); + break; + case 'SubjectPublicKeyInfo': + bytes = asn1$4.toDer(pki$2.publicKeyToAsn1(key)).getBytes(); + break; + default: + throw new Error('Unknown fingerprint type "' + options.type + '".'); + } + + // hash public key bytes + md.start(); + md.update(bytes); + var digest = md.digest(); + if(options.encoding === 'hex') { + var hex = digest.toHex(); + if(options.delimiter) { + return hex.match(/.{2}/g).join(options.delimiter); + } + return hex; + } else if(options.encoding === 'binary') { + return digest.getBytes(); + } else if(options.encoding) { + throw new Error('Unknown encoding "' + options.encoding + '".'); + } + return digest; +}; + +/** + * Converts a PKCS#10 certification request (CSR) from PEM format. + * + * Note: If the certification request is to be verified then compute hash + * should be set to true. This will scan the CertificationRequestInfo part of + * the ASN.1 object while it is converted so it doesn't need to be converted + * back to ASN.1-DER-encoding later. + * + * @param pem the PEM-formatted certificate. + * @param computeHash true to compute the hash for verification. + * @param strict true to be strict when checking ASN.1 value lengths, false to + * allow truncated values (default: true). + * + * @return the certification request (CSR). + */ +pki$2.certificationRequestFromPem = function(pem, computeHash, strict) { + var msg = forge$c.pem.decode(pem)[0]; + + if(msg.type !== 'CERTIFICATE REQUEST') { + var error = new Error('Could not convert certification request from PEM; ' + + 'PEM header type is not "CERTIFICATE REQUEST".'); + error.headerType = msg.type; + throw error; + } + if(msg.procType && msg.procType.type === 'ENCRYPTED') { + throw new Error('Could not convert certification request from PEM; ' + + 'PEM is encrypted.'); + } + + // convert DER to ASN.1 object + var obj = asn1$4.fromDer(msg.body, strict); + + return pki$2.certificationRequestFromAsn1(obj, computeHash); +}; + +/** + * Converts a PKCS#10 certification request (CSR) to PEM format. + * + * @param csr the certification request. + * @param maxline the maximum characters per line, defaults to 64. + * + * @return the PEM-formatted certification request. + */ +pki$2.certificationRequestToPem = function(csr, maxline) { + // convert to ASN.1, then DER, then PEM-encode + var msg = { + type: 'CERTIFICATE REQUEST', + body: asn1$4.toDer(pki$2.certificationRequestToAsn1(csr)).getBytes() + }; + return forge$c.pem.encode(msg, {maxline: maxline}); +}; + +/** + * Creates an empty X.509v3 RSA certificate. + * + * @return the certificate. + */ +pki$2.createCertificate = function() { + var cert = {}; + cert.version = 0x02; + cert.serialNumber = '00'; + cert.signatureOid = null; + cert.signature = null; + cert.siginfo = {}; + cert.siginfo.algorithmOid = null; + cert.validity = {}; + cert.validity.notBefore = new Date(); + cert.validity.notAfter = new Date(); + + cert.issuer = {}; + cert.issuer.getField = function(sn) { + return _getAttribute(cert.issuer, sn); + }; + cert.issuer.addField = function(attr) { + _fillMissingFields([attr]); + cert.issuer.attributes.push(attr); + }; + cert.issuer.attributes = []; + cert.issuer.hash = null; + + cert.subject = {}; + cert.subject.getField = function(sn) { + return _getAttribute(cert.subject, sn); + }; + cert.subject.addField = function(attr) { + _fillMissingFields([attr]); + cert.subject.attributes.push(attr); + }; + cert.subject.attributes = []; + cert.subject.hash = null; + + cert.extensions = []; + cert.publicKey = null; + cert.md = null; + + /** + * Sets the subject of this certificate. + * + * @param attrs the array of subject attributes to use. + * @param uniqueId an optional a unique ID to use. + */ + cert.setSubject = function(attrs, uniqueId) { + // set new attributes, clear hash + _fillMissingFields(attrs); + cert.subject.attributes = attrs; + delete cert.subject.uniqueId; + if(uniqueId) { + // TODO: support arbitrary bit length ids + cert.subject.uniqueId = uniqueId; + } + cert.subject.hash = null; + }; + + /** + * Sets the issuer of this certificate. + * + * @param attrs the array of issuer attributes to use. + * @param uniqueId an optional a unique ID to use. + */ + cert.setIssuer = function(attrs, uniqueId) { + // set new attributes, clear hash + _fillMissingFields(attrs); + cert.issuer.attributes = attrs; + delete cert.issuer.uniqueId; + if(uniqueId) { + // TODO: support arbitrary bit length ids + cert.issuer.uniqueId = uniqueId; + } + cert.issuer.hash = null; + }; + + /** + * Sets the extensions of this certificate. + * + * @param exts the array of extensions to use. + */ + cert.setExtensions = function(exts) { + for(var i = 0; i < exts.length; ++i) { + _fillMissingExtensionFields(exts[i], {cert: cert}); + } + // set new extensions + cert.extensions = exts; + }; + + /** + * Gets an extension by its name or id. + * + * @param options the name to use or an object with: + * name the name to use. + * id the id to use. + * + * @return the extension or null if not found. + */ + cert.getExtension = function(options) { + if(typeof options === 'string') { + options = {name: options}; + } + + var rval = null; + var ext; + for(var i = 0; rval === null && i < cert.extensions.length; ++i) { + ext = cert.extensions[i]; + if(options.id && ext.id === options.id) { + rval = ext; + } else if(options.name && ext.name === options.name) { + rval = ext; + } + } + return rval; + }; + + /** + * Signs this certificate using the given private key. + * + * @param key the private key to sign with. + * @param md the message digest object to use (defaults to forge.md.sha1). + */ + cert.sign = function(key, md) { + // TODO: get signature OID from private key + cert.md = md || forge$c.md.sha1.create(); + var algorithmOid = oids[cert.md.algorithm + 'WithRSAEncryption']; + if(!algorithmOid) { + var error = new Error('Could not compute certificate digest. ' + + 'Unknown message digest algorithm OID.'); + error.algorithm = cert.md.algorithm; + throw error; + } + cert.signatureOid = cert.siginfo.algorithmOid = algorithmOid; + + // get TBSCertificate, convert to DER + cert.tbsCertificate = pki$2.getTBSCertificate(cert); + var bytes = asn1$4.toDer(cert.tbsCertificate); + + // digest and sign + cert.md.update(bytes.getBytes()); + cert.signature = key.sign(cert.md); + }; + + /** + * Attempts verify the signature on the passed certificate using this + * certificate's public key. + * + * @param child the certificate to verify. + * + * @return true if verified, false if not. + */ + cert.verify = function(child) { + var rval = false; + + if(!cert.issued(child)) { + var issuer = child.issuer; + var subject = cert.subject; + var error = new Error( + 'The parent certificate did not issue the given child ' + + 'certificate; the child certificate\'s issuer does not match the ' + + 'parent\'s subject.'); + error.expectedIssuer = subject.attributes; + error.actualIssuer = issuer.attributes; + throw error; + } + + var md = child.md; + if(md === null) { + // create digest for OID signature types + md = _createSignatureDigest({ + signatureOid: child.signatureOid, + type: 'certificate' + }); + + // produce DER formatted TBSCertificate and digest it + var tbsCertificate = child.tbsCertificate || pki$2.getTBSCertificate(child); + var bytes = asn1$4.toDer(tbsCertificate); + md.update(bytes.getBytes()); + } + + if(md !== null) { + rval = _verifySignature({ + certificate: cert, md: md, signature: child.signature + }); + } + + return rval; + }; + + /** + * Returns true if this certificate's issuer matches the passed + * certificate's subject. Note that no signature check is performed. + * + * @param parent the certificate to check. + * + * @return true if this certificate's issuer matches the passed certificate's + * subject. + */ + cert.isIssuer = function(parent) { + var rval = false; + + var i = cert.issuer; + var s = parent.subject; + + // compare hashes if present + if(i.hash && s.hash) { + rval = (i.hash === s.hash); + } else if(i.attributes.length === s.attributes.length) { + // all attributes are the same so issuer matches subject + rval = true; + var iattr, sattr; + for(var n = 0; rval && n < i.attributes.length; ++n) { + iattr = i.attributes[n]; + sattr = s.attributes[n]; + if(iattr.type !== sattr.type || iattr.value !== sattr.value) { + // attribute mismatch + rval = false; + } + } + } + + return rval; + }; + + /** + * Returns true if this certificate's subject matches the issuer of the + * given certificate). Note that not signature check is performed. + * + * @param child the certificate to check. + * + * @return true if this certificate's subject matches the passed + * certificate's issuer. + */ + cert.issued = function(child) { + return child.isIssuer(cert); + }; + + /** + * Generates the subjectKeyIdentifier for this certificate as byte buffer. + * + * @return the subjectKeyIdentifier for this certificate as byte buffer. + */ + cert.generateSubjectKeyIdentifier = function() { + /* See: 4.2.1.2 section of the the RFC3280, keyIdentifier is either: + + (1) The keyIdentifier is composed of the 160-bit SHA-1 hash of the + value of the BIT STRING subjectPublicKey (excluding the tag, + length, and number of unused bits). + + (2) The keyIdentifier is composed of a four bit type field with + the value 0100 followed by the least significant 60 bits of the + SHA-1 hash of the value of the BIT STRING subjectPublicKey + (excluding the tag, length, and number of unused bit string bits). + */ + + // skipping the tag, length, and number of unused bits is the same + // as just using the RSAPublicKey (for RSA keys, which are the + // only ones supported) + return pki$2.getPublicKeyFingerprint(cert.publicKey, {type: 'RSAPublicKey'}); + }; + + /** + * Verifies the subjectKeyIdentifier extension value for this certificate + * against its public key. If no extension is found, false will be + * returned. + * + * @return true if verified, false if not. + */ + cert.verifySubjectKeyIdentifier = function() { + var oid = oids['subjectKeyIdentifier']; + for(var i = 0; i < cert.extensions.length; ++i) { + var ext = cert.extensions[i]; + if(ext.id === oid) { + var ski = cert.generateSubjectKeyIdentifier().getBytes(); + return (forge$c.util.hexToBytes(ext.subjectKeyIdentifier) === ski); + } + } + return false; + }; + + return cert; +}; + +/** + * Converts an X.509v3 RSA certificate from an ASN.1 object. + * + * Note: If the certificate is to be verified then compute hash should + * be set to true. There is currently no implementation for converting + * a certificate back to ASN.1 so the TBSCertificate part of the ASN.1 + * object needs to be scanned before the cert object is created. + * + * @param obj the asn1 representation of an X.509v3 RSA certificate. + * @param computeHash true to compute the hash for verification. + * + * @return the certificate. + */ +pki$2.certificateFromAsn1 = function(obj, computeHash) { + // validate certificate and capture data + var capture = {}; + var errors = []; + if(!asn1$4.validate(obj, x509CertificateValidator, capture, errors)) { + var error = new Error('Cannot read X.509 certificate. ' + + 'ASN.1 object is not an X509v3 Certificate.'); + error.errors = errors; + throw error; + } + + // get oid + var oid = asn1$4.derToOid(capture.publicKeyOid); + if(oid !== pki$2.oids.rsaEncryption) { + throw new Error('Cannot read public key. OID is not RSA.'); + } + + // create certificate + var cert = pki$2.createCertificate(); + cert.version = capture.certVersion ? + capture.certVersion.charCodeAt(0) : 0; + var serial = forge$c.util.createBuffer(capture.certSerialNumber); + cert.serialNumber = serial.toHex(); + cert.signatureOid = forge$c.asn1.derToOid(capture.certSignatureOid); + cert.signatureParameters = _readSignatureParameters( + cert.signatureOid, capture.certSignatureParams, true); + cert.siginfo.algorithmOid = forge$c.asn1.derToOid(capture.certinfoSignatureOid); + cert.siginfo.parameters = _readSignatureParameters(cert.siginfo.algorithmOid, + capture.certinfoSignatureParams, false); + cert.signature = capture.certSignature; + + var validity = []; + if(capture.certValidity1UTCTime !== undefined) { + validity.push(asn1$4.utcTimeToDate(capture.certValidity1UTCTime)); + } + if(capture.certValidity2GeneralizedTime !== undefined) { + validity.push(asn1$4.generalizedTimeToDate( + capture.certValidity2GeneralizedTime)); + } + if(capture.certValidity3UTCTime !== undefined) { + validity.push(asn1$4.utcTimeToDate(capture.certValidity3UTCTime)); + } + if(capture.certValidity4GeneralizedTime !== undefined) { + validity.push(asn1$4.generalizedTimeToDate( + capture.certValidity4GeneralizedTime)); + } + if(validity.length > 2) { + throw new Error('Cannot read notBefore/notAfter validity times; more ' + + 'than two times were provided in the certificate.'); + } + if(validity.length < 2) { + throw new Error('Cannot read notBefore/notAfter validity times; they ' + + 'were not provided as either UTCTime or GeneralizedTime.'); + } + cert.validity.notBefore = validity[0]; + cert.validity.notAfter = validity[1]; + + // keep TBSCertificate to preserve signature when exporting + cert.tbsCertificate = capture.tbsCertificate; + + if(computeHash) { + // create digest for OID signature type + cert.md = _createSignatureDigest({ + signatureOid: cert.signatureOid, + type: 'certificate' + }); + + // produce DER formatted TBSCertificate and digest it + var bytes = asn1$4.toDer(cert.tbsCertificate); + cert.md.update(bytes.getBytes()); + } + + // handle issuer, build issuer message digest + var imd = forge$c.md.sha1.create(); + var ibytes = asn1$4.toDer(capture.certIssuer); + imd.update(ibytes.getBytes()); + cert.issuer.getField = function(sn) { + return _getAttribute(cert.issuer, sn); + }; + cert.issuer.addField = function(attr) { + _fillMissingFields([attr]); + cert.issuer.attributes.push(attr); + }; + cert.issuer.attributes = pki$2.RDNAttributesAsArray(capture.certIssuer); + if(capture.certIssuerUniqueId) { + cert.issuer.uniqueId = capture.certIssuerUniqueId; + } + cert.issuer.hash = imd.digest().toHex(); + + // handle subject, build subject message digest + var smd = forge$c.md.sha1.create(); + var sbytes = asn1$4.toDer(capture.certSubject); + smd.update(sbytes.getBytes()); + cert.subject.getField = function(sn) { + return _getAttribute(cert.subject, sn); + }; + cert.subject.addField = function(attr) { + _fillMissingFields([attr]); + cert.subject.attributes.push(attr); + }; + cert.subject.attributes = pki$2.RDNAttributesAsArray(capture.certSubject); + if(capture.certSubjectUniqueId) { + cert.subject.uniqueId = capture.certSubjectUniqueId; + } + cert.subject.hash = smd.digest().toHex(); + + // handle extensions + if(capture.certExtensions) { + cert.extensions = pki$2.certificateExtensionsFromAsn1(capture.certExtensions); + } else { + cert.extensions = []; + } + + // convert RSA public key from ASN.1 + cert.publicKey = pki$2.publicKeyFromAsn1(capture.subjectPublicKeyInfo); + + return cert; +}; + +/** + * Converts an ASN.1 extensions object (with extension sequences as its + * values) into an array of extension objects with types and values. + * + * Supported extensions: + * + * id-ce-keyUsage OBJECT IDENTIFIER ::= { id-ce 15 } + * KeyUsage ::= BIT STRING { + * digitalSignature (0), + * nonRepudiation (1), + * keyEncipherment (2), + * dataEncipherment (3), + * keyAgreement (4), + * keyCertSign (5), + * cRLSign (6), + * encipherOnly (7), + * decipherOnly (8) + * } + * + * id-ce-basicConstraints OBJECT IDENTIFIER ::= { id-ce 19 } + * BasicConstraints ::= SEQUENCE { + * cA BOOLEAN DEFAULT FALSE, + * pathLenConstraint INTEGER (0..MAX) OPTIONAL + * } + * + * subjectAltName EXTENSION ::= { + * SYNTAX GeneralNames + * IDENTIFIED BY id-ce-subjectAltName + * } + * + * GeneralNames ::= SEQUENCE SIZE (1..MAX) OF GeneralName + * + * GeneralName ::= CHOICE { + * otherName [0] INSTANCE OF OTHER-NAME, + * rfc822Name [1] IA5String, + * dNSName [2] IA5String, + * x400Address [3] ORAddress, + * directoryName [4] Name, + * ediPartyName [5] EDIPartyName, + * uniformResourceIdentifier [6] IA5String, + * IPAddress [7] OCTET STRING, + * registeredID [8] OBJECT IDENTIFIER + * } + * + * OTHER-NAME ::= TYPE-IDENTIFIER + * + * EDIPartyName ::= SEQUENCE { + * nameAssigner [0] DirectoryString {ub-name} OPTIONAL, + * partyName [1] DirectoryString {ub-name} + * } + * + * @param exts the extensions ASN.1 with extension sequences to parse. + * + * @return the array. + */ +pki$2.certificateExtensionsFromAsn1 = function(exts) { + var rval = []; + for(var i = 0; i < exts.value.length; ++i) { + // get extension sequence + var extseq = exts.value[i]; + for(var ei = 0; ei < extseq.value.length; ++ei) { + rval.push(pki$2.certificateExtensionFromAsn1(extseq.value[ei])); + } + } + + return rval; +}; + +/** + * Parses a single certificate extension from ASN.1. + * + * @param ext the extension in ASN.1 format. + * + * @return the parsed extension as an object. + */ +pki$2.certificateExtensionFromAsn1 = function(ext) { + // an extension has: + // [0] extnID OBJECT IDENTIFIER + // [1] critical BOOLEAN DEFAULT FALSE + // [2] extnValue OCTET STRING + var e = {}; + e.id = asn1$4.derToOid(ext.value[0].value); + e.critical = false; + if(ext.value[1].type === asn1$4.Type.BOOLEAN) { + e.critical = (ext.value[1].value.charCodeAt(0) !== 0x00); + e.value = ext.value[2].value; + } else { + e.value = ext.value[1].value; + } + // if the oid is known, get its name + if(e.id in oids) { + e.name = oids[e.id]; + + // handle key usage + if(e.name === 'keyUsage') { + // get value as BIT STRING + var ev = asn1$4.fromDer(e.value); + var b2 = 0x00; + var b3 = 0x00; + if(ev.value.length > 1) { + // skip first byte, just indicates unused bits which + // will be padded with 0s anyway + // get bytes with flag bits + b2 = ev.value.charCodeAt(1); + b3 = ev.value.length > 2 ? ev.value.charCodeAt(2) : 0; + } + // set flags + e.digitalSignature = (b2 & 0x80) === 0x80; + e.nonRepudiation = (b2 & 0x40) === 0x40; + e.keyEncipherment = (b2 & 0x20) === 0x20; + e.dataEncipherment = (b2 & 0x10) === 0x10; + e.keyAgreement = (b2 & 0x08) === 0x08; + e.keyCertSign = (b2 & 0x04) === 0x04; + e.cRLSign = (b2 & 0x02) === 0x02; + e.encipherOnly = (b2 & 0x01) === 0x01; + e.decipherOnly = (b3 & 0x80) === 0x80; + } else if(e.name === 'basicConstraints') { + // handle basic constraints + // get value as SEQUENCE + var ev = asn1$4.fromDer(e.value); + // get cA BOOLEAN flag (defaults to false) + if(ev.value.length > 0 && ev.value[0].type === asn1$4.Type.BOOLEAN) { + e.cA = (ev.value[0].value.charCodeAt(0) !== 0x00); + } else { + e.cA = false; + } + // get path length constraint + var value = null; + if(ev.value.length > 0 && ev.value[0].type === asn1$4.Type.INTEGER) { + value = ev.value[0].value; + } else if(ev.value.length > 1) { + value = ev.value[1].value; + } + if(value !== null) { + e.pathLenConstraint = asn1$4.derToInteger(value); + } + } else if(e.name === 'extKeyUsage') { + // handle extKeyUsage + // value is a SEQUENCE of OIDs + var ev = asn1$4.fromDer(e.value); + for(var vi = 0; vi < ev.value.length; ++vi) { + var oid = asn1$4.derToOid(ev.value[vi].value); + if(oid in oids) { + e[oids[oid]] = true; + } else { + e[oid] = true; + } + } + } else if(e.name === 'nsCertType') { + // handle nsCertType + // get value as BIT STRING + var ev = asn1$4.fromDer(e.value); + var b2 = 0x00; + if(ev.value.length > 1) { + // skip first byte, just indicates unused bits which + // will be padded with 0s anyway + // get bytes with flag bits + b2 = ev.value.charCodeAt(1); + } + // set flags + e.client = (b2 & 0x80) === 0x80; + e.server = (b2 & 0x40) === 0x40; + e.email = (b2 & 0x20) === 0x20; + e.objsign = (b2 & 0x10) === 0x10; + e.reserved = (b2 & 0x08) === 0x08; + e.sslCA = (b2 & 0x04) === 0x04; + e.emailCA = (b2 & 0x02) === 0x02; + e.objCA = (b2 & 0x01) === 0x01; + } else if( + e.name === 'subjectAltName' || + e.name === 'issuerAltName') { + // handle subjectAltName/issuerAltName + e.altNames = []; + + // ev is a SYNTAX SEQUENCE + var gn; + var ev = asn1$4.fromDer(e.value); + for(var n = 0; n < ev.value.length; ++n) { + // get GeneralName + gn = ev.value[n]; + + var altName = { + type: gn.type, + value: gn.value + }; + e.altNames.push(altName); + + // Note: Support for types 1,2,6,7,8 + switch(gn.type) { + // rfc822Name + case 1: + // dNSName + case 2: + // uniformResourceIdentifier (URI) + case 6: + break; + // IPAddress + case 7: + // convert to IPv4/IPv6 string representation + altName.ip = forge$c.util.bytesToIP(gn.value); + break; + // registeredID + case 8: + altName.oid = asn1$4.derToOid(gn.value); + break; + // unsupported + } + } + } else if(e.name === 'subjectKeyIdentifier') { + // value is an OCTETSTRING w/the hash of the key-type specific + // public key structure (eg: RSAPublicKey) + var ev = asn1$4.fromDer(e.value); + e.subjectKeyIdentifier = forge$c.util.bytesToHex(ev.value); + } + } + return e; +}; + +/** + * Converts a PKCS#10 certification request (CSR) from an ASN.1 object. + * + * Note: If the certification request is to be verified then compute hash + * should be set to true. There is currently no implementation for converting + * a certificate back to ASN.1 so the CertificationRequestInfo part of the + * ASN.1 object needs to be scanned before the csr object is created. + * + * @param obj the asn1 representation of a PKCS#10 certification request (CSR). + * @param computeHash true to compute the hash for verification. + * + * @return the certification request (CSR). + */ +pki$2.certificationRequestFromAsn1 = function(obj, computeHash) { + // validate certification request and capture data + var capture = {}; + var errors = []; + if(!asn1$4.validate(obj, certificationRequestValidator, capture, errors)) { + var error = new Error('Cannot read PKCS#10 certificate request. ' + + 'ASN.1 object is not a PKCS#10 CertificationRequest.'); + error.errors = errors; + throw error; + } + + // get oid + var oid = asn1$4.derToOid(capture.publicKeyOid); + if(oid !== pki$2.oids.rsaEncryption) { + throw new Error('Cannot read public key. OID is not RSA.'); + } + + // create certification request + var csr = pki$2.createCertificationRequest(); + csr.version = capture.csrVersion ? capture.csrVersion.charCodeAt(0) : 0; + csr.signatureOid = forge$c.asn1.derToOid(capture.csrSignatureOid); + csr.signatureParameters = _readSignatureParameters( + csr.signatureOid, capture.csrSignatureParams, true); + csr.siginfo.algorithmOid = forge$c.asn1.derToOid(capture.csrSignatureOid); + csr.siginfo.parameters = _readSignatureParameters( + csr.siginfo.algorithmOid, capture.csrSignatureParams, false); + csr.signature = capture.csrSignature; + + // keep CertificationRequestInfo to preserve signature when exporting + csr.certificationRequestInfo = capture.certificationRequestInfo; + + if(computeHash) { + // create digest for OID signature type + csr.md = _createSignatureDigest({ + signatureOid: csr.signatureOid, + type: 'certification request' + }); + + // produce DER formatted CertificationRequestInfo and digest it + var bytes = asn1$4.toDer(csr.certificationRequestInfo); + csr.md.update(bytes.getBytes()); + } + + // handle subject, build subject message digest + var smd = forge$c.md.sha1.create(); + csr.subject.getField = function(sn) { + return _getAttribute(csr.subject, sn); + }; + csr.subject.addField = function(attr) { + _fillMissingFields([attr]); + csr.subject.attributes.push(attr); + }; + csr.subject.attributes = pki$2.RDNAttributesAsArray( + capture.certificationRequestInfoSubject, smd); + csr.subject.hash = smd.digest().toHex(); + + // convert RSA public key from ASN.1 + csr.publicKey = pki$2.publicKeyFromAsn1(capture.subjectPublicKeyInfo); + + // convert attributes from ASN.1 + csr.getAttribute = function(sn) { + return _getAttribute(csr, sn); + }; + csr.addAttribute = function(attr) { + _fillMissingFields([attr]); + csr.attributes.push(attr); + }; + csr.attributes = pki$2.CRIAttributesAsArray( + capture.certificationRequestInfoAttributes || []); + + return csr; +}; + +/** + * Creates an empty certification request (a CSR or certificate signing + * request). Once created, its public key and attributes can be set and then + * it can be signed. + * + * @return the empty certification request. + */ +pki$2.createCertificationRequest = function() { + var csr = {}; + csr.version = 0x00; + csr.signatureOid = null; + csr.signature = null; + csr.siginfo = {}; + csr.siginfo.algorithmOid = null; + + csr.subject = {}; + csr.subject.getField = function(sn) { + return _getAttribute(csr.subject, sn); + }; + csr.subject.addField = function(attr) { + _fillMissingFields([attr]); + csr.subject.attributes.push(attr); + }; + csr.subject.attributes = []; + csr.subject.hash = null; + + csr.publicKey = null; + csr.attributes = []; + csr.getAttribute = function(sn) { + return _getAttribute(csr, sn); + }; + csr.addAttribute = function(attr) { + _fillMissingFields([attr]); + csr.attributes.push(attr); + }; + csr.md = null; + + /** + * Sets the subject of this certification request. + * + * @param attrs the array of subject attributes to use. + */ + csr.setSubject = function(attrs) { + // set new attributes + _fillMissingFields(attrs); + csr.subject.attributes = attrs; + csr.subject.hash = null; + }; + + /** + * Sets the attributes of this certification request. + * + * @param attrs the array of attributes to use. + */ + csr.setAttributes = function(attrs) { + // set new attributes + _fillMissingFields(attrs); + csr.attributes = attrs; + }; + + /** + * Signs this certification request using the given private key. + * + * @param key the private key to sign with. + * @param md the message digest object to use (defaults to forge.md.sha1). + */ + csr.sign = function(key, md) { + // TODO: get signature OID from private key + csr.md = md || forge$c.md.sha1.create(); + var algorithmOid = oids[csr.md.algorithm + 'WithRSAEncryption']; + if(!algorithmOid) { + var error = new Error('Could not compute certification request digest. ' + + 'Unknown message digest algorithm OID.'); + error.algorithm = csr.md.algorithm; + throw error; + } + csr.signatureOid = csr.siginfo.algorithmOid = algorithmOid; + + // get CertificationRequestInfo, convert to DER + csr.certificationRequestInfo = pki$2.getCertificationRequestInfo(csr); + var bytes = asn1$4.toDer(csr.certificationRequestInfo); + + // digest and sign + csr.md.update(bytes.getBytes()); + csr.signature = key.sign(csr.md); + }; + + /** + * Attempts verify the signature on the passed certification request using + * its public key. + * + * A CSR that has been exported to a file in PEM format can be verified using + * OpenSSL using this command: + * + * openssl req -in -verify -noout -text + * + * @return true if verified, false if not. + */ + csr.verify = function() { + var rval = false; + + var md = csr.md; + if(md === null) { + md = _createSignatureDigest({ + signatureOid: csr.signatureOid, + type: 'certification request' + }); + + // produce DER formatted CertificationRequestInfo and digest it + var cri = csr.certificationRequestInfo || + pki$2.getCertificationRequestInfo(csr); + var bytes = asn1$4.toDer(cri); + md.update(bytes.getBytes()); + } + + if(md !== null) { + rval = _verifySignature({ + certificate: csr, md: md, signature: csr.signature + }); + } + + return rval; + }; + + return csr; +}; + +/** + * Converts an X.509 subject or issuer to an ASN.1 RDNSequence. + * + * @param obj the subject or issuer (distinguished name). + * + * @return the ASN.1 RDNSequence. + */ +function _dnToAsn1(obj) { + // create an empty RDNSequence + var rval = asn1$4.create( + asn1$4.Class.UNIVERSAL, asn1$4.Type.SEQUENCE, true, []); + + // iterate over attributes + var attr, set; + var attrs = obj.attributes; + for(var i = 0; i < attrs.length; ++i) { + attr = attrs[i]; + var value = attr.value; + + // reuse tag class for attribute value if available + var valueTagClass = asn1$4.Type.PRINTABLESTRING; + if('valueTagClass' in attr) { + valueTagClass = attr.valueTagClass; + + if(valueTagClass === asn1$4.Type.UTF8) { + value = forge$c.util.encodeUtf8(value); + } + // FIXME: handle more encodings + } + + // create a RelativeDistinguishedName set + // each value in the set is an AttributeTypeAndValue first + // containing the type (an OID) and second the value + set = asn1$4.create(asn1$4.Class.UNIVERSAL, asn1$4.Type.SET, true, [ + asn1$4.create(asn1$4.Class.UNIVERSAL, asn1$4.Type.SEQUENCE, true, [ + // AttributeType + asn1$4.create(asn1$4.Class.UNIVERSAL, asn1$4.Type.OID, false, + asn1$4.oidToDer(attr.type).getBytes()), + // AttributeValue + asn1$4.create(asn1$4.Class.UNIVERSAL, valueTagClass, false, value) + ]) + ]); + rval.value.push(set); + } + + return rval; +} + +/** + * Fills in missing fields in attributes. + * + * @param attrs the attributes to fill missing fields in. + */ +function _fillMissingFields(attrs) { + var attr; + for(var i = 0; i < attrs.length; ++i) { + attr = attrs[i]; + + // populate missing name + if(typeof attr.name === 'undefined') { + if(attr.type && attr.type in pki$2.oids) { + attr.name = pki$2.oids[attr.type]; + } else if(attr.shortName && attr.shortName in _shortNames) { + attr.name = pki$2.oids[_shortNames[attr.shortName]]; + } + } + + // populate missing type (OID) + if(typeof attr.type === 'undefined') { + if(attr.name && attr.name in pki$2.oids) { + attr.type = pki$2.oids[attr.name]; + } else { + var error = new Error('Attribute type not specified.'); + error.attribute = attr; + throw error; + } + } + + // populate missing shortname + if(typeof attr.shortName === 'undefined') { + if(attr.name && attr.name in _shortNames) { + attr.shortName = _shortNames[attr.name]; + } + } + + // convert extensions to value + if(attr.type === oids.extensionRequest) { + attr.valueConstructed = true; + attr.valueTagClass = asn1$4.Type.SEQUENCE; + if(!attr.value && attr.extensions) { + attr.value = []; + for(var ei = 0; ei < attr.extensions.length; ++ei) { + attr.value.push(pki$2.certificateExtensionToAsn1( + _fillMissingExtensionFields(attr.extensions[ei]))); + } + } + } + + if(typeof attr.value === 'undefined') { + var error = new Error('Attribute value not specified.'); + error.attribute = attr; + throw error; + } + } +} + +/** + * Fills in missing fields in certificate extensions. + * + * @param e the extension. + * @param [options] the options to use. + * [cert] the certificate the extensions are for. + * + * @return the extension. + */ +function _fillMissingExtensionFields(e, options) { + options = options || {}; + + // populate missing name + if(typeof e.name === 'undefined') { + if(e.id && e.id in pki$2.oids) { + e.name = pki$2.oids[e.id]; + } + } + + // populate missing id + if(typeof e.id === 'undefined') { + if(e.name && e.name in pki$2.oids) { + e.id = pki$2.oids[e.name]; + } else { + var error = new Error('Extension ID not specified.'); + error.extension = e; + throw error; + } + } + + if(typeof e.value !== 'undefined') { + return e; + } + + // handle missing value: + + // value is a BIT STRING + if(e.name === 'keyUsage') { + // build flags + var unused = 0; + var b2 = 0x00; + var b3 = 0x00; + if(e.digitalSignature) { + b2 |= 0x80; + unused = 7; + } + if(e.nonRepudiation) { + b2 |= 0x40; + unused = 6; + } + if(e.keyEncipherment) { + b2 |= 0x20; + unused = 5; + } + if(e.dataEncipherment) { + b2 |= 0x10; + unused = 4; + } + if(e.keyAgreement) { + b2 |= 0x08; + unused = 3; + } + if(e.keyCertSign) { + b2 |= 0x04; + unused = 2; + } + if(e.cRLSign) { + b2 |= 0x02; + unused = 1; + } + if(e.encipherOnly) { + b2 |= 0x01; + unused = 0; + } + if(e.decipherOnly) { + b3 |= 0x80; + unused = 7; + } + + // create bit string + var value = String.fromCharCode(unused); + if(b3 !== 0) { + value += String.fromCharCode(b2) + String.fromCharCode(b3); + } else if(b2 !== 0) { + value += String.fromCharCode(b2); + } + e.value = asn1$4.create( + asn1$4.Class.UNIVERSAL, asn1$4.Type.BITSTRING, false, value); + } else if(e.name === 'basicConstraints') { + // basicConstraints is a SEQUENCE + e.value = asn1$4.create( + asn1$4.Class.UNIVERSAL, asn1$4.Type.SEQUENCE, true, []); + // cA BOOLEAN flag defaults to false + if(e.cA) { + e.value.value.push(asn1$4.create( + asn1$4.Class.UNIVERSAL, asn1$4.Type.BOOLEAN, false, + String.fromCharCode(0xFF))); + } + if('pathLenConstraint' in e) { + e.value.value.push(asn1$4.create( + asn1$4.Class.UNIVERSAL, asn1$4.Type.INTEGER, false, + asn1$4.integerToDer(e.pathLenConstraint).getBytes())); + } + } else if(e.name === 'extKeyUsage') { + // extKeyUsage is a SEQUENCE of OIDs + e.value = asn1$4.create( + asn1$4.Class.UNIVERSAL, asn1$4.Type.SEQUENCE, true, []); + var seq = e.value.value; + for(var key in e) { + if(e[key] !== true) { + continue; + } + // key is name in OID map + if(key in oids) { + seq.push(asn1$4.create(asn1$4.Class.UNIVERSAL, asn1$4.Type.OID, + false, asn1$4.oidToDer(oids[key]).getBytes())); + } else if(key.indexOf('.') !== -1) { + // assume key is an OID + seq.push(asn1$4.create(asn1$4.Class.UNIVERSAL, asn1$4.Type.OID, + false, asn1$4.oidToDer(key).getBytes())); + } + } + } else if(e.name === 'nsCertType') { + // nsCertType is a BIT STRING + // build flags + var unused = 0; + var b2 = 0x00; + + if(e.client) { + b2 |= 0x80; + unused = 7; + } + if(e.server) { + b2 |= 0x40; + unused = 6; + } + if(e.email) { + b2 |= 0x20; + unused = 5; + } + if(e.objsign) { + b2 |= 0x10; + unused = 4; + } + if(e.reserved) { + b2 |= 0x08; + unused = 3; + } + if(e.sslCA) { + b2 |= 0x04; + unused = 2; + } + if(e.emailCA) { + b2 |= 0x02; + unused = 1; + } + if(e.objCA) { + b2 |= 0x01; + unused = 0; + } + + // create bit string + var value = String.fromCharCode(unused); + if(b2 !== 0) { + value += String.fromCharCode(b2); + } + e.value = asn1$4.create( + asn1$4.Class.UNIVERSAL, asn1$4.Type.BITSTRING, false, value); + } else if(e.name === 'subjectAltName' || e.name === 'issuerAltName') { + // SYNTAX SEQUENCE + e.value = asn1$4.create(asn1$4.Class.UNIVERSAL, asn1$4.Type.SEQUENCE, true, []); + + var altName; + for(var n = 0; n < e.altNames.length; ++n) { + altName = e.altNames[n]; + var value = altName.value; + // handle IP + if(altName.type === 7 && altName.ip) { + value = forge$c.util.bytesFromIP(altName.ip); + if(value === null) { + var error = new Error( + 'Extension "ip" value is not a valid IPv4 or IPv6 address.'); + error.extension = e; + throw error; + } + } else if(altName.type === 8) { + // handle OID + if(altName.oid) { + value = asn1$4.oidToDer(asn1$4.oidToDer(altName.oid)); + } else { + // deprecated ... convert value to OID + value = asn1$4.oidToDer(value); + } + } + e.value.value.push(asn1$4.create( + asn1$4.Class.CONTEXT_SPECIFIC, altName.type, false, + value)); + } + } else if(e.name === 'nsComment' && options.cert) { + // sanity check value is ASCII (req'd) and not too big + if(!(/^[\x00-\x7F]*$/.test(e.comment)) || + (e.comment.length < 1) || (e.comment.length > 128)) { + throw new Error('Invalid "nsComment" content.'); + } + // IA5STRING opaque comment + e.value = asn1$4.create( + asn1$4.Class.UNIVERSAL, asn1$4.Type.IA5STRING, false, e.comment); + } else if(e.name === 'subjectKeyIdentifier' && options.cert) { + var ski = options.cert.generateSubjectKeyIdentifier(); + e.subjectKeyIdentifier = ski.toHex(); + // OCTETSTRING w/digest + e.value = asn1$4.create( + asn1$4.Class.UNIVERSAL, asn1$4.Type.OCTETSTRING, false, ski.getBytes()); + } else if(e.name === 'authorityKeyIdentifier' && options.cert) { + // SYNTAX SEQUENCE + e.value = asn1$4.create(asn1$4.Class.UNIVERSAL, asn1$4.Type.SEQUENCE, true, []); + var seq = e.value.value; + + if(e.keyIdentifier) { + var keyIdentifier = (e.keyIdentifier === true ? + options.cert.generateSubjectKeyIdentifier().getBytes() : + e.keyIdentifier); + seq.push( + asn1$4.create(asn1$4.Class.CONTEXT_SPECIFIC, 0, false, keyIdentifier)); + } + + if(e.authorityCertIssuer) { + var authorityCertIssuer = [ + asn1$4.create(asn1$4.Class.CONTEXT_SPECIFIC, 4, true, [ + _dnToAsn1(e.authorityCertIssuer === true ? + options.cert.issuer : e.authorityCertIssuer) + ]) + ]; + seq.push( + asn1$4.create(asn1$4.Class.CONTEXT_SPECIFIC, 1, true, authorityCertIssuer)); + } + + if(e.serialNumber) { + var serialNumber = forge$c.util.hexToBytes(e.serialNumber === true ? + options.cert.serialNumber : e.serialNumber); + seq.push( + asn1$4.create(asn1$4.Class.CONTEXT_SPECIFIC, 2, false, serialNumber)); + } + } else if(e.name === 'cRLDistributionPoints') { + e.value = asn1$4.create(asn1$4.Class.UNIVERSAL, asn1$4.Type.SEQUENCE, true, []); + var seq = e.value.value; + + // Create sub SEQUENCE of DistributionPointName + var subSeq = asn1$4.create( + asn1$4.Class.UNIVERSAL, asn1$4.Type.SEQUENCE, true, []); + + // Create fullName CHOICE + var fullNameGeneralNames = asn1$4.create( + asn1$4.Class.CONTEXT_SPECIFIC, 0, true, []); + var altName; + for(var n = 0; n < e.altNames.length; ++n) { + altName = e.altNames[n]; + var value = altName.value; + // handle IP + if(altName.type === 7 && altName.ip) { + value = forge$c.util.bytesFromIP(altName.ip); + if(value === null) { + var error = new Error( + 'Extension "ip" value is not a valid IPv4 or IPv6 address.'); + error.extension = e; + throw error; + } + } else if(altName.type === 8) { + // handle OID + if(altName.oid) { + value = asn1$4.oidToDer(asn1$4.oidToDer(altName.oid)); + } else { + // deprecated ... convert value to OID + value = asn1$4.oidToDer(value); + } + } + fullNameGeneralNames.value.push(asn1$4.create( + asn1$4.Class.CONTEXT_SPECIFIC, altName.type, false, + value)); + } + + // Add to the parent SEQUENCE + subSeq.value.push(asn1$4.create( + asn1$4.Class.CONTEXT_SPECIFIC, 0, true, [fullNameGeneralNames])); + seq.push(subSeq); + } + + // ensure value has been defined by now + if(typeof e.value === 'undefined') { + var error = new Error('Extension value not specified.'); + error.extension = e; + throw error; + } + + return e; +} + +/** + * Convert signature parameters object to ASN.1 + * + * @param {String} oid Signature algorithm OID + * @param params The signature parametrs object + * @return ASN.1 object representing signature parameters + */ +function _signatureParametersToAsn1(oid, params) { + switch(oid) { + case oids['RSASSA-PSS']: + var parts = []; + + if(params.hash.algorithmOid !== undefined) { + parts.push(asn1$4.create(asn1$4.Class.CONTEXT_SPECIFIC, 0, true, [ + asn1$4.create(asn1$4.Class.UNIVERSAL, asn1$4.Type.SEQUENCE, true, [ + asn1$4.create(asn1$4.Class.UNIVERSAL, asn1$4.Type.OID, false, + asn1$4.oidToDer(params.hash.algorithmOid).getBytes()), + asn1$4.create(asn1$4.Class.UNIVERSAL, asn1$4.Type.NULL, false, '') + ]) + ])); + } + + if(params.mgf.algorithmOid !== undefined) { + parts.push(asn1$4.create(asn1$4.Class.CONTEXT_SPECIFIC, 1, true, [ + asn1$4.create(asn1$4.Class.UNIVERSAL, asn1$4.Type.SEQUENCE, true, [ + asn1$4.create(asn1$4.Class.UNIVERSAL, asn1$4.Type.OID, false, + asn1$4.oidToDer(params.mgf.algorithmOid).getBytes()), + asn1$4.create(asn1$4.Class.UNIVERSAL, asn1$4.Type.SEQUENCE, true, [ + asn1$4.create(asn1$4.Class.UNIVERSAL, asn1$4.Type.OID, false, + asn1$4.oidToDer(params.mgf.hash.algorithmOid).getBytes()), + asn1$4.create(asn1$4.Class.UNIVERSAL, asn1$4.Type.NULL, false, '') + ]) + ]) + ])); + } + + if(params.saltLength !== undefined) { + parts.push(asn1$4.create(asn1$4.Class.CONTEXT_SPECIFIC, 2, true, [ + asn1$4.create(asn1$4.Class.UNIVERSAL, asn1$4.Type.INTEGER, false, + asn1$4.integerToDer(params.saltLength).getBytes()) + ])); + } + + return asn1$4.create(asn1$4.Class.UNIVERSAL, asn1$4.Type.SEQUENCE, true, parts); + + default: + return asn1$4.create(asn1$4.Class.UNIVERSAL, asn1$4.Type.NULL, false, ''); + } +} + +/** + * Converts a certification request's attributes to an ASN.1 set of + * CRIAttributes. + * + * @param csr certification request. + * + * @return the ASN.1 set of CRIAttributes. + */ +function _CRIAttributesToAsn1(csr) { + // create an empty context-specific container + var rval = asn1$4.create(asn1$4.Class.CONTEXT_SPECIFIC, 0, true, []); + + // no attributes, return empty container + if(csr.attributes.length === 0) { + return rval; + } + + // each attribute has a sequence with a type and a set of values + var attrs = csr.attributes; + for(var i = 0; i < attrs.length; ++i) { + var attr = attrs[i]; + var value = attr.value; + + // reuse tag class for attribute value if available + var valueTagClass = asn1$4.Type.UTF8; + if('valueTagClass' in attr) { + valueTagClass = attr.valueTagClass; + } + if(valueTagClass === asn1$4.Type.UTF8) { + value = forge$c.util.encodeUtf8(value); + } + var valueConstructed = false; + if('valueConstructed' in attr) { + valueConstructed = attr.valueConstructed; + } + // FIXME: handle more encodings + + // create a RelativeDistinguishedName set + // each value in the set is an AttributeTypeAndValue first + // containing the type (an OID) and second the value + var seq = asn1$4.create(asn1$4.Class.UNIVERSAL, asn1$4.Type.SEQUENCE, true, [ + // AttributeType + asn1$4.create(asn1$4.Class.UNIVERSAL, asn1$4.Type.OID, false, + asn1$4.oidToDer(attr.type).getBytes()), + asn1$4.create(asn1$4.Class.UNIVERSAL, asn1$4.Type.SET, true, [ + // AttributeValue + asn1$4.create( + asn1$4.Class.UNIVERSAL, valueTagClass, valueConstructed, value) + ]) + ]); + rval.value.push(seq); + } + + return rval; +} + +var jan_1_1950 = new Date('1950-01-01T00:00:00Z'); +var jan_1_2050 = new Date('2050-01-01T00:00:00Z'); + +/** + * Converts a Date object to ASN.1 + * Handles the different format before and after 1st January 2050 + * + * @param date date object. + * + * @return the ASN.1 object representing the date. + */ +function _dateToAsn1(date) { + if(date >= jan_1_1950 && date < jan_1_2050) { + return asn1$4.create( + asn1$4.Class.UNIVERSAL, asn1$4.Type.UTCTIME, false, + asn1$4.dateToUtcTime(date)); + } else { + return asn1$4.create( + asn1$4.Class.UNIVERSAL, asn1$4.Type.GENERALIZEDTIME, false, + asn1$4.dateToGeneralizedTime(date)); + } +} + +/** + * Gets the ASN.1 TBSCertificate part of an X.509v3 certificate. + * + * @param cert the certificate. + * + * @return the asn1 TBSCertificate. + */ +pki$2.getTBSCertificate = function(cert) { + // TBSCertificate + var notBefore = _dateToAsn1(cert.validity.notBefore); + var notAfter = _dateToAsn1(cert.validity.notAfter); + var tbs = asn1$4.create(asn1$4.Class.UNIVERSAL, asn1$4.Type.SEQUENCE, true, [ + // version + asn1$4.create(asn1$4.Class.CONTEXT_SPECIFIC, 0, true, [ + // integer + asn1$4.create(asn1$4.Class.UNIVERSAL, asn1$4.Type.INTEGER, false, + asn1$4.integerToDer(cert.version).getBytes()) + ]), + // serialNumber + asn1$4.create(asn1$4.Class.UNIVERSAL, asn1$4.Type.INTEGER, false, + forge$c.util.hexToBytes(cert.serialNumber)), + // signature + asn1$4.create(asn1$4.Class.UNIVERSAL, asn1$4.Type.SEQUENCE, true, [ + // algorithm + asn1$4.create(asn1$4.Class.UNIVERSAL, asn1$4.Type.OID, false, + asn1$4.oidToDer(cert.siginfo.algorithmOid).getBytes()), + // parameters + _signatureParametersToAsn1( + cert.siginfo.algorithmOid, cert.siginfo.parameters) + ]), + // issuer + _dnToAsn1(cert.issuer), + // validity + asn1$4.create(asn1$4.Class.UNIVERSAL, asn1$4.Type.SEQUENCE, true, [ + notBefore, + notAfter + ]), + // subject + _dnToAsn1(cert.subject), + // SubjectPublicKeyInfo + pki$2.publicKeyToAsn1(cert.publicKey) + ]); + + if(cert.issuer.uniqueId) { + // issuerUniqueID (optional) + tbs.value.push( + asn1$4.create(asn1$4.Class.CONTEXT_SPECIFIC, 1, true, [ + asn1$4.create(asn1$4.Class.UNIVERSAL, asn1$4.Type.BITSTRING, false, + // TODO: support arbitrary bit length ids + String.fromCharCode(0x00) + + cert.issuer.uniqueId + ) + ]) + ); + } + if(cert.subject.uniqueId) { + // subjectUniqueID (optional) + tbs.value.push( + asn1$4.create(asn1$4.Class.CONTEXT_SPECIFIC, 2, true, [ + asn1$4.create(asn1$4.Class.UNIVERSAL, asn1$4.Type.BITSTRING, false, + // TODO: support arbitrary bit length ids + String.fromCharCode(0x00) + + cert.subject.uniqueId + ) + ]) + ); + } + + if(cert.extensions.length > 0) { + // extensions (optional) + tbs.value.push(pki$2.certificateExtensionsToAsn1(cert.extensions)); + } + + return tbs; +}; + +/** + * Gets the ASN.1 CertificationRequestInfo part of a + * PKCS#10 CertificationRequest. + * + * @param csr the certification request. + * + * @return the asn1 CertificationRequestInfo. + */ +pki$2.getCertificationRequestInfo = function(csr) { + // CertificationRequestInfo + var cri = asn1$4.create(asn1$4.Class.UNIVERSAL, asn1$4.Type.SEQUENCE, true, [ + // version + asn1$4.create(asn1$4.Class.UNIVERSAL, asn1$4.Type.INTEGER, false, + asn1$4.integerToDer(csr.version).getBytes()), + // subject + _dnToAsn1(csr.subject), + // SubjectPublicKeyInfo + pki$2.publicKeyToAsn1(csr.publicKey), + // attributes + _CRIAttributesToAsn1(csr) + ]); + + return cri; +}; + +/** + * Converts a DistinguishedName (subject or issuer) to an ASN.1 object. + * + * @param dn the DistinguishedName. + * + * @return the asn1 representation of a DistinguishedName. + */ +pki$2.distinguishedNameToAsn1 = function(dn) { + return _dnToAsn1(dn); +}; + +/** + * Converts an X.509v3 RSA certificate to an ASN.1 object. + * + * @param cert the certificate. + * + * @return the asn1 representation of an X.509v3 RSA certificate. + */ +pki$2.certificateToAsn1 = function(cert) { + // prefer cached TBSCertificate over generating one + var tbsCertificate = cert.tbsCertificate || pki$2.getTBSCertificate(cert); + + // Certificate + return asn1$4.create(asn1$4.Class.UNIVERSAL, asn1$4.Type.SEQUENCE, true, [ + // TBSCertificate + tbsCertificate, + // AlgorithmIdentifier (signature algorithm) + asn1$4.create(asn1$4.Class.UNIVERSAL, asn1$4.Type.SEQUENCE, true, [ + // algorithm + asn1$4.create(asn1$4.Class.UNIVERSAL, asn1$4.Type.OID, false, + asn1$4.oidToDer(cert.signatureOid).getBytes()), + // parameters + _signatureParametersToAsn1(cert.signatureOid, cert.signatureParameters) + ]), + // SignatureValue + asn1$4.create(asn1$4.Class.UNIVERSAL, asn1$4.Type.BITSTRING, false, + String.fromCharCode(0x00) + cert.signature) + ]); +}; + +/** + * Converts X.509v3 certificate extensions to ASN.1. + * + * @param exts the extensions to convert. + * + * @return the extensions in ASN.1 format. + */ +pki$2.certificateExtensionsToAsn1 = function(exts) { + // create top-level extension container + var rval = asn1$4.create(asn1$4.Class.CONTEXT_SPECIFIC, 3, true, []); + + // create extension sequence (stores a sequence for each extension) + var seq = asn1$4.create(asn1$4.Class.UNIVERSAL, asn1$4.Type.SEQUENCE, true, []); + rval.value.push(seq); + + for(var i = 0; i < exts.length; ++i) { + seq.value.push(pki$2.certificateExtensionToAsn1(exts[i])); + } + + return rval; +}; + +/** + * Converts a single certificate extension to ASN.1. + * + * @param ext the extension to convert. + * + * @return the extension in ASN.1 format. + */ +pki$2.certificateExtensionToAsn1 = function(ext) { + // create a sequence for each extension + var extseq = asn1$4.create(asn1$4.Class.UNIVERSAL, asn1$4.Type.SEQUENCE, true, []); + + // extnID (OID) + extseq.value.push(asn1$4.create( + asn1$4.Class.UNIVERSAL, asn1$4.Type.OID, false, + asn1$4.oidToDer(ext.id).getBytes())); + + // critical defaults to false + if(ext.critical) { + // critical BOOLEAN DEFAULT FALSE + extseq.value.push(asn1$4.create( + asn1$4.Class.UNIVERSAL, asn1$4.Type.BOOLEAN, false, + String.fromCharCode(0xFF))); + } + + var value = ext.value; + if(typeof ext.value !== 'string') { + // value is asn.1 + value = asn1$4.toDer(value).getBytes(); + } + + // extnValue (OCTET STRING) + extseq.value.push(asn1$4.create( + asn1$4.Class.UNIVERSAL, asn1$4.Type.OCTETSTRING, false, value)); + + return extseq; +}; + +/** + * Converts a PKCS#10 certification request to an ASN.1 object. + * + * @param csr the certification request. + * + * @return the asn1 representation of a certification request. + */ +pki$2.certificationRequestToAsn1 = function(csr) { + // prefer cached CertificationRequestInfo over generating one + var cri = csr.certificationRequestInfo || + pki$2.getCertificationRequestInfo(csr); + + // Certificate + return asn1$4.create(asn1$4.Class.UNIVERSAL, asn1$4.Type.SEQUENCE, true, [ + // CertificationRequestInfo + cri, + // AlgorithmIdentifier (signature algorithm) + asn1$4.create(asn1$4.Class.UNIVERSAL, asn1$4.Type.SEQUENCE, true, [ + // algorithm + asn1$4.create(asn1$4.Class.UNIVERSAL, asn1$4.Type.OID, false, + asn1$4.oidToDer(csr.signatureOid).getBytes()), + // parameters + _signatureParametersToAsn1(csr.signatureOid, csr.signatureParameters) + ]), + // signature + asn1$4.create(asn1$4.Class.UNIVERSAL, asn1$4.Type.BITSTRING, false, + String.fromCharCode(0x00) + csr.signature) + ]); +}; + +/** + * Creates a CA store. + * + * @param certs an optional array of certificate objects or PEM-formatted + * certificate strings to add to the CA store. + * + * @return the CA store. + */ +pki$2.createCaStore = function(certs) { + // create CA store + var caStore = { + // stored certificates + certs: {} + }; + + /** + * Gets the certificate that issued the passed certificate or its + * 'parent'. + * + * @param cert the certificate to get the parent for. + * + * @return the parent certificate or null if none was found. + */ + caStore.getIssuer = function(cert) { + var rval = getBySubject(cert.issuer); + + // see if there are multiple matches + /*if(forge.util.isArray(rval)) { + // TODO: resolve multiple matches by checking + // authorityKey/subjectKey/issuerUniqueID/other identifiers, etc. + // FIXME: or alternatively do authority key mapping + // if possible (X.509v1 certs can't work?) + throw new Error('Resolving multiple issuer matches not implemented yet.'); + }*/ + + return rval; + }; + + /** + * Adds a trusted certificate to the store. + * + * @param cert the certificate to add as a trusted certificate (either a + * pki.certificate object or a PEM-formatted certificate). + */ + caStore.addCertificate = function(cert) { + // convert from pem if necessary + if(typeof cert === 'string') { + cert = forge$c.pki.certificateFromPem(cert); + } + + ensureSubjectHasHash(cert.subject); + + if(!caStore.hasCertificate(cert)) { // avoid duplicate certificates in store + if(cert.subject.hash in caStore.certs) { + // subject hash already exists, append to array + var tmp = caStore.certs[cert.subject.hash]; + if(!forge$c.util.isArray(tmp)) { + tmp = [tmp]; + } + tmp.push(cert); + caStore.certs[cert.subject.hash] = tmp; + } else { + caStore.certs[cert.subject.hash] = cert; + } + } + }; + + /** + * Checks to see if the given certificate is in the store. + * + * @param cert the certificate to check (either a pki.certificate or a + * PEM-formatted certificate). + * + * @return true if the certificate is in the store, false if not. + */ + caStore.hasCertificate = function(cert) { + // convert from pem if necessary + if(typeof cert === 'string') { + cert = forge$c.pki.certificateFromPem(cert); + } + + var match = getBySubject(cert.subject); + if(!match) { + return false; + } + if(!forge$c.util.isArray(match)) { + match = [match]; + } + // compare DER-encoding of certificates + var der1 = asn1$4.toDer(pki$2.certificateToAsn1(cert)).getBytes(); + for(var i = 0; i < match.length; ++i) { + var der2 = asn1$4.toDer(pki$2.certificateToAsn1(match[i])).getBytes(); + if(der1 === der2) { + return true; + } + } + return false; + }; + + /** + * Lists all of the certificates kept in the store. + * + * @return an array of all of the pki.certificate objects in the store. + */ + caStore.listAllCertificates = function() { + var certList = []; + + for(var hash in caStore.certs) { + if(caStore.certs.hasOwnProperty(hash)) { + var value = caStore.certs[hash]; + if(!forge$c.util.isArray(value)) { + certList.push(value); + } else { + for(var i = 0; i < value.length; ++i) { + certList.push(value[i]); + } + } + } + } + + return certList; + }; + + /** + * Removes a certificate from the store. + * + * @param cert the certificate to remove (either a pki.certificate or a + * PEM-formatted certificate). + * + * @return the certificate that was removed or null if the certificate + * wasn't in store. + */ + caStore.removeCertificate = function(cert) { + var result; + + // convert from pem if necessary + if(typeof cert === 'string') { + cert = forge$c.pki.certificateFromPem(cert); + } + ensureSubjectHasHash(cert.subject); + if(!caStore.hasCertificate(cert)) { + return null; + } + + var match = getBySubject(cert.subject); + + if(!forge$c.util.isArray(match)) { + result = caStore.certs[cert.subject.hash]; + delete caStore.certs[cert.subject.hash]; + return result; + } + + // compare DER-encoding of certificates + var der1 = asn1$4.toDer(pki$2.certificateToAsn1(cert)).getBytes(); + for(var i = 0; i < match.length; ++i) { + var der2 = asn1$4.toDer(pki$2.certificateToAsn1(match[i])).getBytes(); + if(der1 === der2) { + result = match[i]; + match.splice(i, 1); + } + } + if(match.length === 0) { + delete caStore.certs[cert.subject.hash]; + } + + return result; + }; + + function getBySubject(subject) { + ensureSubjectHasHash(subject); + return caStore.certs[subject.hash] || null; + } + + function ensureSubjectHasHash(subject) { + // produce subject hash if it doesn't exist + if(!subject.hash) { + var md = forge$c.md.sha1.create(); + subject.attributes = pki$2.RDNAttributesAsArray(_dnToAsn1(subject), md); + subject.hash = md.digest().toHex(); + } + } + + // auto-add passed in certs + if(certs) { + // parse PEM-formatted certificates as necessary + for(var i = 0; i < certs.length; ++i) { + var cert = certs[i]; + caStore.addCertificate(cert); + } + } + + return caStore; +}; + +/** + * Certificate verification errors, based on TLS. + */ +pki$2.certificateError = { + bad_certificate: 'forge.pki.BadCertificate', + unsupported_certificate: 'forge.pki.UnsupportedCertificate', + certificate_revoked: 'forge.pki.CertificateRevoked', + certificate_expired: 'forge.pki.CertificateExpired', + certificate_unknown: 'forge.pki.CertificateUnknown', + unknown_ca: 'forge.pki.UnknownCertificateAuthority' +}; + +/** + * Verifies a certificate chain against the given Certificate Authority store + * with an optional custom verify callback. + * + * @param caStore a certificate store to verify against. + * @param chain the certificate chain to verify, with the root or highest + * authority at the end (an array of certificates). + * @param options a callback to be called for every certificate in the chain or + * an object with: + * verify a callback to be called for every certificate in the + * chain + * validityCheckDate the date against which the certificate + * validity period should be checked. Pass null to not check + * the validity period. By default, the current date is used. + * + * The verify callback has the following signature: + * + * verified - Set to true if certificate was verified, otherwise the + * pki.certificateError for why the certificate failed. + * depth - The current index in the chain, where 0 is the end point's cert. + * certs - The certificate chain, *NOTE* an empty chain indicates an anonymous + * end point. + * + * The function returns true on success and on failure either the appropriate + * pki.certificateError or an object with 'error' set to the appropriate + * pki.certificateError and 'message' set to a custom error message. + * + * @return true if successful, error thrown if not. + */ +pki$2.verifyCertificateChain = function(caStore, chain, options) { + /* From: RFC3280 - Internet X.509 Public Key Infrastructure Certificate + Section 6: Certification Path Validation + See inline parentheticals related to this particular implementation. + + The primary goal of path validation is to verify the binding between + a subject distinguished name or a subject alternative name and subject + public key, as represented in the end entity certificate, based on the + public key of the trust anchor. This requires obtaining a sequence of + certificates that support that binding. That sequence should be provided + in the passed 'chain'. The trust anchor should be in the given CA + store. The 'end entity' certificate is the certificate provided by the + end point (typically a server) and is the first in the chain. + + To meet this goal, the path validation process verifies, among other + things, that a prospective certification path (a sequence of n + certificates or a 'chain') satisfies the following conditions: + + (a) for all x in {1, ..., n-1}, the subject of certificate x is + the issuer of certificate x+1; + + (b) certificate 1 is issued by the trust anchor; + + (c) certificate n is the certificate to be validated; and + + (d) for all x in {1, ..., n}, the certificate was valid at the + time in question. + + Note that here 'n' is index 0 in the chain and 1 is the last certificate + in the chain and it must be signed by a certificate in the connection's + CA store. + + The path validation process also determines the set of certificate + policies that are valid for this path, based on the certificate policies + extension, policy mapping extension, policy constraints extension, and + inhibit any-policy extension. + + Note: Policy mapping extension not supported (Not Required). + + Note: If the certificate has an unsupported critical extension, then it + must be rejected. + + Note: A certificate is self-issued if the DNs that appear in the subject + and issuer fields are identical and are not empty. + + The path validation algorithm assumes the following seven inputs are + provided to the path processing logic. What this specific implementation + will use is provided parenthetically: + + (a) a prospective certification path of length n (the 'chain') + (b) the current date/time: ('now'). + (c) user-initial-policy-set: A set of certificate policy identifiers + naming the policies that are acceptable to the certificate user. + The user-initial-policy-set contains the special value any-policy + if the user is not concerned about certificate policy + (Not implemented. Any policy is accepted). + (d) trust anchor information, describing a CA that serves as a trust + anchor for the certification path. The trust anchor information + includes: + + (1) the trusted issuer name, + (2) the trusted public key algorithm, + (3) the trusted public key, and + (4) optionally, the trusted public key parameters associated + with the public key. + + (Trust anchors are provided via certificates in the CA store). + + The trust anchor information may be provided to the path processing + procedure in the form of a self-signed certificate. The trusted anchor + information is trusted because it was delivered to the path processing + procedure by some trustworthy out-of-band procedure. If the trusted + public key algorithm requires parameters, then the parameters are + provided along with the trusted public key (No parameters used in this + implementation). + + (e) initial-policy-mapping-inhibit, which indicates if policy mapping is + allowed in the certification path. + (Not implemented, no policy checking) + + (f) initial-explicit-policy, which indicates if the path must be valid + for at least one of the certificate policies in the user-initial- + policy-set. + (Not implemented, no policy checking) + + (g) initial-any-policy-inhibit, which indicates whether the + anyPolicy OID should be processed if it is included in a + certificate. + (Not implemented, so any policy is valid provided that it is + not marked as critical) */ + + /* Basic Path Processing: + + For each certificate in the 'chain', the following is checked: + + 1. The certificate validity period includes the current time. + 2. The certificate was signed by its parent (where the parent is either + the next in the chain or from the CA store). Allow processing to + continue to the next step if no parent is found but the certificate is + in the CA store. + 3. TODO: The certificate has not been revoked. + 4. The certificate issuer name matches the parent's subject name. + 5. TODO: If the certificate is self-issued and not the final certificate + in the chain, skip this step, otherwise verify that the subject name + is within one of the permitted subtrees of X.500 distinguished names + and that each of the alternative names in the subjectAltName extension + (critical or non-critical) is within one of the permitted subtrees for + that name type. + 6. TODO: If the certificate is self-issued and not the final certificate + in the chain, skip this step, otherwise verify that the subject name + is not within one of the excluded subtrees for X.500 distinguished + names and none of the subjectAltName extension names are excluded for + that name type. + 7. The other steps in the algorithm for basic path processing involve + handling the policy extension which is not presently supported in this + implementation. Instead, if a critical policy extension is found, the + certificate is rejected as not supported. + 8. If the certificate is not the first or if its the only certificate in + the chain (having no parent from the CA store or is self-signed) and it + has a critical key usage extension, verify that the keyCertSign bit is + set. If the key usage extension exists, verify that the basic + constraints extension exists. If the basic constraints extension exists, + verify that the cA flag is set. If pathLenConstraint is set, ensure that + the number of certificates that precede in the chain (come earlier + in the chain as implemented below), excluding the very first in the + chain (typically the end-entity one), isn't greater than the + pathLenConstraint. This constraint limits the number of intermediate + CAs that may appear below a CA before only end-entity certificates + may be issued. */ + + // if a verify callback is passed as the third parameter, package it within + // the options object. This is to support a legacy function signature that + // expected the verify callback as the third parameter. + if(typeof options === 'function') { + options = {verify: options}; + } + options = options || {}; + + // copy cert chain references to another array to protect against changes + // in verify callback + chain = chain.slice(0); + var certs = chain.slice(0); + + var validityCheckDate = options.validityCheckDate; + // if no validityCheckDate is specified, default to the current date. Make + // sure to maintain the value null because it indicates that the validity + // period should not be checked. + if(typeof validityCheckDate === 'undefined') { + validityCheckDate = new Date(); + } + + // verify each cert in the chain using its parent, where the parent + // is either the next in the chain or from the CA store + var first = true; + var error = null; + var depth = 0; + do { + var cert = chain.shift(); + var parent = null; + var selfSigned = false; + + if(validityCheckDate) { + // 1. check valid time + if(validityCheckDate < cert.validity.notBefore || + validityCheckDate > cert.validity.notAfter) { + error = { + message: 'Certificate is not valid yet or has expired.', + error: pki$2.certificateError.certificate_expired, + notBefore: cert.validity.notBefore, + notAfter: cert.validity.notAfter, + // TODO: we might want to reconsider renaming 'now' to + // 'validityCheckDate' should this API be changed in the future. + now: validityCheckDate + }; + } + } + + // 2. verify with parent from chain or CA store + if(error === null) { + parent = chain[0] || caStore.getIssuer(cert); + if(parent === null) { + // check for self-signed cert + if(cert.isIssuer(cert)) { + selfSigned = true; + parent = cert; + } + } + + if(parent) { + // FIXME: current CA store implementation might have multiple + // certificates where the issuer can't be determined from the + // certificate (happens rarely with, eg: old certificates) so normalize + // by always putting parents into an array + // TODO: there's may be an extreme degenerate case currently uncovered + // where an old intermediate certificate seems to have a matching parent + // but none of the parents actually verify ... but the intermediate + // is in the CA and it should pass this check; needs investigation + var parents = parent; + if(!forge$c.util.isArray(parents)) { + parents = [parents]; + } + + // try to verify with each possible parent (typically only one) + var verified = false; + while(!verified && parents.length > 0) { + parent = parents.shift(); + try { + verified = parent.verify(cert); + } catch(ex) { + // failure to verify, don't care why, try next one + } + } + + if(!verified) { + error = { + message: 'Certificate signature is invalid.', + error: pki$2.certificateError.bad_certificate + }; + } + } + + if(error === null && (!parent || selfSigned) && + !caStore.hasCertificate(cert)) { + // no parent issuer and certificate itself is not trusted + error = { + message: 'Certificate is not trusted.', + error: pki$2.certificateError.unknown_ca + }; + } + } + + // TODO: 3. check revoked + + // 4. check for matching issuer/subject + if(error === null && parent && !cert.isIssuer(parent)) { + // parent is not issuer + error = { + message: 'Certificate issuer is invalid.', + error: pki$2.certificateError.bad_certificate + }; + } + + // 5. TODO: check names with permitted names tree + + // 6. TODO: check names against excluded names tree + + // 7. check for unsupported critical extensions + if(error === null) { + // supported extensions + var se = { + keyUsage: true, + basicConstraints: true + }; + for(var i = 0; error === null && i < cert.extensions.length; ++i) { + var ext = cert.extensions[i]; + if(ext.critical && !(ext.name in se)) { + error = { + message: + 'Certificate has an unsupported critical extension.', + error: pki$2.certificateError.unsupported_certificate + }; + } + } + } + + // 8. check for CA if cert is not first or is the only certificate + // remaining in chain with no parent or is self-signed + if(error === null && + (!first || (chain.length === 0 && (!parent || selfSigned)))) { + // first check keyUsage extension and then basic constraints + var bcExt = cert.getExtension('basicConstraints'); + var keyUsageExt = cert.getExtension('keyUsage'); + if(keyUsageExt !== null) { + // keyCertSign must be true and there must be a basic + // constraints extension + if(!keyUsageExt.keyCertSign || bcExt === null) { + // bad certificate + error = { + message: + 'Certificate keyUsage or basicConstraints conflict ' + + 'or indicate that the certificate is not a CA. ' + + 'If the certificate is the only one in the chain or ' + + 'isn\'t the first then the certificate must be a ' + + 'valid CA.', + error: pki$2.certificateError.bad_certificate + }; + } + } + // basic constraints cA flag must be set + if(error === null && bcExt !== null && !bcExt.cA) { + // bad certificate + error = { + message: + 'Certificate basicConstraints indicates the certificate ' + + 'is not a CA.', + error: pki$2.certificateError.bad_certificate + }; + } + // if error is not null and keyUsage is available, then we know it + // has keyCertSign and there is a basic constraints extension too, + // which means we can check pathLenConstraint (if it exists) + if(error === null && keyUsageExt !== null && + 'pathLenConstraint' in bcExt) { + // pathLen is the maximum # of intermediate CA certs that can be + // found between the current certificate and the end-entity (depth 0) + // certificate; this number does not include the end-entity (depth 0, + // last in the chain) even if it happens to be a CA certificate itself + var pathLen = depth - 1; + if(pathLen > bcExt.pathLenConstraint) { + // pathLenConstraint violated, bad certificate + error = { + message: + 'Certificate basicConstraints pathLenConstraint violated.', + error: pki$2.certificateError.bad_certificate + }; + } + } + } + + // call application callback + var vfd = (error === null) ? true : error.error; + var ret = options.verify ? options.verify(vfd, depth, certs) : vfd; + if(ret === true) { + // clear any set error + error = null; + } else { + // if passed basic tests, set default message and alert + if(vfd === true) { + error = { + message: 'The application rejected the certificate.', + error: pki$2.certificateError.bad_certificate + }; + } + + // check for custom error info + if(ret || ret === 0) { + // set custom message and error + if(typeof ret === 'object' && !forge$c.util.isArray(ret)) { + if(ret.message) { + error.message = ret.message; + } + if(ret.error) { + error.error = ret.error; + } + } else if(typeof ret === 'string') { + // set custom error + error.error = ret; + } + } + + // throw error + throw error; + } + + // no longer first cert in chain + first = false; + ++depth; + } while(chain.length > 0); + + return true; +}; + +/** + * Javascript implementation of PKCS#12. + * + * @author Dave Longley + * @author Stefan Siegl + * + * Copyright (c) 2010-2014 Digital Bazaar, Inc. + * Copyright (c) 2012 Stefan Siegl + * + * The ASN.1 representation of PKCS#12 is as follows + * (see ftp://ftp.rsasecurity.com/pub/pkcs/pkcs-12/pkcs-12-tc1.pdf for details) + * + * PFX ::= SEQUENCE { + * version INTEGER {v3(3)}(v3,...), + * authSafe ContentInfo, + * macData MacData OPTIONAL + * } + * + * MacData ::= SEQUENCE { + * mac DigestInfo, + * macSalt OCTET STRING, + * iterations INTEGER DEFAULT 1 + * } + * Note: The iterations default is for historical reasons and its use is + * deprecated. A higher value, like 1024, is recommended. + * + * DigestInfo is defined in PKCS#7 as follows: + * + * DigestInfo ::= SEQUENCE { + * digestAlgorithm DigestAlgorithmIdentifier, + * digest Digest + * } + * + * DigestAlgorithmIdentifier ::= AlgorithmIdentifier + * + * The AlgorithmIdentifier contains an Object Identifier (OID) and parameters + * for the algorithm, if any. In the case of SHA1 there is none. + * + * AlgorithmIdentifer ::= SEQUENCE { + * algorithm OBJECT IDENTIFIER, + * parameters ANY DEFINED BY algorithm OPTIONAL + * } + * + * Digest ::= OCTET STRING + * + * + * ContentInfo ::= SEQUENCE { + * contentType ContentType, + * content [0] EXPLICIT ANY DEFINED BY contentType OPTIONAL + * } + * + * ContentType ::= OBJECT IDENTIFIER + * + * AuthenticatedSafe ::= SEQUENCE OF ContentInfo + * -- Data if unencrypted + * -- EncryptedData if password-encrypted + * -- EnvelopedData if public key-encrypted + * + * + * SafeContents ::= SEQUENCE OF SafeBag + * + * SafeBag ::= SEQUENCE { + * bagId BAG-TYPE.&id ({PKCS12BagSet}) + * bagValue [0] EXPLICIT BAG-TYPE.&Type({PKCS12BagSet}{@bagId}), + * bagAttributes SET OF PKCS12Attribute OPTIONAL + * } + * + * PKCS12Attribute ::= SEQUENCE { + * attrId ATTRIBUTE.&id ({PKCS12AttrSet}), + * attrValues SET OF ATTRIBUTE.&Type ({PKCS12AttrSet}{@attrId}) + * } -- This type is compatible with the X.500 type 'Attribute' + * + * PKCS12AttrSet ATTRIBUTE ::= { + * friendlyName | -- from PKCS #9 + * localKeyId, -- from PKCS #9 + * ... -- Other attributes are allowed + * } + * + * CertBag ::= SEQUENCE { + * certId BAG-TYPE.&id ({CertTypes}), + * certValue [0] EXPLICIT BAG-TYPE.&Type ({CertTypes}{@certId}) + * } + * + * x509Certificate BAG-TYPE ::= {OCTET STRING IDENTIFIED BY {certTypes 1}} + * -- DER-encoded X.509 certificate stored in OCTET STRING + * + * sdsiCertificate BAG-TYPE ::= {IA5String IDENTIFIED BY {certTypes 2}} + * -- Base64-encoded SDSI certificate stored in IA5String + * + * CertTypes BAG-TYPE ::= { + * x509Certificate | + * sdsiCertificate, + * ... -- For future extensions + * } + */ + +var forge$b = forge$D; + + + + + + + + + + + +// shortcut for asn.1 & PKI API +var asn1$3 = forge$b.asn1; +var pki$1 = forge$b.pki; + +// shortcut for PKCS#12 API +var p12 = forge$b.pkcs12 = forge$b.pkcs12 || {}; + +var contentInfoValidator = { + name: 'ContentInfo', + tagClass: asn1$3.Class.UNIVERSAL, + type: asn1$3.Type.SEQUENCE, // a ContentInfo + constructed: true, + value: [{ + name: 'ContentInfo.contentType', + tagClass: asn1$3.Class.UNIVERSAL, + type: asn1$3.Type.OID, + constructed: false, + capture: 'contentType' + }, { + name: 'ContentInfo.content', + tagClass: asn1$3.Class.CONTEXT_SPECIFIC, + constructed: true, + captureAsn1: 'content' + }] +}; + +var pfxValidator = { + name: 'PFX', + tagClass: asn1$3.Class.UNIVERSAL, + type: asn1$3.Type.SEQUENCE, + constructed: true, + value: [{ + name: 'PFX.version', + tagClass: asn1$3.Class.UNIVERSAL, + type: asn1$3.Type.INTEGER, + constructed: false, + capture: 'version' + }, + contentInfoValidator, { + name: 'PFX.macData', + tagClass: asn1$3.Class.UNIVERSAL, + type: asn1$3.Type.SEQUENCE, + constructed: true, + optional: true, + captureAsn1: 'mac', + value: [{ + name: 'PFX.macData.mac', + tagClass: asn1$3.Class.UNIVERSAL, + type: asn1$3.Type.SEQUENCE, // DigestInfo + constructed: true, + value: [{ + name: 'PFX.macData.mac.digestAlgorithm', + tagClass: asn1$3.Class.UNIVERSAL, + type: asn1$3.Type.SEQUENCE, // DigestAlgorithmIdentifier + constructed: true, + value: [{ + name: 'PFX.macData.mac.digestAlgorithm.algorithm', + tagClass: asn1$3.Class.UNIVERSAL, + type: asn1$3.Type.OID, + constructed: false, + capture: 'macAlgorithm' + }, { + name: 'PFX.macData.mac.digestAlgorithm.parameters', + tagClass: asn1$3.Class.UNIVERSAL, + captureAsn1: 'macAlgorithmParameters' + }] + }, { + name: 'PFX.macData.mac.digest', + tagClass: asn1$3.Class.UNIVERSAL, + type: asn1$3.Type.OCTETSTRING, + constructed: false, + capture: 'macDigest' + }] + }, { + name: 'PFX.macData.macSalt', + tagClass: asn1$3.Class.UNIVERSAL, + type: asn1$3.Type.OCTETSTRING, + constructed: false, + capture: 'macSalt' + }, { + name: 'PFX.macData.iterations', + tagClass: asn1$3.Class.UNIVERSAL, + type: asn1$3.Type.INTEGER, + constructed: false, + optional: true, + capture: 'macIterations' + }] + }] +}; + +var safeBagValidator = { + name: 'SafeBag', + tagClass: asn1$3.Class.UNIVERSAL, + type: asn1$3.Type.SEQUENCE, + constructed: true, + value: [{ + name: 'SafeBag.bagId', + tagClass: asn1$3.Class.UNIVERSAL, + type: asn1$3.Type.OID, + constructed: false, + capture: 'bagId' + }, { + name: 'SafeBag.bagValue', + tagClass: asn1$3.Class.CONTEXT_SPECIFIC, + constructed: true, + captureAsn1: 'bagValue' + }, { + name: 'SafeBag.bagAttributes', + tagClass: asn1$3.Class.UNIVERSAL, + type: asn1$3.Type.SET, + constructed: true, + optional: true, + capture: 'bagAttributes' + }] +}; + +var attributeValidator = { + name: 'Attribute', + tagClass: asn1$3.Class.UNIVERSAL, + type: asn1$3.Type.SEQUENCE, + constructed: true, + value: [{ + name: 'Attribute.attrId', + tagClass: asn1$3.Class.UNIVERSAL, + type: asn1$3.Type.OID, + constructed: false, + capture: 'oid' + }, { + name: 'Attribute.attrValues', + tagClass: asn1$3.Class.UNIVERSAL, + type: asn1$3.Type.SET, + constructed: true, + capture: 'values' + }] +}; + +var certBagValidator = { + name: 'CertBag', + tagClass: asn1$3.Class.UNIVERSAL, + type: asn1$3.Type.SEQUENCE, + constructed: true, + value: [{ + name: 'CertBag.certId', + tagClass: asn1$3.Class.UNIVERSAL, + type: asn1$3.Type.OID, + constructed: false, + capture: 'certId' + }, { + name: 'CertBag.certValue', + tagClass: asn1$3.Class.CONTEXT_SPECIFIC, + constructed: true, + /* So far we only support X.509 certificates (which are wrapped in + an OCTET STRING, hence hard code that here). */ + value: [{ + name: 'CertBag.certValue[0]', + tagClass: asn1$3.Class.UNIVERSAL, + type: asn1$3.Class.OCTETSTRING, + constructed: false, + capture: 'cert' + }] + }] +}; + +/** + * Search SafeContents structure for bags with matching attributes. + * + * The search can optionally be narrowed by a certain bag type. + * + * @param safeContents the SafeContents structure to search in. + * @param attrName the name of the attribute to compare against. + * @param attrValue the attribute value to search for. + * @param [bagType] bag type to narrow search by. + * + * @return an array of matching bags. + */ +function _getBagsByAttribute(safeContents, attrName, attrValue, bagType) { + var result = []; + + for(var i = 0; i < safeContents.length; i++) { + for(var j = 0; j < safeContents[i].safeBags.length; j++) { + var bag = safeContents[i].safeBags[j]; + if(bagType !== undefined && bag.type !== bagType) { + continue; + } + // only filter by bag type, no attribute specified + if(attrName === null) { + result.push(bag); + continue; + } + if(bag.attributes[attrName] !== undefined && + bag.attributes[attrName].indexOf(attrValue) >= 0) { + result.push(bag); + } + } + } + + return result; +} + +/** + * Converts a PKCS#12 PFX in ASN.1 notation into a PFX object. + * + * @param obj The PKCS#12 PFX in ASN.1 notation. + * @param strict true to use strict DER decoding, false not to (default: true). + * @param {String} password Password to decrypt with (optional). + * + * @return PKCS#12 PFX object. + */ +p12.pkcs12FromAsn1 = function(obj, strict, password) { + // handle args + if(typeof strict === 'string') { + password = strict; + strict = true; + } else if(strict === undefined) { + strict = true; + } + + // validate PFX and capture data + var capture = {}; + var errors = []; + if(!asn1$3.validate(obj, pfxValidator, capture, errors)) { + var error = new Error('Cannot read PKCS#12 PFX. ' + + 'ASN.1 object is not an PKCS#12 PFX.'); + error.errors = error; + throw error; + } + + var pfx = { + version: capture.version.charCodeAt(0), + safeContents: [], + + /** + * Gets bags with matching attributes. + * + * @param filter the attributes to filter by: + * [localKeyId] the localKeyId to search for. + * [localKeyIdHex] the localKeyId in hex to search for. + * [friendlyName] the friendly name to search for. + * [bagType] bag type to narrow each attribute search by. + * + * @return a map of attribute type to an array of matching bags or, if no + * attribute was given but a bag type, the map key will be the + * bag type. + */ + getBags: function(filter) { + var rval = {}; + + var localKeyId; + if('localKeyId' in filter) { + localKeyId = filter.localKeyId; + } else if('localKeyIdHex' in filter) { + localKeyId = forge$b.util.hexToBytes(filter.localKeyIdHex); + } + + // filter on bagType only + if(localKeyId === undefined && !('friendlyName' in filter) && + 'bagType' in filter) { + rval[filter.bagType] = _getBagsByAttribute( + pfx.safeContents, null, null, filter.bagType); + } + + if(localKeyId !== undefined) { + rval.localKeyId = _getBagsByAttribute( + pfx.safeContents, 'localKeyId', + localKeyId, filter.bagType); + } + if('friendlyName' in filter) { + rval.friendlyName = _getBagsByAttribute( + pfx.safeContents, 'friendlyName', + filter.friendlyName, filter.bagType); + } + + return rval; + }, + + /** + * DEPRECATED: use getBags() instead. + * + * Get bags with matching friendlyName attribute. + * + * @param friendlyName the friendly name to search for. + * @param [bagType] bag type to narrow search by. + * + * @return an array of bags with matching friendlyName attribute. + */ + getBagsByFriendlyName: function(friendlyName, bagType) { + return _getBagsByAttribute( + pfx.safeContents, 'friendlyName', friendlyName, bagType); + }, + + /** + * DEPRECATED: use getBags() instead. + * + * Get bags with matching localKeyId attribute. + * + * @param localKeyId the localKeyId to search for. + * @param [bagType] bag type to narrow search by. + * + * @return an array of bags with matching localKeyId attribute. + */ + getBagsByLocalKeyId: function(localKeyId, bagType) { + return _getBagsByAttribute( + pfx.safeContents, 'localKeyId', localKeyId, bagType); + } + }; + + if(capture.version.charCodeAt(0) !== 3) { + var error = new Error('PKCS#12 PFX of version other than 3 not supported.'); + error.version = capture.version.charCodeAt(0); + throw error; + } + + if(asn1$3.derToOid(capture.contentType) !== pki$1.oids.data) { + var error = new Error('Only PKCS#12 PFX in password integrity mode supported.'); + error.oid = asn1$3.derToOid(capture.contentType); + throw error; + } + + var data = capture.content.value[0]; + if(data.tagClass !== asn1$3.Class.UNIVERSAL || + data.type !== asn1$3.Type.OCTETSTRING) { + throw new Error('PKCS#12 authSafe content data is not an OCTET STRING.'); + } + data = _decodePkcs7Data(data); + + // check for MAC + if(capture.mac) { + var md = null; + var macKeyBytes = 0; + var macAlgorithm = asn1$3.derToOid(capture.macAlgorithm); + switch(macAlgorithm) { + case pki$1.oids.sha1: + md = forge$b.md.sha1.create(); + macKeyBytes = 20; + break; + case pki$1.oids.sha256: + md = forge$b.md.sha256.create(); + macKeyBytes = 32; + break; + case pki$1.oids.sha384: + md = forge$b.md.sha384.create(); + macKeyBytes = 48; + break; + case pki$1.oids.sha512: + md = forge$b.md.sha512.create(); + macKeyBytes = 64; + break; + case pki$1.oids.md5: + md = forge$b.md.md5.create(); + macKeyBytes = 16; + break; + } + if(md === null) { + throw new Error('PKCS#12 uses unsupported MAC algorithm: ' + macAlgorithm); + } + + // verify MAC (iterations default to 1) + var macSalt = new forge$b.util.ByteBuffer(capture.macSalt); + var macIterations = (('macIterations' in capture) ? + parseInt(forge$b.util.bytesToHex(capture.macIterations), 16) : 1); + var macKey = p12.generateKey( + password, macSalt, 3, macIterations, macKeyBytes, md); + var mac = forge$b.hmac.create(); + mac.start(md, macKey); + mac.update(data.value); + var macValue = mac.getMac(); + if(macValue.getBytes() !== capture.macDigest) { + throw new Error('PKCS#12 MAC could not be verified. Invalid password?'); + } + } + + _decodeAuthenticatedSafe(pfx, data.value, strict, password); + return pfx; +}; + +/** + * Decodes PKCS#7 Data. PKCS#7 (RFC 2315) defines "Data" as an OCTET STRING, + * but it is sometimes an OCTET STRING that is composed/constructed of chunks, + * each its own OCTET STRING. This is BER-encoding vs. DER-encoding. This + * function transforms this corner-case into the usual simple, + * non-composed/constructed OCTET STRING. + * + * This function may be moved to ASN.1 at some point to better deal with + * more BER-encoding issues, should they arise. + * + * @param data the ASN.1 Data object to transform. + */ +function _decodePkcs7Data(data) { + // handle special case of "chunked" data content: an octet string composed + // of other octet strings + if(data.composed || data.constructed) { + var value = forge$b.util.createBuffer(); + for(var i = 0; i < data.value.length; ++i) { + value.putBytes(data.value[i].value); + } + data.composed = data.constructed = false; + data.value = value.getBytes(); + } + return data; +} + +/** + * Decode PKCS#12 AuthenticatedSafe (BER encoded) into PFX object. + * + * The AuthenticatedSafe is a BER-encoded SEQUENCE OF ContentInfo. + * + * @param pfx The PKCS#12 PFX object to fill. + * @param {String} authSafe BER-encoded AuthenticatedSafe. + * @param strict true to use strict DER decoding, false not to. + * @param {String} password Password to decrypt with (optional). + */ +function _decodeAuthenticatedSafe(pfx, authSafe, strict, password) { + authSafe = asn1$3.fromDer(authSafe, strict); /* actually it's BER encoded */ + + if(authSafe.tagClass !== asn1$3.Class.UNIVERSAL || + authSafe.type !== asn1$3.Type.SEQUENCE || + authSafe.constructed !== true) { + throw new Error('PKCS#12 AuthenticatedSafe expected to be a ' + + 'SEQUENCE OF ContentInfo'); + } + + for(var i = 0; i < authSafe.value.length; i++) { + var contentInfo = authSafe.value[i]; + + // validate contentInfo and capture data + var capture = {}; + var errors = []; + if(!asn1$3.validate(contentInfo, contentInfoValidator, capture, errors)) { + var error = new Error('Cannot read ContentInfo.'); + error.errors = errors; + throw error; + } + + var obj = { + encrypted: false + }; + var safeContents = null; + var data = capture.content.value[0]; + switch(asn1$3.derToOid(capture.contentType)) { + case pki$1.oids.data: + if(data.tagClass !== asn1$3.Class.UNIVERSAL || + data.type !== asn1$3.Type.OCTETSTRING) { + throw new Error('PKCS#12 SafeContents Data is not an OCTET STRING.'); + } + safeContents = _decodePkcs7Data(data).value; + break; + case pki$1.oids.encryptedData: + safeContents = _decryptSafeContents(data, password); + obj.encrypted = true; + break; + default: + var error = new Error('Unsupported PKCS#12 contentType.'); + error.contentType = asn1$3.derToOid(capture.contentType); + throw error; + } + + obj.safeBags = _decodeSafeContents(safeContents, strict, password); + pfx.safeContents.push(obj); + } +} + +/** + * Decrypt PKCS#7 EncryptedData structure. + * + * @param data ASN.1 encoded EncryptedContentInfo object. + * @param password The user-provided password. + * + * @return The decrypted SafeContents (ASN.1 object). + */ +function _decryptSafeContents(data, password) { + var capture = {}; + var errors = []; + if(!asn1$3.validate( + data, forge$b.pkcs7.asn1.encryptedDataValidator, capture, errors)) { + var error = new Error('Cannot read EncryptedContentInfo.'); + error.errors = errors; + throw error; + } + + var oid = asn1$3.derToOid(capture.contentType); + if(oid !== pki$1.oids.data) { + var error = new Error( + 'PKCS#12 EncryptedContentInfo ContentType is not Data.'); + error.oid = oid; + throw error; + } + + // get cipher + oid = asn1$3.derToOid(capture.encAlgorithm); + var cipher = pki$1.pbe.getCipher(oid, capture.encParameter, password); + + // get encrypted data + var encryptedContentAsn1 = _decodePkcs7Data(capture.encryptedContentAsn1); + var encrypted = forge$b.util.createBuffer(encryptedContentAsn1.value); + + cipher.update(encrypted); + if(!cipher.finish()) { + throw new Error('Failed to decrypt PKCS#12 SafeContents.'); + } + + return cipher.output.getBytes(); +} + +/** + * Decode PKCS#12 SafeContents (BER-encoded) into array of Bag objects. + * + * The safeContents is a BER-encoded SEQUENCE OF SafeBag. + * + * @param {String} safeContents BER-encoded safeContents. + * @param strict true to use strict DER decoding, false not to. + * @param {String} password Password to decrypt with (optional). + * + * @return {Array} Array of Bag objects. + */ +function _decodeSafeContents(safeContents, strict, password) { + // if strict and no safe contents, return empty safes + if(!strict && safeContents.length === 0) { + return []; + } + + // actually it's BER-encoded + safeContents = asn1$3.fromDer(safeContents, strict); + + if(safeContents.tagClass !== asn1$3.Class.UNIVERSAL || + safeContents.type !== asn1$3.Type.SEQUENCE || + safeContents.constructed !== true) { + throw new Error( + 'PKCS#12 SafeContents expected to be a SEQUENCE OF SafeBag.'); + } + + var res = []; + for(var i = 0; i < safeContents.value.length; i++) { + var safeBag = safeContents.value[i]; + + // validate SafeBag and capture data + var capture = {}; + var errors = []; + if(!asn1$3.validate(safeBag, safeBagValidator, capture, errors)) { + var error = new Error('Cannot read SafeBag.'); + error.errors = errors; + throw error; + } + + /* Create bag object and push to result array. */ + var bag = { + type: asn1$3.derToOid(capture.bagId), + attributes: _decodeBagAttributes(capture.bagAttributes) + }; + res.push(bag); + + var validator, decoder; + var bagAsn1 = capture.bagValue.value[0]; + switch(bag.type) { + case pki$1.oids.pkcs8ShroudedKeyBag: + /* bagAsn1 has a EncryptedPrivateKeyInfo, which we need to decrypt. + Afterwards we can handle it like a keyBag, + which is a PrivateKeyInfo. */ + bagAsn1 = pki$1.decryptPrivateKeyInfo(bagAsn1, password); + if(bagAsn1 === null) { + throw new Error( + 'Unable to decrypt PKCS#8 ShroudedKeyBag, wrong password?'); + } + + /* fall through */ + case pki$1.oids.keyBag: + /* A PKCS#12 keyBag is a simple PrivateKeyInfo as understood by our + PKI module, hence we don't have to do validation/capturing here, + just pass what we already got. */ + try { + bag.key = pki$1.privateKeyFromAsn1(bagAsn1); + } catch(e) { + // ignore unknown key type, pass asn1 value + bag.key = null; + bag.asn1 = bagAsn1; + } + continue; /* Nothing more to do. */ + + case pki$1.oids.certBag: + /* A PKCS#12 certBag can wrap both X.509 and sdsi certificates. + Therefore put the SafeBag content through another validator to + capture the fields. Afterwards check & store the results. */ + validator = certBagValidator; + decoder = function() { + if(asn1$3.derToOid(capture.certId) !== pki$1.oids.x509Certificate) { + var error = new Error( + 'Unsupported certificate type, only X.509 supported.'); + error.oid = asn1$3.derToOid(capture.certId); + throw error; + } + + // true=produce cert hash + var certAsn1 = asn1$3.fromDer(capture.cert, strict); + try { + bag.cert = pki$1.certificateFromAsn1(certAsn1, true); + } catch(e) { + // ignore unknown cert type, pass asn1 value + bag.cert = null; + bag.asn1 = certAsn1; + } + }; + break; + + default: + var error = new Error('Unsupported PKCS#12 SafeBag type.'); + error.oid = bag.type; + throw error; + } + + /* Validate SafeBag value (i.e. CertBag, etc.) and capture data if needed. */ + if(validator !== undefined && + !asn1$3.validate(bagAsn1, validator, capture, errors)) { + var error = new Error('Cannot read PKCS#12 ' + validator.name); + error.errors = errors; + throw error; + } + + /* Call decoder function from above to store the results. */ + decoder(); + } + + return res; +} + +/** + * Decode PKCS#12 SET OF PKCS12Attribute into JavaScript object. + * + * @param attributes SET OF PKCS12Attribute (ASN.1 object). + * + * @return the decoded attributes. + */ +function _decodeBagAttributes(attributes) { + var decodedAttrs = {}; + + if(attributes !== undefined) { + for(var i = 0; i < attributes.length; ++i) { + var capture = {}; + var errors = []; + if(!asn1$3.validate(attributes[i], attributeValidator, capture, errors)) { + var error = new Error('Cannot read PKCS#12 BagAttribute.'); + error.errors = errors; + throw error; + } + + var oid = asn1$3.derToOid(capture.oid); + if(pki$1.oids[oid] === undefined) { + // unsupported attribute type, ignore. + continue; + } + + decodedAttrs[pki$1.oids[oid]] = []; + for(var j = 0; j < capture.values.length; ++j) { + decodedAttrs[pki$1.oids[oid]].push(capture.values[j].value); + } + } + } + + return decodedAttrs; +} + +/** + * Wraps a private key and certificate in a PKCS#12 PFX wrapper. If a + * password is provided then the private key will be encrypted. + * + * An entire certificate chain may also be included. To do this, pass + * an array for the "cert" parameter where the first certificate is + * the one that is paired with the private key and each subsequent one + * verifies the previous one. The certificates may be in PEM format or + * have been already parsed by Forge. + * + * @todo implement password-based-encryption for the whole package + * + * @param key the private key. + * @param cert the certificate (may be an array of certificates in order + * to specify a certificate chain). + * @param password the password to use, null for none. + * @param options: + * algorithm the encryption algorithm to use + * ('aes128', 'aes192', 'aes256', '3des'), defaults to 'aes128'. + * count the iteration count to use. + * saltSize the salt size to use. + * useMac true to include a MAC, false not to, defaults to true. + * localKeyId the local key ID to use, in hex. + * friendlyName the friendly name to use. + * generateLocalKeyId true to generate a random local key ID, + * false not to, defaults to true. + * + * @return the PKCS#12 PFX ASN.1 object. + */ +p12.toPkcs12Asn1 = function(key, cert, password, options) { + // set default options + options = options || {}; + options.saltSize = options.saltSize || 8; + options.count = options.count || 2048; + options.algorithm = options.algorithm || options.encAlgorithm || 'aes128'; + if(!('useMac' in options)) { + options.useMac = true; + } + if(!('localKeyId' in options)) { + options.localKeyId = null; + } + if(!('generateLocalKeyId' in options)) { + options.generateLocalKeyId = true; + } + + var localKeyId = options.localKeyId; + var bagAttrs; + if(localKeyId !== null) { + localKeyId = forge$b.util.hexToBytes(localKeyId); + } else if(options.generateLocalKeyId) { + // use SHA-1 of paired cert, if available + if(cert) { + var pairedCert = forge$b.util.isArray(cert) ? cert[0] : cert; + if(typeof pairedCert === 'string') { + pairedCert = pki$1.certificateFromPem(pairedCert); + } + var sha1 = forge$b.md.sha1.create(); + sha1.update(asn1$3.toDer(pki$1.certificateToAsn1(pairedCert)).getBytes()); + localKeyId = sha1.digest().getBytes(); + } else { + // FIXME: consider using SHA-1 of public key (which can be generated + // from private key components), see: cert.generateSubjectKeyIdentifier + // generate random bytes + localKeyId = forge$b.random.getBytes(20); + } + } + + var attrs = []; + if(localKeyId !== null) { + attrs.push( + // localKeyID + asn1$3.create(asn1$3.Class.UNIVERSAL, asn1$3.Type.SEQUENCE, true, [ + // attrId + asn1$3.create(asn1$3.Class.UNIVERSAL, asn1$3.Type.OID, false, + asn1$3.oidToDer(pki$1.oids.localKeyId).getBytes()), + // attrValues + asn1$3.create(asn1$3.Class.UNIVERSAL, asn1$3.Type.SET, true, [ + asn1$3.create(asn1$3.Class.UNIVERSAL, asn1$3.Type.OCTETSTRING, false, + localKeyId) + ]) + ])); + } + if('friendlyName' in options) { + attrs.push( + // friendlyName + asn1$3.create(asn1$3.Class.UNIVERSAL, asn1$3.Type.SEQUENCE, true, [ + // attrId + asn1$3.create(asn1$3.Class.UNIVERSAL, asn1$3.Type.OID, false, + asn1$3.oidToDer(pki$1.oids.friendlyName).getBytes()), + // attrValues + asn1$3.create(asn1$3.Class.UNIVERSAL, asn1$3.Type.SET, true, [ + asn1$3.create(asn1$3.Class.UNIVERSAL, asn1$3.Type.BMPSTRING, false, + options.friendlyName) + ]) + ])); + } + + if(attrs.length > 0) { + bagAttrs = asn1$3.create(asn1$3.Class.UNIVERSAL, asn1$3.Type.SET, true, attrs); + } + + // collect contents for AuthenticatedSafe + var contents = []; + + // create safe bag(s) for certificate chain + var chain = []; + if(cert !== null) { + if(forge$b.util.isArray(cert)) { + chain = cert; + } else { + chain = [cert]; + } + } + + var certSafeBags = []; + for(var i = 0; i < chain.length; ++i) { + // convert cert from PEM as necessary + cert = chain[i]; + if(typeof cert === 'string') { + cert = pki$1.certificateFromPem(cert); + } + + // SafeBag + var certBagAttrs = (i === 0) ? bagAttrs : undefined; + var certAsn1 = pki$1.certificateToAsn1(cert); + var certSafeBag = + asn1$3.create(asn1$3.Class.UNIVERSAL, asn1$3.Type.SEQUENCE, true, [ + // bagId + asn1$3.create(asn1$3.Class.UNIVERSAL, asn1$3.Type.OID, false, + asn1$3.oidToDer(pki$1.oids.certBag).getBytes()), + // bagValue + asn1$3.create(asn1$3.Class.CONTEXT_SPECIFIC, 0, true, [ + // CertBag + asn1$3.create(asn1$3.Class.UNIVERSAL, asn1$3.Type.SEQUENCE, true, [ + // certId + asn1$3.create(asn1$3.Class.UNIVERSAL, asn1$3.Type.OID, false, + asn1$3.oidToDer(pki$1.oids.x509Certificate).getBytes()), + // certValue (x509Certificate) + asn1$3.create(asn1$3.Class.CONTEXT_SPECIFIC, 0, true, [ + asn1$3.create( + asn1$3.Class.UNIVERSAL, asn1$3.Type.OCTETSTRING, false, + asn1$3.toDer(certAsn1).getBytes()) + ])])]), + // bagAttributes (OPTIONAL) + certBagAttrs + ]); + certSafeBags.push(certSafeBag); + } + + if(certSafeBags.length > 0) { + // SafeContents + var certSafeContents = asn1$3.create( + asn1$3.Class.UNIVERSAL, asn1$3.Type.SEQUENCE, true, certSafeBags); + + // ContentInfo + var certCI = + // PKCS#7 ContentInfo + asn1$3.create(asn1$3.Class.UNIVERSAL, asn1$3.Type.SEQUENCE, true, [ + // contentType + asn1$3.create(asn1$3.Class.UNIVERSAL, asn1$3.Type.OID, false, + // OID for the content type is 'data' + asn1$3.oidToDer(pki$1.oids.data).getBytes()), + // content + asn1$3.create(asn1$3.Class.CONTEXT_SPECIFIC, 0, true, [ + asn1$3.create( + asn1$3.Class.UNIVERSAL, asn1$3.Type.OCTETSTRING, false, + asn1$3.toDer(certSafeContents).getBytes()) + ]) + ]); + contents.push(certCI); + } + + // create safe contents for private key + var keyBag = null; + if(key !== null) { + // SafeBag + var pkAsn1 = pki$1.wrapRsaPrivateKey(pki$1.privateKeyToAsn1(key)); + if(password === null) { + // no encryption + keyBag = asn1$3.create(asn1$3.Class.UNIVERSAL, asn1$3.Type.SEQUENCE, true, [ + // bagId + asn1$3.create(asn1$3.Class.UNIVERSAL, asn1$3.Type.OID, false, + asn1$3.oidToDer(pki$1.oids.keyBag).getBytes()), + // bagValue + asn1$3.create(asn1$3.Class.CONTEXT_SPECIFIC, 0, true, [ + // PrivateKeyInfo + pkAsn1 + ]), + // bagAttributes (OPTIONAL) + bagAttrs + ]); + } else { + // encrypted PrivateKeyInfo + keyBag = asn1$3.create(asn1$3.Class.UNIVERSAL, asn1$3.Type.SEQUENCE, true, [ + // bagId + asn1$3.create(asn1$3.Class.UNIVERSAL, asn1$3.Type.OID, false, + asn1$3.oidToDer(pki$1.oids.pkcs8ShroudedKeyBag).getBytes()), + // bagValue + asn1$3.create(asn1$3.Class.CONTEXT_SPECIFIC, 0, true, [ + // EncryptedPrivateKeyInfo + pki$1.encryptPrivateKeyInfo(pkAsn1, password, options) + ]), + // bagAttributes (OPTIONAL) + bagAttrs + ]); + } + + // SafeContents + var keySafeContents = + asn1$3.create(asn1$3.Class.UNIVERSAL, asn1$3.Type.SEQUENCE, true, [keyBag]); + + // ContentInfo + var keyCI = + // PKCS#7 ContentInfo + asn1$3.create(asn1$3.Class.UNIVERSAL, asn1$3.Type.SEQUENCE, true, [ + // contentType + asn1$3.create(asn1$3.Class.UNIVERSAL, asn1$3.Type.OID, false, + // OID for the content type is 'data' + asn1$3.oidToDer(pki$1.oids.data).getBytes()), + // content + asn1$3.create(asn1$3.Class.CONTEXT_SPECIFIC, 0, true, [ + asn1$3.create( + asn1$3.Class.UNIVERSAL, asn1$3.Type.OCTETSTRING, false, + asn1$3.toDer(keySafeContents).getBytes()) + ]) + ]); + contents.push(keyCI); + } + + // create AuthenticatedSafe by stringing together the contents + var safe = asn1$3.create( + asn1$3.Class.UNIVERSAL, asn1$3.Type.SEQUENCE, true, contents); + + var macData; + if(options.useMac) { + // MacData + var sha1 = forge$b.md.sha1.create(); + var macSalt = new forge$b.util.ByteBuffer( + forge$b.random.getBytes(options.saltSize)); + var count = options.count; + // 160-bit key + var key = p12.generateKey(password, macSalt, 3, count, 20); + var mac = forge$b.hmac.create(); + mac.start(sha1, key); + mac.update(asn1$3.toDer(safe).getBytes()); + var macValue = mac.getMac(); + macData = asn1$3.create(asn1$3.Class.UNIVERSAL, asn1$3.Type.SEQUENCE, true, [ + // mac DigestInfo + asn1$3.create(asn1$3.Class.UNIVERSAL, asn1$3.Type.SEQUENCE, true, [ + // digestAlgorithm + asn1$3.create(asn1$3.Class.UNIVERSAL, asn1$3.Type.SEQUENCE, true, [ + // algorithm = SHA-1 + asn1$3.create(asn1$3.Class.UNIVERSAL, asn1$3.Type.OID, false, + asn1$3.oidToDer(pki$1.oids.sha1).getBytes()), + // parameters = Null + asn1$3.create(asn1$3.Class.UNIVERSAL, asn1$3.Type.NULL, false, '') + ]), + // digest + asn1$3.create( + asn1$3.Class.UNIVERSAL, asn1$3.Type.OCTETSTRING, + false, macValue.getBytes()) + ]), + // macSalt OCTET STRING + asn1$3.create( + asn1$3.Class.UNIVERSAL, asn1$3.Type.OCTETSTRING, false, macSalt.getBytes()), + // iterations INTEGER (XXX: Only support count < 65536) + asn1$3.create(asn1$3.Class.UNIVERSAL, asn1$3.Type.INTEGER, false, + asn1$3.integerToDer(count).getBytes() + ) + ]); + } + + // PFX + return asn1$3.create(asn1$3.Class.UNIVERSAL, asn1$3.Type.SEQUENCE, true, [ + // version (3) + asn1$3.create(asn1$3.Class.UNIVERSAL, asn1$3.Type.INTEGER, false, + asn1$3.integerToDer(3).getBytes()), + // PKCS#7 ContentInfo + asn1$3.create(asn1$3.Class.UNIVERSAL, asn1$3.Type.SEQUENCE, true, [ + // contentType + asn1$3.create(asn1$3.Class.UNIVERSAL, asn1$3.Type.OID, false, + // OID for the content type is 'data' + asn1$3.oidToDer(pki$1.oids.data).getBytes()), + // content + asn1$3.create(asn1$3.Class.CONTEXT_SPECIFIC, 0, true, [ + asn1$3.create( + asn1$3.Class.UNIVERSAL, asn1$3.Type.OCTETSTRING, false, + asn1$3.toDer(safe).getBytes()) + ]) + ]), + macData + ]); +}; + +/** + * Derives a PKCS#12 key. + * + * @param password the password to derive the key material from, null or + * undefined for none. + * @param salt the salt, as a ByteBuffer, to use. + * @param id the PKCS#12 ID byte (1 = key material, 2 = IV, 3 = MAC). + * @param iter the iteration count. + * @param n the number of bytes to derive from the password. + * @param md the message digest to use, defaults to SHA-1. + * + * @return a ByteBuffer with the bytes derived from the password. + */ +p12.generateKey = forge$b.pbe.generatePkcs12Key; + +/** + * Javascript implementation of a basic Public Key Infrastructure, including + * support for RSA public and private keys. + * + * @author Dave Longley + * + * Copyright (c) 2010-2013 Digital Bazaar, Inc. + */ + +var forge$a = forge$D; + + + + + + + + + + + +// shortcut for asn.1 API +var asn1$2 = forge$a.asn1; + +/* Public Key Infrastructure (PKI) implementation. */ +var pki = forge$a.pki = forge$a.pki || {}; + +/** + * NOTE: THIS METHOD IS DEPRECATED. Use pem.decode() instead. + * + * Converts PEM-formatted data to DER. + * + * @param pem the PEM-formatted data. + * + * @return the DER-formatted data. + */ +pki.pemToDer = function(pem) { + var msg = forge$a.pem.decode(pem)[0]; + if(msg.procType && msg.procType.type === 'ENCRYPTED') { + throw new Error('Could not convert PEM to DER; PEM is encrypted.'); + } + return forge$a.util.createBuffer(msg.body); +}; + +/** + * Converts an RSA private key from PEM format. + * + * @param pem the PEM-formatted private key. + * + * @return the private key. + */ +pki.privateKeyFromPem = function(pem) { + var msg = forge$a.pem.decode(pem)[0]; + + if(msg.type !== 'PRIVATE KEY' && msg.type !== 'RSA PRIVATE KEY') { + var error = new Error('Could not convert private key from PEM; PEM ' + + 'header type is not "PRIVATE KEY" or "RSA PRIVATE KEY".'); + error.headerType = msg.type; + throw error; + } + if(msg.procType && msg.procType.type === 'ENCRYPTED') { + throw new Error('Could not convert private key from PEM; PEM is encrypted.'); + } + + // convert DER to ASN.1 object + var obj = asn1$2.fromDer(msg.body); + + return pki.privateKeyFromAsn1(obj); +}; + +/** + * Converts an RSA private key to PEM format. + * + * @param key the private key. + * @param maxline the maximum characters per line, defaults to 64. + * + * @return the PEM-formatted private key. + */ +pki.privateKeyToPem = function(key, maxline) { + // convert to ASN.1, then DER, then PEM-encode + var msg = { + type: 'RSA PRIVATE KEY', + body: asn1$2.toDer(pki.privateKeyToAsn1(key)).getBytes() + }; + return forge$a.pem.encode(msg, {maxline: maxline}); +}; + +/** + * Converts a PrivateKeyInfo to PEM format. + * + * @param pki the PrivateKeyInfo. + * @param maxline the maximum characters per line, defaults to 64. + * + * @return the PEM-formatted private key. + */ +pki.privateKeyInfoToPem = function(pki, maxline) { + // convert to DER, then PEM-encode + var msg = { + type: 'PRIVATE KEY', + body: asn1$2.toDer(pki).getBytes() + }; + return forge$a.pem.encode(msg, {maxline: maxline}); +}; + +/** + * A Javascript implementation of Transport Layer Security (TLS). + * + * @author Dave Longley + * + * Copyright (c) 2009-2014 Digital Bazaar, Inc. + * + * The TLS Handshake Protocol involves the following steps: + * + * - Exchange hello messages to agree on algorithms, exchange random values, + * and check for session resumption. + * + * - Exchange the necessary cryptographic parameters to allow the client and + * server to agree on a premaster secret. + * + * - Exchange certificates and cryptographic information to allow the client + * and server to authenticate themselves. + * + * - Generate a master secret from the premaster secret and exchanged random + * values. + * + * - Provide security parameters to the record layer. + * + * - Allow the client and server to verify that their peer has calculated the + * same security parameters and that the handshake occurred without tampering + * by an attacker. + * + * Up to 4 different messages may be sent during a key exchange. The server + * certificate, the server key exchange, the client certificate, and the + * client key exchange. + * + * A typical handshake (from the client's perspective). + * + * 1. Client sends ClientHello. + * 2. Client receives ServerHello. + * 3. Client receives optional Certificate. + * 4. Client receives optional ServerKeyExchange. + * 5. Client receives ServerHelloDone. + * 6. Client sends optional Certificate. + * 7. Client sends ClientKeyExchange. + * 8. Client sends optional CertificateVerify. + * 9. Client sends ChangeCipherSpec. + * 10. Client sends Finished. + * 11. Client receives ChangeCipherSpec. + * 12. Client receives Finished. + * 13. Client sends/receives application data. + * + * To reuse an existing session: + * + * 1. Client sends ClientHello with session ID for reuse. + * 2. Client receives ServerHello with same session ID if reusing. + * 3. Client receives ChangeCipherSpec message if reusing. + * 4. Client receives Finished. + * 5. Client sends ChangeCipherSpec. + * 6. Client sends Finished. + * + * Note: Client ignores HelloRequest if in the middle of a handshake. + * + * Record Layer: + * + * The record layer fragments information blocks into TLSPlaintext records + * carrying data in chunks of 2^14 bytes or less. Client message boundaries are + * not preserved in the record layer (i.e., multiple client messages of the + * same ContentType MAY be coalesced into a single TLSPlaintext record, or a + * single message MAY be fragmented across several records). + * + * struct { + * uint8 major; + * uint8 minor; + * } ProtocolVersion; + * + * struct { + * ContentType type; + * ProtocolVersion version; + * uint16 length; + * opaque fragment[TLSPlaintext.length]; + * } TLSPlaintext; + * + * type: + * The higher-level protocol used to process the enclosed fragment. + * + * version: + * The version of the protocol being employed. TLS Version 1.2 uses version + * {3, 3}. TLS Version 1.0 uses version {3, 1}. Note that a client that + * supports multiple versions of TLS may not know what version will be + * employed before it receives the ServerHello. + * + * length: + * The length (in bytes) of the following TLSPlaintext.fragment. The length + * MUST NOT exceed 2^14 = 16384 bytes. + * + * fragment: + * The application data. This data is transparent and treated as an + * independent block to be dealt with by the higher-level protocol specified + * by the type field. + * + * Implementations MUST NOT send zero-length fragments of Handshake, Alert, or + * ChangeCipherSpec content types. Zero-length fragments of Application data + * MAY be sent as they are potentially useful as a traffic analysis + * countermeasure. + * + * Note: Data of different TLS record layer content types MAY be interleaved. + * Application data is generally of lower precedence for transmission than + * other content types. However, records MUST be delivered to the network in + * the same order as they are protected by the record layer. Recipients MUST + * receive and process interleaved application layer traffic during handshakes + * subsequent to the first one on a connection. + * + * struct { + * ContentType type; // same as TLSPlaintext.type + * ProtocolVersion version;// same as TLSPlaintext.version + * uint16 length; + * opaque fragment[TLSCompressed.length]; + * } TLSCompressed; + * + * length: + * The length (in bytes) of the following TLSCompressed.fragment. + * The length MUST NOT exceed 2^14 + 1024. + * + * fragment: + * The compressed form of TLSPlaintext.fragment. + * + * Note: A CompressionMethod.null operation is an identity operation; no fields + * are altered. In this implementation, since no compression is supported, + * uncompressed records are always the same as compressed records. + * + * Encryption Information: + * + * The encryption and MAC functions translate a TLSCompressed structure into a + * TLSCiphertext. The decryption functions reverse the process. The MAC of the + * record also includes a sequence number so that missing, extra, or repeated + * messages are detectable. + * + * struct { + * ContentType type; + * ProtocolVersion version; + * uint16 length; + * select (SecurityParameters.cipher_type) { + * case stream: GenericStreamCipher; + * case block: GenericBlockCipher; + * case aead: GenericAEADCipher; + * } fragment; + * } TLSCiphertext; + * + * type: + * The type field is identical to TLSCompressed.type. + * + * version: + * The version field is identical to TLSCompressed.version. + * + * length: + * The length (in bytes) of the following TLSCiphertext.fragment. + * The length MUST NOT exceed 2^14 + 2048. + * + * fragment: + * The encrypted form of TLSCompressed.fragment, with the MAC. + * + * Note: Only CBC Block Ciphers are supported by this implementation. + * + * The TLSCompressed.fragment structures are converted to/from block + * TLSCiphertext.fragment structures. + * + * struct { + * opaque IV[SecurityParameters.record_iv_length]; + * block-ciphered struct { + * opaque content[TLSCompressed.length]; + * opaque MAC[SecurityParameters.mac_length]; + * uint8 padding[GenericBlockCipher.padding_length]; + * uint8 padding_length; + * }; + * } GenericBlockCipher; + * + * The MAC is generated as described in Section 6.2.3.1. + * + * IV: + * The Initialization Vector (IV) SHOULD be chosen at random, and MUST be + * unpredictable. Note that in versions of TLS prior to 1.1, there was no + * IV field, and the last ciphertext block of the previous record (the "CBC + * residue") was used as the IV. This was changed to prevent the attacks + * described in [CBCATT]. For block ciphers, the IV length is of length + * SecurityParameters.record_iv_length, which is equal to the + * SecurityParameters.block_size. + * + * padding: + * Padding that is added to force the length of the plaintext to be an + * integral multiple of the block cipher's block length. The padding MAY be + * any length up to 255 bytes, as long as it results in the + * TLSCiphertext.length being an integral multiple of the block length. + * Lengths longer than necessary might be desirable to frustrate attacks on + * a protocol that are based on analysis of the lengths of exchanged + * messages. Each uint8 in the padding data vector MUST be filled with the + * padding length value. The receiver MUST check this padding and MUST use + * the bad_record_mac alert to indicate padding errors. + * + * padding_length: + * The padding length MUST be such that the total size of the + * GenericBlockCipher structure is a multiple of the cipher's block length. + * Legal values range from zero to 255, inclusive. This length specifies the + * length of the padding field exclusive of the padding_length field itself. + * + * The encrypted data length (TLSCiphertext.length) is one more than the sum of + * SecurityParameters.block_length, TLSCompressed.length, + * SecurityParameters.mac_length, and padding_length. + * + * Example: If the block length is 8 bytes, the content length + * (TLSCompressed.length) is 61 bytes, and the MAC length is 20 bytes, then the + * length before padding is 82 bytes (this does not include the IV. Thus, the + * padding length modulo 8 must be equal to 6 in order to make the total length + * an even multiple of 8 bytes (the block length). The padding length can be + * 6, 14, 22, and so on, through 254. If the padding length were the minimum + * necessary, 6, the padding would be 6 bytes, each containing the value 6. + * Thus, the last 8 octets of the GenericBlockCipher before block encryption + * would be xx 06 06 06 06 06 06 06, where xx is the last octet of the MAC. + * + * Note: With block ciphers in CBC mode (Cipher Block Chaining), it is critical + * that the entire plaintext of the record be known before any ciphertext is + * transmitted. Otherwise, it is possible for the attacker to mount the attack + * described in [CBCATT]. + * + * Implementation note: Canvel et al. [CBCTIME] have demonstrated a timing + * attack on CBC padding based on the time required to compute the MAC. In + * order to defend against this attack, implementations MUST ensure that + * record processing time is essentially the same whether or not the padding + * is correct. In general, the best way to do this is to compute the MAC even + * if the padding is incorrect, and only then reject the packet. For instance, + * if the pad appears to be incorrect, the implementation might assume a + * zero-length pad and then compute the MAC. This leaves a small timing + * channel, since MAC performance depends, to some extent, on the size of the + * data fragment, but it is not believed to be large enough to be exploitable, + * due to the large block size of existing MACs and the small size of the + * timing signal. + */ + +var forge$9 = forge$D; + + + + + + + + + +/** + * Generates pseudo random bytes by mixing the result of two hash functions, + * MD5 and SHA-1. + * + * prf_TLS1(secret, label, seed) = + * P_MD5(S1, label + seed) XOR P_SHA-1(S2, label + seed); + * + * Each P_hash function functions as follows: + * + * P_hash(secret, seed) = HMAC_hash(secret, A(1) + seed) + + * HMAC_hash(secret, A(2) + seed) + + * HMAC_hash(secret, A(3) + seed) + ... + * A() is defined as: + * A(0) = seed + * A(i) = HMAC_hash(secret, A(i-1)) + * + * The '+' operator denotes concatenation. + * + * As many iterations A(N) as are needed are performed to generate enough + * pseudo random byte output. If an iteration creates more data than is + * necessary, then it is truncated. + * + * Therefore: + * A(1) = HMAC_hash(secret, A(0)) + * = HMAC_hash(secret, seed) + * A(2) = HMAC_hash(secret, A(1)) + * = HMAC_hash(secret, HMAC_hash(secret, seed)) + * + * Therefore: + * P_hash(secret, seed) = + * HMAC_hash(secret, HMAC_hash(secret, A(0)) + seed) + + * HMAC_hash(secret, HMAC_hash(secret, A(1)) + seed) + + * ... + * + * Therefore: + * P_hash(secret, seed) = + * HMAC_hash(secret, HMAC_hash(secret, seed) + seed) + + * HMAC_hash(secret, HMAC_hash(secret, HMAC_hash(secret, seed)) + seed) + + * ... + * + * @param secret the secret to use. + * @param label the label to use. + * @param seed the seed value to use. + * @param length the number of bytes to generate. + * + * @return the pseudo random bytes in a byte buffer. + */ +var prf_TLS1 = function(secret, label, seed, length) { + var rval = forge$9.util.createBuffer(); + + /* For TLS 1.0, the secret is split in half, into two secrets of equal + length. If the secret has an odd length then the last byte of the first + half will be the same as the first byte of the second. The length of the + two secrets is half of the secret rounded up. */ + var idx = (secret.length >> 1); + var slen = idx + (secret.length & 1); + var s1 = secret.substr(0, slen); + var s2 = secret.substr(idx, slen); + var ai = forge$9.util.createBuffer(); + var hmac = forge$9.hmac.create(); + seed = label + seed; + + // determine the number of iterations that must be performed to generate + // enough output bytes, md5 creates 16 byte hashes, sha1 creates 20 + var md5itr = Math.ceil(length / 16); + var sha1itr = Math.ceil(length / 20); + + // do md5 iterations + hmac.start('MD5', s1); + var md5bytes = forge$9.util.createBuffer(); + ai.putBytes(seed); + for(var i = 0; i < md5itr; ++i) { + // HMAC_hash(secret, A(i-1)) + hmac.start(null, null); + hmac.update(ai.getBytes()); + ai.putBuffer(hmac.digest()); + + // HMAC_hash(secret, A(i) + seed) + hmac.start(null, null); + hmac.update(ai.bytes() + seed); + md5bytes.putBuffer(hmac.digest()); + } + + // do sha1 iterations + hmac.start('SHA1', s2); + var sha1bytes = forge$9.util.createBuffer(); + ai.clear(); + ai.putBytes(seed); + for(var i = 0; i < sha1itr; ++i) { + // HMAC_hash(secret, A(i-1)) + hmac.start(null, null); + hmac.update(ai.getBytes()); + ai.putBuffer(hmac.digest()); + + // HMAC_hash(secret, A(i) + seed) + hmac.start(null, null); + hmac.update(ai.bytes() + seed); + sha1bytes.putBuffer(hmac.digest()); + } + + // XOR the md5 bytes with the sha1 bytes + rval.putBytes(forge$9.util.xorBytes( + md5bytes.getBytes(), sha1bytes.getBytes(), length)); + + return rval; +}; + +/** + * Gets a MAC for a record using the SHA-1 hash algorithm. + * + * @param key the mac key. + * @param state the sequence number (array of two 32-bit integers). + * @param record the record. + * + * @return the sha-1 hash (20 bytes) for the given record. + */ +var hmac_sha1 = function(key, seqNum, record) { + /* MAC is computed like so: + HMAC_hash( + key, seqNum + + TLSCompressed.type + + TLSCompressed.version + + TLSCompressed.length + + TLSCompressed.fragment) + */ + var hmac = forge$9.hmac.create(); + hmac.start('SHA1', key); + var b = forge$9.util.createBuffer(); + b.putInt32(seqNum[0]); + b.putInt32(seqNum[1]); + b.putByte(record.type); + b.putByte(record.version.major); + b.putByte(record.version.minor); + b.putInt16(record.length); + b.putBytes(record.fragment.bytes()); + hmac.update(b.getBytes()); + return hmac.digest().getBytes(); +}; + +/** + * Compresses the TLSPlaintext record into a TLSCompressed record using the + * deflate algorithm. + * + * @param c the TLS connection. + * @param record the TLSPlaintext record to compress. + * @param s the ConnectionState to use. + * + * @return true on success, false on failure. + */ +var deflate = function(c, record, s) { + var rval = false; + + try { + var bytes = c.deflate(record.fragment.getBytes()); + record.fragment = forge$9.util.createBuffer(bytes); + record.length = bytes.length; + rval = true; + } catch(ex) { + // deflate error, fail out + } + + return rval; +}; + +/** + * Decompresses the TLSCompressed record into a TLSPlaintext record using the + * deflate algorithm. + * + * @param c the TLS connection. + * @param record the TLSCompressed record to decompress. + * @param s the ConnectionState to use. + * + * @return true on success, false on failure. + */ +var inflate = function(c, record, s) { + var rval = false; + + try { + var bytes = c.inflate(record.fragment.getBytes()); + record.fragment = forge$9.util.createBuffer(bytes); + record.length = bytes.length; + rval = true; + } catch(ex) { + // inflate error, fail out + } + + return rval; +}; + +/** + * Reads a TLS variable-length vector from a byte buffer. + * + * Variable-length vectors are defined by specifying a subrange of legal + * lengths, inclusively, using the notation . When these are + * encoded, the actual length precedes the vector's contents in the byte + * stream. The length will be in the form of a number consuming as many bytes + * as required to hold the vector's specified maximum (ceiling) length. A + * variable-length vector with an actual length field of zero is referred to + * as an empty vector. + * + * @param b the byte buffer. + * @param lenBytes the number of bytes required to store the length. + * + * @return the resulting byte buffer. + */ +var readVector = function(b, lenBytes) { + var len = 0; + switch(lenBytes) { + case 1: + len = b.getByte(); + break; + case 2: + len = b.getInt16(); + break; + case 3: + len = b.getInt24(); + break; + case 4: + len = b.getInt32(); + break; + } + + // read vector bytes into a new buffer + return forge$9.util.createBuffer(b.getBytes(len)); +}; + +/** + * Writes a TLS variable-length vector to a byte buffer. + * + * @param b the byte buffer. + * @param lenBytes the number of bytes required to store the length. + * @param v the byte buffer vector. + */ +var writeVector = function(b, lenBytes, v) { + // encode length at the start of the vector, where the number of bytes for + // the length is the maximum number of bytes it would take to encode the + // vector's ceiling + b.putInt(v.length(), lenBytes << 3); + b.putBuffer(v); +}; + +/** + * The tls implementation. + */ +var tls$1 = {}; + +/** + * Version: TLS 1.2 = 3.3, TLS 1.1 = 3.2, TLS 1.0 = 3.1. Both TLS 1.1 and + * TLS 1.2 were still too new (ie: openSSL didn't implement them) at the time + * of this implementation so TLS 1.0 was implemented instead. + */ +tls$1.Versions = { + TLS_1_0: {major: 3, minor: 1}, + TLS_1_1: {major: 3, minor: 2}, + TLS_1_2: {major: 3, minor: 3} +}; +tls$1.SupportedVersions = [ + tls$1.Versions.TLS_1_1, + tls$1.Versions.TLS_1_0 +]; +tls$1.Version = tls$1.SupportedVersions[0]; + +/** + * Maximum fragment size. True maximum is 16384, but we fragment before that + * to allow for unusual small increases during compression. + */ +tls$1.MaxFragment = 16384 - 1024; + +/** + * Whether this entity is considered the "client" or "server". + * enum { server, client } ConnectionEnd; + */ +tls$1.ConnectionEnd = { + server: 0, + client: 1 +}; + +/** + * Pseudo-random function algorithm used to generate keys from the master + * secret. + * enum { tls_prf_sha256 } PRFAlgorithm; + */ +tls$1.PRFAlgorithm = { + tls_prf_sha256: 0 +}; + +/** + * Bulk encryption algorithms. + * enum { null, rc4, des3, aes } BulkCipherAlgorithm; + */ +tls$1.BulkCipherAlgorithm = { + none: null, + rc4: 0, + des3: 1, + aes: 2 +}; + +/** + * Cipher types. + * enum { stream, block, aead } CipherType; + */ +tls$1.CipherType = { + stream: 0, + block: 1, + aead: 2 +}; + +/** + * MAC (Message Authentication Code) algorithms. + * enum { null, hmac_md5, hmac_sha1, hmac_sha256, + * hmac_sha384, hmac_sha512} MACAlgorithm; + */ +tls$1.MACAlgorithm = { + none: null, + hmac_md5: 0, + hmac_sha1: 1, + hmac_sha256: 2, + hmac_sha384: 3, + hmac_sha512: 4 +}; + +/** + * Compression algorithms. + * enum { null(0), deflate(1), (255) } CompressionMethod; + */ +tls$1.CompressionMethod = { + none: 0, + deflate: 1 +}; + +/** + * TLS record content types. + * enum { + * change_cipher_spec(20), alert(21), handshake(22), + * application_data(23), (255) + * } ContentType; + */ +tls$1.ContentType = { + change_cipher_spec: 20, + alert: 21, + handshake: 22, + application_data: 23, + heartbeat: 24 +}; + +/** + * TLS handshake types. + * enum { + * hello_request(0), client_hello(1), server_hello(2), + * certificate(11), server_key_exchange (12), + * certificate_request(13), server_hello_done(14), + * certificate_verify(15), client_key_exchange(16), + * finished(20), (255) + * } HandshakeType; + */ +tls$1.HandshakeType = { + hello_request: 0, + client_hello: 1, + server_hello: 2, + certificate: 11, + server_key_exchange: 12, + certificate_request: 13, + server_hello_done: 14, + certificate_verify: 15, + client_key_exchange: 16, + finished: 20 +}; + +/** + * TLS Alert Protocol. + * + * enum { warning(1), fatal(2), (255) } AlertLevel; + * + * enum { + * close_notify(0), + * unexpected_message(10), + * bad_record_mac(20), + * decryption_failed(21), + * record_overflow(22), + * decompression_failure(30), + * handshake_failure(40), + * bad_certificate(42), + * unsupported_certificate(43), + * certificate_revoked(44), + * certificate_expired(45), + * certificate_unknown(46), + * illegal_parameter(47), + * unknown_ca(48), + * access_denied(49), + * decode_error(50), + * decrypt_error(51), + * export_restriction(60), + * protocol_version(70), + * insufficient_security(71), + * internal_error(80), + * user_canceled(90), + * no_renegotiation(100), + * (255) + * } AlertDescription; + * + * struct { + * AlertLevel level; + * AlertDescription description; + * } Alert; + */ +tls$1.Alert = {}; +tls$1.Alert.Level = { + warning: 1, + fatal: 2 +}; +tls$1.Alert.Description = { + close_notify: 0, + unexpected_message: 10, + bad_record_mac: 20, + decryption_failed: 21, + record_overflow: 22, + decompression_failure: 30, + handshake_failure: 40, + bad_certificate: 42, + unsupported_certificate: 43, + certificate_revoked: 44, + certificate_expired: 45, + certificate_unknown: 46, + illegal_parameter: 47, + unknown_ca: 48, + access_denied: 49, + decode_error: 50, + decrypt_error: 51, + export_restriction: 60, + protocol_version: 70, + insufficient_security: 71, + internal_error: 80, + user_canceled: 90, + no_renegotiation: 100 +}; + +/** + * TLS Heartbeat Message types. + * enum { + * heartbeat_request(1), + * heartbeat_response(2), + * (255) + * } HeartbeatMessageType; + */ +tls$1.HeartbeatMessageType = { + heartbeat_request: 1, + heartbeat_response: 2 +}; + +/** + * Supported cipher suites. + */ +tls$1.CipherSuites = {}; + +/** + * Gets a supported cipher suite from its 2 byte ID. + * + * @param twoBytes two bytes in a string. + * + * @return the matching supported cipher suite or null. + */ +tls$1.getCipherSuite = function(twoBytes) { + var rval = null; + for(var key in tls$1.CipherSuites) { + var cs = tls$1.CipherSuites[key]; + if(cs.id[0] === twoBytes.charCodeAt(0) && + cs.id[1] === twoBytes.charCodeAt(1)) { + rval = cs; + break; + } + } + return rval; +}; + +/** + * Called when an unexpected record is encountered. + * + * @param c the connection. + * @param record the record. + */ +tls$1.handleUnexpected = function(c, record) { + // if connection is client and closed, ignore unexpected messages + var ignore = (!c.open && c.entity === tls$1.ConnectionEnd.client); + if(!ignore) { + c.error(c, { + message: 'Unexpected message. Received TLS record out of order.', + send: true, + alert: { + level: tls$1.Alert.Level.fatal, + description: tls$1.Alert.Description.unexpected_message + } + }); + } +}; + +/** + * Called when a client receives a HelloRequest record. + * + * @param c the connection. + * @param record the record. + * @param length the length of the handshake message. + */ +tls$1.handleHelloRequest = function(c, record, length) { + // ignore renegotiation requests from the server during a handshake, but + // if handshaking, send a warning alert that renegotation is denied + if(!c.handshaking && c.handshakes > 0) { + // send alert warning + tls$1.queue(c, tls$1.createAlert(c, { + level: tls$1.Alert.Level.warning, + description: tls$1.Alert.Description.no_renegotiation + })); + tls$1.flush(c); + } + + // continue + c.process(); +}; + +/** + * Parses a hello message from a ClientHello or ServerHello record. + * + * @param record the record to parse. + * + * @return the parsed message. + */ +tls$1.parseHelloMessage = function(c, record, length) { + var msg = null; + + var client = (c.entity === tls$1.ConnectionEnd.client); + + // minimum of 38 bytes in message + if(length < 38) { + c.error(c, { + message: client ? + 'Invalid ServerHello message. Message too short.' : + 'Invalid ClientHello message. Message too short.', + send: true, + alert: { + level: tls$1.Alert.Level.fatal, + description: tls$1.Alert.Description.illegal_parameter + } + }); + } else { + // use 'remaining' to calculate # of remaining bytes in the message + var b = record.fragment; + var remaining = b.length(); + msg = { + version: { + major: b.getByte(), + minor: b.getByte() + }, + random: forge$9.util.createBuffer(b.getBytes(32)), + session_id: readVector(b, 1), + extensions: [] + }; + if(client) { + msg.cipher_suite = b.getBytes(2); + msg.compression_method = b.getByte(); + } else { + msg.cipher_suites = readVector(b, 2); + msg.compression_methods = readVector(b, 1); + } + + // read extensions if there are any bytes left in the message + remaining = length - (remaining - b.length()); + if(remaining > 0) { + // parse extensions + var exts = readVector(b, 2); + while(exts.length() > 0) { + msg.extensions.push({ + type: [exts.getByte(), exts.getByte()], + data: readVector(exts, 2) + }); + } + + // TODO: make extension support modular + if(!client) { + for(var i = 0; i < msg.extensions.length; ++i) { + var ext = msg.extensions[i]; + + // support SNI extension + if(ext.type[0] === 0x00 && ext.type[1] === 0x00) { + // get server name list + var snl = readVector(ext.data, 2); + while(snl.length() > 0) { + // read server name type + var snType = snl.getByte(); + + // only HostName type (0x00) is known, break out if + // another type is detected + if(snType !== 0x00) { + break; + } + + // add host name to server name list + c.session.extensions.server_name.serverNameList.push( + readVector(snl, 2).getBytes()); + } + } + } + } + } + + // version already set, do not allow version change + if(c.session.version) { + if(msg.version.major !== c.session.version.major || + msg.version.minor !== c.session.version.minor) { + return c.error(c, { + message: 'TLS version change is disallowed during renegotiation.', + send: true, + alert: { + level: tls$1.Alert.Level.fatal, + description: tls$1.Alert.Description.protocol_version + } + }); + } + } + + // get the chosen (ServerHello) cipher suite + if(client) { + // FIXME: should be checking configured acceptable cipher suites + c.session.cipherSuite = tls$1.getCipherSuite(msg.cipher_suite); + } else { + // get a supported preferred (ClientHello) cipher suite + // choose the first supported cipher suite + var tmp = forge$9.util.createBuffer(msg.cipher_suites.bytes()); + while(tmp.length() > 0) { + // FIXME: should be checking configured acceptable suites + // cipher suites take up 2 bytes + c.session.cipherSuite = tls$1.getCipherSuite(tmp.getBytes(2)); + if(c.session.cipherSuite !== null) { + break; + } + } + } + + // cipher suite not supported + if(c.session.cipherSuite === null) { + return c.error(c, { + message: 'No cipher suites in common.', + send: true, + alert: { + level: tls$1.Alert.Level.fatal, + description: tls$1.Alert.Description.handshake_failure + }, + cipherSuite: forge$9.util.bytesToHex(msg.cipher_suite) + }); + } + + // TODO: handle compression methods + if(client) { + c.session.compressionMethod = msg.compression_method; + } else { + // no compression + c.session.compressionMethod = tls$1.CompressionMethod.none; + } + } + + return msg; +}; + +/** + * Creates security parameters for the given connection based on the given + * hello message. + * + * @param c the TLS connection. + * @param msg the hello message. + */ +tls$1.createSecurityParameters = function(c, msg) { + /* Note: security params are from TLS 1.2, some values like prf_algorithm + are ignored for TLS 1.0/1.1 and the builtin as specified in the spec is + used. */ + + // TODO: handle other options from server when more supported + + // get client and server randoms + var client = (c.entity === tls$1.ConnectionEnd.client); + var msgRandom = msg.random.bytes(); + var cRandom = client ? c.session.sp.client_random : msgRandom; + var sRandom = client ? msgRandom : tls$1.createRandom().getBytes(); + + // create new security parameters + c.session.sp = { + entity: c.entity, + prf_algorithm: tls$1.PRFAlgorithm.tls_prf_sha256, + bulk_cipher_algorithm: null, + cipher_type: null, + enc_key_length: null, + block_length: null, + fixed_iv_length: null, + record_iv_length: null, + mac_algorithm: null, + mac_length: null, + mac_key_length: null, + compression_algorithm: c.session.compressionMethod, + pre_master_secret: null, + master_secret: null, + client_random: cRandom, + server_random: sRandom + }; +}; + +/** + * Called when a client receives a ServerHello record. + * + * When a ServerHello message will be sent: + * The server will send this message in response to a client hello message + * when it was able to find an acceptable set of algorithms. If it cannot + * find such a match, it will respond with a handshake failure alert. + * + * uint24 length; + * struct { + * ProtocolVersion server_version; + * Random random; + * SessionID session_id; + * CipherSuite cipher_suite; + * CompressionMethod compression_method; + * select(extensions_present) { + * case false: + * struct {}; + * case true: + * Extension extensions<0..2^16-1>; + * }; + * } ServerHello; + * + * @param c the connection. + * @param record the record. + * @param length the length of the handshake message. + */ +tls$1.handleServerHello = function(c, record, length) { + var msg = tls$1.parseHelloMessage(c, record, length); + if(c.fail) { + return; + } + + // ensure server version is compatible + if(msg.version.minor <= c.version.minor) { + c.version.minor = msg.version.minor; + } else { + return c.error(c, { + message: 'Incompatible TLS version.', + send: true, + alert: { + level: tls$1.Alert.Level.fatal, + description: tls$1.Alert.Description.protocol_version + } + }); + } + + // indicate session version has been set + c.session.version = c.version; + + // get the session ID from the message + var sessionId = msg.session_id.bytes(); + + // if the session ID is not blank and matches the cached one, resume + // the session + if(sessionId.length > 0 && sessionId === c.session.id) { + // resuming session, expect a ChangeCipherSpec next + c.expect = SCC; + c.session.resuming = true; + + // get new server random + c.session.sp.server_random = msg.random.bytes(); + } else { + // not resuming, expect a server Certificate message next + c.expect = SCE; + c.session.resuming = false; + + // create new security parameters + tls$1.createSecurityParameters(c, msg); + } + + // set new session ID + c.session.id = sessionId; + + // continue + c.process(); +}; + +/** + * Called when a server receives a ClientHello record. + * + * When a ClientHello message will be sent: + * When a client first connects to a server it is required to send the + * client hello as its first message. The client can also send a client + * hello in response to a hello request or on its own initiative in order + * to renegotiate the security parameters in an existing connection. + * + * @param c the connection. + * @param record the record. + * @param length the length of the handshake message. + */ +tls$1.handleClientHello = function(c, record, length) { + var msg = tls$1.parseHelloMessage(c, record, length); + if(c.fail) { + return; + } + + // get the session ID from the message + var sessionId = msg.session_id.bytes(); + + // see if the given session ID is in the cache + var session = null; + if(c.sessionCache) { + session = c.sessionCache.getSession(sessionId); + if(session === null) { + // session ID not found + sessionId = ''; + } else if(session.version.major !== msg.version.major || + session.version.minor > msg.version.minor) { + // if session version is incompatible with client version, do not resume + session = null; + sessionId = ''; + } + } + + // no session found to resume, generate a new session ID + if(sessionId.length === 0) { + sessionId = forge$9.random.getBytes(32); + } + + // update session + c.session.id = sessionId; + c.session.clientHelloVersion = msg.version; + c.session.sp = {}; + if(session) { + // use version and security parameters from resumed session + c.version = c.session.version = session.version; + c.session.sp = session.sp; + } else { + // use highest compatible minor version + var version; + for(var i = 1; i < tls$1.SupportedVersions.length; ++i) { + version = tls$1.SupportedVersions[i]; + if(version.minor <= msg.version.minor) { + break; + } + } + c.version = {major: version.major, minor: version.minor}; + c.session.version = c.version; + } + + // if a session is set, resume it + if(session !== null) { + // resuming session, expect a ChangeCipherSpec next + c.expect = CCC; + c.session.resuming = true; + + // get new client random + c.session.sp.client_random = msg.random.bytes(); + } else { + // not resuming, expect a Certificate or ClientKeyExchange + c.expect = (c.verifyClient !== false) ? CCE : CKE; + c.session.resuming = false; + + // create new security parameters + tls$1.createSecurityParameters(c, msg); + } + + // connection now open + c.open = true; + + // queue server hello + tls$1.queue(c, tls$1.createRecord(c, { + type: tls$1.ContentType.handshake, + data: tls$1.createServerHello(c) + })); + + if(c.session.resuming) { + // queue change cipher spec message + tls$1.queue(c, tls$1.createRecord(c, { + type: tls$1.ContentType.change_cipher_spec, + data: tls$1.createChangeCipherSpec() + })); + + // create pending state + c.state.pending = tls$1.createConnectionState(c); + + // change current write state to pending write state + c.state.current.write = c.state.pending.write; + + // queue finished + tls$1.queue(c, tls$1.createRecord(c, { + type: tls$1.ContentType.handshake, + data: tls$1.createFinished(c) + })); + } else { + // queue server certificate + tls$1.queue(c, tls$1.createRecord(c, { + type: tls$1.ContentType.handshake, + data: tls$1.createCertificate(c) + })); + + if(!c.fail) { + // queue server key exchange + tls$1.queue(c, tls$1.createRecord(c, { + type: tls$1.ContentType.handshake, + data: tls$1.createServerKeyExchange(c) + })); + + // request client certificate if set + if(c.verifyClient !== false) { + // queue certificate request + tls$1.queue(c, tls$1.createRecord(c, { + type: tls$1.ContentType.handshake, + data: tls$1.createCertificateRequest(c) + })); + } + + // queue server hello done + tls$1.queue(c, tls$1.createRecord(c, { + type: tls$1.ContentType.handshake, + data: tls$1.createServerHelloDone(c) + })); + } + } + + // send records + tls$1.flush(c); + + // continue + c.process(); +}; + +/** + * Called when a client receives a Certificate record. + * + * When this message will be sent: + * The server must send a certificate whenever the agreed-upon key exchange + * method is not an anonymous one. This message will always immediately + * follow the server hello message. + * + * Meaning of this message: + * The certificate type must be appropriate for the selected cipher suite's + * key exchange algorithm, and is generally an X.509v3 certificate. It must + * contain a key which matches the key exchange method, as follows. Unless + * otherwise specified, the signing algorithm for the certificate must be + * the same as the algorithm for the certificate key. Unless otherwise + * specified, the public key may be of any length. + * + * opaque ASN.1Cert<1..2^24-1>; + * struct { + * ASN.1Cert certificate_list<1..2^24-1>; + * } Certificate; + * + * @param c the connection. + * @param record the record. + * @param length the length of the handshake message. + */ +tls$1.handleCertificate = function(c, record, length) { + // minimum of 3 bytes in message + if(length < 3) { + return c.error(c, { + message: 'Invalid Certificate message. Message too short.', + send: true, + alert: { + level: tls$1.Alert.Level.fatal, + description: tls$1.Alert.Description.illegal_parameter + } + }); + } + + var b = record.fragment; + var msg = { + certificate_list: readVector(b, 3) + }; + + /* The sender's certificate will be first in the list (chain), each + subsequent one that follows will certify the previous one, but root + certificates (self-signed) that specify the certificate authority may + be omitted under the assumption that clients must already possess it. */ + var cert, asn1; + var certs = []; + try { + while(msg.certificate_list.length() > 0) { + // each entry in msg.certificate_list is a vector with 3 len bytes + cert = readVector(msg.certificate_list, 3); + asn1 = forge$9.asn1.fromDer(cert); + cert = forge$9.pki.certificateFromAsn1(asn1, true); + certs.push(cert); + } + } catch(ex) { + return c.error(c, { + message: 'Could not parse certificate list.', + cause: ex, + send: true, + alert: { + level: tls$1.Alert.Level.fatal, + description: tls$1.Alert.Description.bad_certificate + } + }); + } + + // ensure at least 1 certificate was provided if in client-mode + // or if verifyClient was set to true to require a certificate + // (as opposed to 'optional') + var client = (c.entity === tls$1.ConnectionEnd.client); + if((client || c.verifyClient === true) && certs.length === 0) { + // error, no certificate + c.error(c, { + message: client ? + 'No server certificate provided.' : + 'No client certificate provided.', + send: true, + alert: { + level: tls$1.Alert.Level.fatal, + description: tls$1.Alert.Description.illegal_parameter + } + }); + } else if(certs.length === 0) { + // no certs to verify + // expect a ServerKeyExchange or ClientKeyExchange message next + c.expect = client ? SKE : CKE; + } else { + // save certificate in session + if(client) { + c.session.serverCertificate = certs[0]; + } else { + c.session.clientCertificate = certs[0]; + } + + if(tls$1.verifyCertificateChain(c, certs)) { + // expect a ServerKeyExchange or ClientKeyExchange message next + c.expect = client ? SKE : CKE; + } + } + + // continue + c.process(); +}; + +/** + * Called when a client receives a ServerKeyExchange record. + * + * When this message will be sent: + * This message will be sent immediately after the server certificate + * message (or the server hello message, if this is an anonymous + * negotiation). + * + * The server key exchange message is sent by the server only when the + * server certificate message (if sent) does not contain enough data to + * allow the client to exchange a premaster secret. + * + * Meaning of this message: + * This message conveys cryptographic information to allow the client to + * communicate the premaster secret: either an RSA public key to encrypt + * the premaster secret with, or a Diffie-Hellman public key with which the + * client can complete a key exchange (with the result being the premaster + * secret.) + * + * enum { + * dhe_dss, dhe_rsa, dh_anon, rsa, dh_dss, dh_rsa + * } KeyExchangeAlgorithm; + * + * struct { + * opaque dh_p<1..2^16-1>; + * opaque dh_g<1..2^16-1>; + * opaque dh_Ys<1..2^16-1>; + * } ServerDHParams; + * + * struct { + * select(KeyExchangeAlgorithm) { + * case dh_anon: + * ServerDHParams params; + * case dhe_dss: + * case dhe_rsa: + * ServerDHParams params; + * digitally-signed struct { + * opaque client_random[32]; + * opaque server_random[32]; + * ServerDHParams params; + * } signed_params; + * case rsa: + * case dh_dss: + * case dh_rsa: + * struct {}; + * }; + * } ServerKeyExchange; + * + * @param c the connection. + * @param record the record. + * @param length the length of the handshake message. + */ +tls$1.handleServerKeyExchange = function(c, record, length) { + // this implementation only supports RSA, no Diffie-Hellman support + // so any length > 0 is invalid + if(length > 0) { + return c.error(c, { + message: 'Invalid key parameters. Only RSA is supported.', + send: true, + alert: { + level: tls$1.Alert.Level.fatal, + description: tls$1.Alert.Description.unsupported_certificate + } + }); + } + + // expect an optional CertificateRequest message next + c.expect = SCR; + + // continue + c.process(); +}; + +/** + * Called when a client receives a ClientKeyExchange record. + * + * @param c the connection. + * @param record the record. + * @param length the length of the handshake message. + */ +tls$1.handleClientKeyExchange = function(c, record, length) { + // this implementation only supports RSA, no Diffie-Hellman support + // so any length < 48 is invalid + if(length < 48) { + return c.error(c, { + message: 'Invalid key parameters. Only RSA is supported.', + send: true, + alert: { + level: tls$1.Alert.Level.fatal, + description: tls$1.Alert.Description.unsupported_certificate + } + }); + } + + var b = record.fragment; + var msg = { + enc_pre_master_secret: readVector(b, 2).getBytes() + }; + + // do rsa decryption + var privateKey = null; + if(c.getPrivateKey) { + try { + privateKey = c.getPrivateKey(c, c.session.serverCertificate); + privateKey = forge$9.pki.privateKeyFromPem(privateKey); + } catch(ex) { + c.error(c, { + message: 'Could not get private key.', + cause: ex, + send: true, + alert: { + level: tls$1.Alert.Level.fatal, + description: tls$1.Alert.Description.internal_error + } + }); + } + } + + if(privateKey === null) { + return c.error(c, { + message: 'No private key set.', + send: true, + alert: { + level: tls$1.Alert.Level.fatal, + description: tls$1.Alert.Description.internal_error + } + }); + } + + try { + // decrypt 48-byte pre-master secret + var sp = c.session.sp; + sp.pre_master_secret = privateKey.decrypt(msg.enc_pre_master_secret); + + // ensure client hello version matches first 2 bytes + var version = c.session.clientHelloVersion; + if(version.major !== sp.pre_master_secret.charCodeAt(0) || + version.minor !== sp.pre_master_secret.charCodeAt(1)) { + // error, do not send alert (see BLEI attack below) + throw new Error('TLS version rollback attack detected.'); + } + } catch(ex) { + /* Note: Daniel Bleichenbacher [BLEI] can be used to attack a + TLS server which is using PKCS#1 encoded RSA, so instead of + failing here, we generate 48 random bytes and use that as + the pre-master secret. */ + sp.pre_master_secret = forge$9.random.getBytes(48); + } + + // expect a CertificateVerify message if a Certificate was received that + // does not have fixed Diffie-Hellman params, otherwise expect + // ChangeCipherSpec + c.expect = CCC; + if(c.session.clientCertificate !== null) { + // only RSA support, so expect CertificateVerify + // TODO: support Diffie-Hellman + c.expect = CCV; + } + + // continue + c.process(); +}; + +/** + * Called when a client receives a CertificateRequest record. + * + * When this message will be sent: + * A non-anonymous server can optionally request a certificate from the + * client, if appropriate for the selected cipher suite. This message, if + * sent, will immediately follow the Server Key Exchange message (if it is + * sent; otherwise, the Server Certificate message). + * + * enum { + * rsa_sign(1), dss_sign(2), rsa_fixed_dh(3), dss_fixed_dh(4), + * rsa_ephemeral_dh_RESERVED(5), dss_ephemeral_dh_RESERVED(6), + * fortezza_dms_RESERVED(20), (255) + * } ClientCertificateType; + * + * opaque DistinguishedName<1..2^16-1>; + * + * struct { + * ClientCertificateType certificate_types<1..2^8-1>; + * SignatureAndHashAlgorithm supported_signature_algorithms<2^16-1>; + * DistinguishedName certificate_authorities<0..2^16-1>; + * } CertificateRequest; + * + * @param c the connection. + * @param record the record. + * @param length the length of the handshake message. + */ +tls$1.handleCertificateRequest = function(c, record, length) { + // minimum of 3 bytes in message + if(length < 3) { + return c.error(c, { + message: 'Invalid CertificateRequest. Message too short.', + send: true, + alert: { + level: tls$1.Alert.Level.fatal, + description: tls$1.Alert.Description.illegal_parameter + } + }); + } + + // TODO: TLS 1.2+ has different format including + // SignatureAndHashAlgorithm after cert types + var b = record.fragment; + var msg = { + certificate_types: readVector(b, 1), + certificate_authorities: readVector(b, 2) + }; + + // save certificate request in session + c.session.certificateRequest = msg; + + // expect a ServerHelloDone message next + c.expect = SHD; + + // continue + c.process(); +}; + +/** + * Called when a server receives a CertificateVerify record. + * + * @param c the connection. + * @param record the record. + * @param length the length of the handshake message. + */ +tls$1.handleCertificateVerify = function(c, record, length) { + if(length < 2) { + return c.error(c, { + message: 'Invalid CertificateVerify. Message too short.', + send: true, + alert: { + level: tls$1.Alert.Level.fatal, + description: tls$1.Alert.Description.illegal_parameter + } + }); + } + + // rewind to get full bytes for message so it can be manually + // digested below (special case for CertificateVerify messages because + // they must be digested *after* handling as opposed to all others) + var b = record.fragment; + b.read -= 4; + var msgBytes = b.bytes(); + b.read += 4; + + var msg = { + signature: readVector(b, 2).getBytes() + }; + + // TODO: add support for DSA + + // generate data to verify + var verify = forge$9.util.createBuffer(); + verify.putBuffer(c.session.md5.digest()); + verify.putBuffer(c.session.sha1.digest()); + verify = verify.getBytes(); + + try { + var cert = c.session.clientCertificate; + /*b = forge.pki.rsa.decrypt( + msg.signature, cert.publicKey, true, verify.length); + if(b !== verify) {*/ + if(!cert.publicKey.verify(verify, msg.signature, 'NONE')) { + throw new Error('CertificateVerify signature does not match.'); + } + + // digest message now that it has been handled + c.session.md5.update(msgBytes); + c.session.sha1.update(msgBytes); + } catch(ex) { + return c.error(c, { + message: 'Bad signature in CertificateVerify.', + send: true, + alert: { + level: tls$1.Alert.Level.fatal, + description: tls$1.Alert.Description.handshake_failure + } + }); + } + + // expect ChangeCipherSpec + c.expect = CCC; + + // continue + c.process(); +}; + +/** + * Called when a client receives a ServerHelloDone record. + * + * When this message will be sent: + * The server hello done message is sent by the server to indicate the end + * of the server hello and associated messages. After sending this message + * the server will wait for a client response. + * + * Meaning of this message: + * This message means that the server is done sending messages to support + * the key exchange, and the client can proceed with its phase of the key + * exchange. + * + * Upon receipt of the server hello done message the client should verify + * that the server provided a valid certificate if required and check that + * the server hello parameters are acceptable. + * + * struct {} ServerHelloDone; + * + * @param c the connection. + * @param record the record. + * @param length the length of the handshake message. + */ +tls$1.handleServerHelloDone = function(c, record, length) { + // len must be 0 bytes + if(length > 0) { + return c.error(c, { + message: 'Invalid ServerHelloDone message. Invalid length.', + send: true, + alert: { + level: tls$1.Alert.Level.fatal, + description: tls$1.Alert.Description.record_overflow + } + }); + } + + if(c.serverCertificate === null) { + // no server certificate was provided + var error = { + message: 'No server certificate provided. Not enough security.', + send: true, + alert: { + level: tls$1.Alert.Level.fatal, + description: tls$1.Alert.Description.insufficient_security + } + }; + + // call application callback + var depth = 0; + var ret = c.verify(c, error.alert.description, depth, []); + if(ret !== true) { + // check for custom alert info + if(ret || ret === 0) { + // set custom message and alert description + if(typeof ret === 'object' && !forge$9.util.isArray(ret)) { + if(ret.message) { + error.message = ret.message; + } + if(ret.alert) { + error.alert.description = ret.alert; + } + } else if(typeof ret === 'number') { + // set custom alert description + error.alert.description = ret; + } + } + + // send error + return c.error(c, error); + } + } + + // create client certificate message if requested + if(c.session.certificateRequest !== null) { + record = tls$1.createRecord(c, { + type: tls$1.ContentType.handshake, + data: tls$1.createCertificate(c) + }); + tls$1.queue(c, record); + } + + // create client key exchange message + record = tls$1.createRecord(c, { + type: tls$1.ContentType.handshake, + data: tls$1.createClientKeyExchange(c) + }); + tls$1.queue(c, record); + + // expect no messages until the following callback has been called + c.expect = SER; + + // create callback to handle client signature (for client-certs) + var callback = function(c, signature) { + if(c.session.certificateRequest !== null && + c.session.clientCertificate !== null) { + // create certificate verify message + tls$1.queue(c, tls$1.createRecord(c, { + type: tls$1.ContentType.handshake, + data: tls$1.createCertificateVerify(c, signature) + })); + } + + // create change cipher spec message + tls$1.queue(c, tls$1.createRecord(c, { + type: tls$1.ContentType.change_cipher_spec, + data: tls$1.createChangeCipherSpec() + })); + + // create pending state + c.state.pending = tls$1.createConnectionState(c); + + // change current write state to pending write state + c.state.current.write = c.state.pending.write; + + // create finished message + tls$1.queue(c, tls$1.createRecord(c, { + type: tls$1.ContentType.handshake, + data: tls$1.createFinished(c) + })); + + // expect a server ChangeCipherSpec message next + c.expect = SCC; + + // send records + tls$1.flush(c); + + // continue + c.process(); + }; + + // if there is no certificate request or no client certificate, do + // callback immediately + if(c.session.certificateRequest === null || + c.session.clientCertificate === null) { + return callback(c, null); + } + + // otherwise get the client signature + tls$1.getClientSignature(c, callback); +}; + +/** + * Called when a ChangeCipherSpec record is received. + * + * @param c the connection. + * @param record the record. + */ +tls$1.handleChangeCipherSpec = function(c, record) { + if(record.fragment.getByte() !== 0x01) { + return c.error(c, { + message: 'Invalid ChangeCipherSpec message received.', + send: true, + alert: { + level: tls$1.Alert.Level.fatal, + description: tls$1.Alert.Description.illegal_parameter + } + }); + } + + // create pending state if: + // 1. Resuming session in client mode OR + // 2. NOT resuming session in server mode + var client = (c.entity === tls$1.ConnectionEnd.client); + if((c.session.resuming && client) || (!c.session.resuming && !client)) { + c.state.pending = tls$1.createConnectionState(c); + } + + // change current read state to pending read state + c.state.current.read = c.state.pending.read; + + // clear pending state if: + // 1. NOT resuming session in client mode OR + // 2. resuming a session in server mode + if((!c.session.resuming && client) || (c.session.resuming && !client)) { + c.state.pending = null; + } + + // expect a Finished record next + c.expect = client ? SFI : CFI; + + // continue + c.process(); +}; + +/** + * Called when a Finished record is received. + * + * When this message will be sent: + * A finished message is always sent immediately after a change + * cipher spec message to verify that the key exchange and + * authentication processes were successful. It is essential that a + * change cipher spec message be received between the other + * handshake messages and the Finished message. + * + * Meaning of this message: + * The finished message is the first protected with the just- + * negotiated algorithms, keys, and secrets. Recipients of finished + * messages must verify that the contents are correct. Once a side + * has sent its Finished message and received and validated the + * Finished message from its peer, it may begin to send and receive + * application data over the connection. + * + * struct { + * opaque verify_data[verify_data_length]; + * } Finished; + * + * verify_data + * PRF(master_secret, finished_label, Hash(handshake_messages)) + * [0..verify_data_length-1]; + * + * finished_label + * For Finished messages sent by the client, the string + * "client finished". For Finished messages sent by the server, the + * string "server finished". + * + * verify_data_length depends on the cipher suite. If it is not specified + * by the cipher suite, then it is 12. Versions of TLS < 1.2 always used + * 12 bytes. + * + * @param c the connection. + * @param record the record. + * @param length the length of the handshake message. + */ +tls$1.handleFinished = function(c, record, length) { + // rewind to get full bytes for message so it can be manually + // digested below (special case for Finished messages because they + // must be digested *after* handling as opposed to all others) + var b = record.fragment; + b.read -= 4; + var msgBytes = b.bytes(); + b.read += 4; + + // message contains only verify_data + var vd = record.fragment.getBytes(); + + // ensure verify data is correct + b = forge$9.util.createBuffer(); + b.putBuffer(c.session.md5.digest()); + b.putBuffer(c.session.sha1.digest()); + + // set label based on entity type + var client = (c.entity === tls$1.ConnectionEnd.client); + var label = client ? 'server finished' : 'client finished'; + + // TODO: determine prf function and verify length for TLS 1.2 + var sp = c.session.sp; + var vdl = 12; + var prf = prf_TLS1; + b = prf(sp.master_secret, label, b.getBytes(), vdl); + if(b.getBytes() !== vd) { + return c.error(c, { + message: 'Invalid verify_data in Finished message.', + send: true, + alert: { + level: tls$1.Alert.Level.fatal, + description: tls$1.Alert.Description.decrypt_error + } + }); + } + + // digest finished message now that it has been handled + c.session.md5.update(msgBytes); + c.session.sha1.update(msgBytes); + + // resuming session as client or NOT resuming session as server + if((c.session.resuming && client) || (!c.session.resuming && !client)) { + // create change cipher spec message + tls$1.queue(c, tls$1.createRecord(c, { + type: tls$1.ContentType.change_cipher_spec, + data: tls$1.createChangeCipherSpec() + })); + + // change current write state to pending write state, clear pending + c.state.current.write = c.state.pending.write; + c.state.pending = null; + + // create finished message + tls$1.queue(c, tls$1.createRecord(c, { + type: tls$1.ContentType.handshake, + data: tls$1.createFinished(c) + })); + } + + // expect application data next + c.expect = client ? SAD : CAD; + + // handshake complete + c.handshaking = false; + ++c.handshakes; + + // save access to peer certificate + c.peerCertificate = client ? + c.session.serverCertificate : c.session.clientCertificate; + + // send records + tls$1.flush(c); + + // now connected + c.isConnected = true; + c.connected(c); + + // continue + c.process(); +}; + +/** + * Called when an Alert record is received. + * + * @param c the connection. + * @param record the record. + */ +tls$1.handleAlert = function(c, record) { + // read alert + var b = record.fragment; + var alert = { + level: b.getByte(), + description: b.getByte() + }; + + // TODO: consider using a table? + // get appropriate message + var msg; + switch(alert.description) { + case tls$1.Alert.Description.close_notify: + msg = 'Connection closed.'; + break; + case tls$1.Alert.Description.unexpected_message: + msg = 'Unexpected message.'; + break; + case tls$1.Alert.Description.bad_record_mac: + msg = 'Bad record MAC.'; + break; + case tls$1.Alert.Description.decryption_failed: + msg = 'Decryption failed.'; + break; + case tls$1.Alert.Description.record_overflow: + msg = 'Record overflow.'; + break; + case tls$1.Alert.Description.decompression_failure: + msg = 'Decompression failed.'; + break; + case tls$1.Alert.Description.handshake_failure: + msg = 'Handshake failure.'; + break; + case tls$1.Alert.Description.bad_certificate: + msg = 'Bad certificate.'; + break; + case tls$1.Alert.Description.unsupported_certificate: + msg = 'Unsupported certificate.'; + break; + case tls$1.Alert.Description.certificate_revoked: + msg = 'Certificate revoked.'; + break; + case tls$1.Alert.Description.certificate_expired: + msg = 'Certificate expired.'; + break; + case tls$1.Alert.Description.certificate_unknown: + msg = 'Certificate unknown.'; + break; + case tls$1.Alert.Description.illegal_parameter: + msg = 'Illegal parameter.'; + break; + case tls$1.Alert.Description.unknown_ca: + msg = 'Unknown certificate authority.'; + break; + case tls$1.Alert.Description.access_denied: + msg = 'Access denied.'; + break; + case tls$1.Alert.Description.decode_error: + msg = 'Decode error.'; + break; + case tls$1.Alert.Description.decrypt_error: + msg = 'Decrypt error.'; + break; + case tls$1.Alert.Description.export_restriction: + msg = 'Export restriction.'; + break; + case tls$1.Alert.Description.protocol_version: + msg = 'Unsupported protocol version.'; + break; + case tls$1.Alert.Description.insufficient_security: + msg = 'Insufficient security.'; + break; + case tls$1.Alert.Description.internal_error: + msg = 'Internal error.'; + break; + case tls$1.Alert.Description.user_canceled: + msg = 'User canceled.'; + break; + case tls$1.Alert.Description.no_renegotiation: + msg = 'Renegotiation not supported.'; + break; + default: + msg = 'Unknown error.'; + break; + } + + // close connection on close_notify, not an error + if(alert.description === tls$1.Alert.Description.close_notify) { + return c.close(); + } + + // call error handler + c.error(c, { + message: msg, + send: false, + // origin is the opposite end + origin: (c.entity === tls$1.ConnectionEnd.client) ? 'server' : 'client', + alert: alert + }); + + // continue + c.process(); +}; + +/** + * Called when a Handshake record is received. + * + * @param c the connection. + * @param record the record. + */ +tls$1.handleHandshake = function(c, record) { + // get the handshake type and message length + var b = record.fragment; + var type = b.getByte(); + var length = b.getInt24(); + + // see if the record fragment doesn't yet contain the full message + if(length > b.length()) { + // cache the record, clear its fragment, and reset the buffer read + // pointer before the type and length were read + c.fragmented = record; + record.fragment = forge$9.util.createBuffer(); + b.read -= 4; + + // continue + return c.process(); + } + + // full message now available, clear cache, reset read pointer to + // before type and length + c.fragmented = null; + b.read -= 4; + + // save the handshake bytes for digestion after handler is found + // (include type and length of handshake msg) + var bytes = b.bytes(length + 4); + + // restore read pointer + b.read += 4; + + // handle expected message + if(type in hsTable[c.entity][c.expect]) { + // initialize server session + if(c.entity === tls$1.ConnectionEnd.server && !c.open && !c.fail) { + c.handshaking = true; + c.session = { + version: null, + extensions: { + server_name: { + serverNameList: [] + } + }, + cipherSuite: null, + compressionMethod: null, + serverCertificate: null, + clientCertificate: null, + md5: forge$9.md.md5.create(), + sha1: forge$9.md.sha1.create() + }; + } + + /* Update handshake messages digest. Finished and CertificateVerify + messages are not digested here. They can't be digested as part of + the verify_data that they contain. These messages are manually + digested in their handlers. HelloRequest messages are simply never + included in the handshake message digest according to spec. */ + if(type !== tls$1.HandshakeType.hello_request && + type !== tls$1.HandshakeType.certificate_verify && + type !== tls$1.HandshakeType.finished) { + c.session.md5.update(bytes); + c.session.sha1.update(bytes); + } + + // handle specific handshake type record + hsTable[c.entity][c.expect][type](c, record, length); + } else { + // unexpected record + tls$1.handleUnexpected(c, record); + } +}; + +/** + * Called when an ApplicationData record is received. + * + * @param c the connection. + * @param record the record. + */ +tls$1.handleApplicationData = function(c, record) { + // buffer data, notify that its ready + c.data.putBuffer(record.fragment); + c.dataReady(c); + + // continue + c.process(); +}; + +/** + * Called when a Heartbeat record is received. + * + * @param c the connection. + * @param record the record. + */ +tls$1.handleHeartbeat = function(c, record) { + // get the heartbeat type and payload + var b = record.fragment; + var type = b.getByte(); + var length = b.getInt16(); + var payload = b.getBytes(length); + + if(type === tls$1.HeartbeatMessageType.heartbeat_request) { + // discard request during handshake or if length is too large + if(c.handshaking || length > payload.length) { + // continue + return c.process(); + } + // retransmit payload + tls$1.queue(c, tls$1.createRecord(c, { + type: tls$1.ContentType.heartbeat, + data: tls$1.createHeartbeat( + tls$1.HeartbeatMessageType.heartbeat_response, payload) + })); + tls$1.flush(c); + } else if(type === tls$1.HeartbeatMessageType.heartbeat_response) { + // check payload against expected payload, discard heartbeat if no match + if(payload !== c.expectedHeartbeatPayload) { + // continue + return c.process(); + } + + // notify that a valid heartbeat was received + if(c.heartbeatReceived) { + c.heartbeatReceived(c, forge$9.util.createBuffer(payload)); + } + } + + // continue + c.process(); +}; + +/** + * The transistional state tables for receiving TLS records. It maps the + * current TLS engine state and a received record to a function to handle the + * record and update the state. + * + * For instance, if the current state is SHE, then the TLS engine is expecting + * a ServerHello record. Once a record is received, the handler function is + * looked up using the state SHE and the record's content type. + * + * The resulting function will either be an error handler or a record handler. + * The function will take whatever action is appropriate and update the state + * for the next record. + * + * The states are all based on possible server record types. Note that the + * client will never specifically expect to receive a HelloRequest or an alert + * from the server so there is no state that reflects this. These messages may + * occur at any time. + * + * There are two tables for mapping states because there is a second tier of + * types for handshake messages. Once a record with a content type of handshake + * is received, the handshake record handler will look up the handshake type in + * the secondary map to get its appropriate handler. + * + * Valid message orders are as follows: + * + * =======================FULL HANDSHAKE====================== + * Client Server + * + * ClientHello --------> + * ServerHello + * Certificate* + * ServerKeyExchange* + * CertificateRequest* + * <-------- ServerHelloDone + * Certificate* + * ClientKeyExchange + * CertificateVerify* + * [ChangeCipherSpec] + * Finished --------> + * [ChangeCipherSpec] + * <-------- Finished + * Application Data <-------> Application Data + * + * =====================SESSION RESUMPTION===================== + * Client Server + * + * ClientHello --------> + * ServerHello + * [ChangeCipherSpec] + * <-------- Finished + * [ChangeCipherSpec] + * Finished --------> + * Application Data <-------> Application Data + */ +// client expect states (indicate which records are expected to be received) +var SHE = 0; // rcv server hello +var SCE = 1; // rcv server certificate +var SKE = 2; // rcv server key exchange +var SCR = 3; // rcv certificate request +var SHD = 4; // rcv server hello done +var SCC = 5; // rcv change cipher spec +var SFI = 6; // rcv finished +var SAD = 7; // rcv application data +var SER = 8; // not expecting any messages at this point + +// server expect states +var CHE = 0; // rcv client hello +var CCE = 1; // rcv client certificate +var CKE = 2; // rcv client key exchange +var CCV = 3; // rcv certificate verify +var CCC = 4; // rcv change cipher spec +var CFI = 5; // rcv finished +var CAD = 6; // rcv application data + +// map client current expect state and content type to function +var __ = tls$1.handleUnexpected; +var R0 = tls$1.handleChangeCipherSpec; +var R1 = tls$1.handleAlert; +var R2 = tls$1.handleHandshake; +var R3 = tls$1.handleApplicationData; +var R4 = tls$1.handleHeartbeat; +var ctTable = []; +ctTable[tls$1.ConnectionEnd.client] = [ +// CC,AL,HS,AD,HB +/*SHE*/[__,R1,R2,__,R4], +/*SCE*/[__,R1,R2,__,R4], +/*SKE*/[__,R1,R2,__,R4], +/*SCR*/[__,R1,R2,__,R4], +/*SHD*/[__,R1,R2,__,R4], +/*SCC*/[R0,R1,__,__,R4], +/*SFI*/[__,R1,R2,__,R4], +/*SAD*/[__,R1,R2,R3,R4], +/*SER*/[__,R1,R2,__,R4] +]; + +// map server current expect state and content type to function +ctTable[tls$1.ConnectionEnd.server] = [ +// CC,AL,HS,AD +/*CHE*/[__,R1,R2,__,R4], +/*CCE*/[__,R1,R2,__,R4], +/*CKE*/[__,R1,R2,__,R4], +/*CCV*/[__,R1,R2,__,R4], +/*CCC*/[R0,R1,__,__,R4], +/*CFI*/[__,R1,R2,__,R4], +/*CAD*/[__,R1,R2,R3,R4], +/*CER*/[__,R1,R2,__,R4] +]; + +// map client current expect state and handshake type to function +var H0 = tls$1.handleHelloRequest; +var H1 = tls$1.handleServerHello; +var H2 = tls$1.handleCertificate; +var H3 = tls$1.handleServerKeyExchange; +var H4 = tls$1.handleCertificateRequest; +var H5 = tls$1.handleServerHelloDone; +var H6 = tls$1.handleFinished; +var hsTable = []; +hsTable[tls$1.ConnectionEnd.client] = [ +// HR,01,SH,03,04,05,06,07,08,09,10,SC,SK,CR,HD,15,CK,17,18,19,FI +/*SHE*/[__,__,H1,__,__,__,__,__,__,__,__,__,__,__,__,__,__,__,__,__,__], +/*SCE*/[H0,__,__,__,__,__,__,__,__,__,__,H2,H3,H4,H5,__,__,__,__,__,__], +/*SKE*/[H0,__,__,__,__,__,__,__,__,__,__,__,H3,H4,H5,__,__,__,__,__,__], +/*SCR*/[H0,__,__,__,__,__,__,__,__,__,__,__,__,H4,H5,__,__,__,__,__,__], +/*SHD*/[H0,__,__,__,__,__,__,__,__,__,__,__,__,__,H5,__,__,__,__,__,__], +/*SCC*/[H0,__,__,__,__,__,__,__,__,__,__,__,__,__,__,__,__,__,__,__,__], +/*SFI*/[H0,__,__,__,__,__,__,__,__,__,__,__,__,__,__,__,__,__,__,__,H6], +/*SAD*/[H0,__,__,__,__,__,__,__,__,__,__,__,__,__,__,__,__,__,__,__,__], +/*SER*/[H0,__,__,__,__,__,__,__,__,__,__,__,__,__,__,__,__,__,__,__,__] +]; + +// map server current expect state and handshake type to function +// Note: CAD[CH] does not map to FB because renegotation is prohibited +var H7 = tls$1.handleClientHello; +var H8 = tls$1.handleClientKeyExchange; +var H9 = tls$1.handleCertificateVerify; +hsTable[tls$1.ConnectionEnd.server] = [ +// 01,CH,02,03,04,05,06,07,08,09,10,CC,12,13,14,CV,CK,17,18,19,FI +/*CHE*/[__,H7,__,__,__,__,__,__,__,__,__,__,__,__,__,__,__,__,__,__,__], +/*CCE*/[__,__,__,__,__,__,__,__,__,__,__,H2,__,__,__,__,__,__,__,__,__], +/*CKE*/[__,__,__,__,__,__,__,__,__,__,__,__,__,__,__,__,H8,__,__,__,__], +/*CCV*/[__,__,__,__,__,__,__,__,__,__,__,__,__,__,__,H9,__,__,__,__,__], +/*CCC*/[__,__,__,__,__,__,__,__,__,__,__,__,__,__,__,__,__,__,__,__,__], +/*CFI*/[__,__,__,__,__,__,__,__,__,__,__,__,__,__,__,__,__,__,__,__,H6], +/*CAD*/[__,__,__,__,__,__,__,__,__,__,__,__,__,__,__,__,__,__,__,__,__], +/*CER*/[__,__,__,__,__,__,__,__,__,__,__,__,__,__,__,__,__,__,__,__,__] +]; + +/** + * Generates the master_secret and keys using the given security parameters. + * + * The security parameters for a TLS connection state are defined as such: + * + * struct { + * ConnectionEnd entity; + * PRFAlgorithm prf_algorithm; + * BulkCipherAlgorithm bulk_cipher_algorithm; + * CipherType cipher_type; + * uint8 enc_key_length; + * uint8 block_length; + * uint8 fixed_iv_length; + * uint8 record_iv_length; + * MACAlgorithm mac_algorithm; + * uint8 mac_length; + * uint8 mac_key_length; + * CompressionMethod compression_algorithm; + * opaque master_secret[48]; + * opaque client_random[32]; + * opaque server_random[32]; + * } SecurityParameters; + * + * Note that this definition is from TLS 1.2. In TLS 1.0 some of these + * parameters are ignored because, for instance, the PRFAlgorithm is a + * builtin-fixed algorithm combining iterations of MD5 and SHA-1 in TLS 1.0. + * + * The Record Protocol requires an algorithm to generate keys required by the + * current connection state. + * + * The master secret is expanded into a sequence of secure bytes, which is then + * split to a client write MAC key, a server write MAC key, a client write + * encryption key, and a server write encryption key. In TLS 1.0 a client write + * IV and server write IV are also generated. Each of these is generated from + * the byte sequence in that order. Unused values are empty. In TLS 1.2, some + * AEAD ciphers may additionally require a client write IV and a server write + * IV (see Section 6.2.3.3). + * + * When keys, MAC keys, and IVs are generated, the master secret is used as an + * entropy source. + * + * To generate the key material, compute: + * + * master_secret = PRF(pre_master_secret, "master secret", + * ClientHello.random + ServerHello.random) + * + * key_block = PRF(SecurityParameters.master_secret, + * "key expansion", + * SecurityParameters.server_random + + * SecurityParameters.client_random); + * + * until enough output has been generated. Then, the key_block is + * partitioned as follows: + * + * client_write_MAC_key[SecurityParameters.mac_key_length] + * server_write_MAC_key[SecurityParameters.mac_key_length] + * client_write_key[SecurityParameters.enc_key_length] + * server_write_key[SecurityParameters.enc_key_length] + * client_write_IV[SecurityParameters.fixed_iv_length] + * server_write_IV[SecurityParameters.fixed_iv_length] + * + * In TLS 1.2, the client_write_IV and server_write_IV are only generated for + * implicit nonce techniques as described in Section 3.2.1 of [AEAD]. This + * implementation uses TLS 1.0 so IVs are generated. + * + * Implementation note: The currently defined cipher suite which requires the + * most material is AES_256_CBC_SHA256. It requires 2 x 32 byte keys and 2 x 32 + * byte MAC keys, for a total 128 bytes of key material. In TLS 1.0 it also + * requires 2 x 16 byte IVs, so it actually takes 160 bytes of key material. + * + * @param c the connection. + * @param sp the security parameters to use. + * + * @return the security keys. + */ +tls$1.generateKeys = function(c, sp) { + // TLS_RSA_WITH_AES_128_CBC_SHA (required to be compliant with TLS 1.2) & + // TLS_RSA_WITH_AES_256_CBC_SHA are the only cipher suites implemented + // at present + + // TLS_DHE_DSS_WITH_3DES_EDE_CBC_SHA is required to be compliant with + // TLS 1.0 but we don't care right now because AES is better and we have + // an implementation for it + + // TODO: TLS 1.2 implementation + /* + // determine the PRF + var prf; + switch(sp.prf_algorithm) { + case tls.PRFAlgorithm.tls_prf_sha256: + prf = prf_sha256; + break; + default: + // should never happen + throw new Error('Invalid PRF'); + } + */ + + // TLS 1.0/1.1 implementation + var prf = prf_TLS1; + + // concatenate server and client random + var random = sp.client_random + sp.server_random; + + // only create master secret if session is new + if(!c.session.resuming) { + // create master secret, clean up pre-master secret + sp.master_secret = prf( + sp.pre_master_secret, 'master secret', random, 48).bytes(); + sp.pre_master_secret = null; + } + + // generate the amount of key material needed + random = sp.server_random + sp.client_random; + var length = 2 * sp.mac_key_length + 2 * sp.enc_key_length; + + // include IV for TLS/1.0 + var tls10 = (c.version.major === tls$1.Versions.TLS_1_0.major && + c.version.minor === tls$1.Versions.TLS_1_0.minor); + if(tls10) { + length += 2 * sp.fixed_iv_length; + } + var km = prf(sp.master_secret, 'key expansion', random, length); + + // split the key material into the MAC and encryption keys + var rval = { + client_write_MAC_key: km.getBytes(sp.mac_key_length), + server_write_MAC_key: km.getBytes(sp.mac_key_length), + client_write_key: km.getBytes(sp.enc_key_length), + server_write_key: km.getBytes(sp.enc_key_length) + }; + + // include TLS 1.0 IVs + if(tls10) { + rval.client_write_IV = km.getBytes(sp.fixed_iv_length); + rval.server_write_IV = km.getBytes(sp.fixed_iv_length); + } + + return rval; +}; + +/** + * Creates a new initialized TLS connection state. A connection state has + * a read mode and a write mode. + * + * compression state: + * The current state of the compression algorithm. + * + * cipher state: + * The current state of the encryption algorithm. This will consist of the + * scheduled key for that connection. For stream ciphers, this will also + * contain whatever state information is necessary to allow the stream to + * continue to encrypt or decrypt data. + * + * MAC key: + * The MAC key for the connection. + * + * sequence number: + * Each connection state contains a sequence number, which is maintained + * separately for read and write states. The sequence number MUST be set to + * zero whenever a connection state is made the active state. Sequence + * numbers are of type uint64 and may not exceed 2^64-1. Sequence numbers do + * not wrap. If a TLS implementation would need to wrap a sequence number, + * it must renegotiate instead. A sequence number is incremented after each + * record: specifically, the first record transmitted under a particular + * connection state MUST use sequence number 0. + * + * @param c the connection. + * + * @return the new initialized TLS connection state. + */ +tls$1.createConnectionState = function(c) { + var client = (c.entity === tls$1.ConnectionEnd.client); + + var createMode = function() { + var mode = { + // two 32-bit numbers, first is most significant + sequenceNumber: [0, 0], + macKey: null, + macLength: 0, + macFunction: null, + cipherState: null, + cipherFunction: function(record) {return true;}, + compressionState: null, + compressFunction: function(record) {return true;}, + updateSequenceNumber: function() { + if(mode.sequenceNumber[1] === 0xFFFFFFFF) { + mode.sequenceNumber[1] = 0; + ++mode.sequenceNumber[0]; + } else { + ++mode.sequenceNumber[1]; + } + } + }; + return mode; + }; + var state = { + read: createMode(), + write: createMode() + }; + + // update function in read mode will decrypt then decompress a record + state.read.update = function(c, record) { + if(!state.read.cipherFunction(record, state.read)) { + c.error(c, { + message: 'Could not decrypt record or bad MAC.', + send: true, + alert: { + level: tls$1.Alert.Level.fatal, + // doesn't matter if decryption failed or MAC was + // invalid, return the same error so as not to reveal + // which one occurred + description: tls$1.Alert.Description.bad_record_mac + } + }); + } else if(!state.read.compressFunction(c, record, state.read)) { + c.error(c, { + message: 'Could not decompress record.', + send: true, + alert: { + level: tls$1.Alert.Level.fatal, + description: tls$1.Alert.Description.decompression_failure + } + }); + } + return !c.fail; + }; + + // update function in write mode will compress then encrypt a record + state.write.update = function(c, record) { + if(!state.write.compressFunction(c, record, state.write)) { + // error, but do not send alert since it would require + // compression as well + c.error(c, { + message: 'Could not compress record.', + send: false, + alert: { + level: tls$1.Alert.Level.fatal, + description: tls$1.Alert.Description.internal_error + } + }); + } else if(!state.write.cipherFunction(record, state.write)) { + // error, but do not send alert since it would require + // encryption as well + c.error(c, { + message: 'Could not encrypt record.', + send: false, + alert: { + level: tls$1.Alert.Level.fatal, + description: tls$1.Alert.Description.internal_error + } + }); + } + return !c.fail; + }; + + // handle security parameters + if(c.session) { + var sp = c.session.sp; + c.session.cipherSuite.initSecurityParameters(sp); + + // generate keys + sp.keys = tls$1.generateKeys(c, sp); + state.read.macKey = client ? + sp.keys.server_write_MAC_key : sp.keys.client_write_MAC_key; + state.write.macKey = client ? + sp.keys.client_write_MAC_key : sp.keys.server_write_MAC_key; + + // cipher suite setup + c.session.cipherSuite.initConnectionState(state, c, sp); + + // compression setup + switch(sp.compression_algorithm) { + case tls$1.CompressionMethod.none: + break; + case tls$1.CompressionMethod.deflate: + state.read.compressFunction = inflate; + state.write.compressFunction = deflate; + break; + default: + throw new Error('Unsupported compression algorithm.'); + } + } + + return state; +}; + +/** + * Creates a Random structure. + * + * struct { + * uint32 gmt_unix_time; + * opaque random_bytes[28]; + * } Random; + * + * gmt_unix_time: + * The current time and date in standard UNIX 32-bit format (seconds since + * the midnight starting Jan 1, 1970, UTC, ignoring leap seconds) according + * to the sender's internal clock. Clocks are not required to be set + * correctly by the basic TLS protocol; higher-level or application + * protocols may define additional requirements. Note that, for historical + * reasons, the data element is named using GMT, the predecessor of the + * current worldwide time base, UTC. + * random_bytes: + * 28 bytes generated by a secure random number generator. + * + * @return the Random structure as a byte array. + */ +tls$1.createRandom = function() { + // get UTC milliseconds + var d = new Date(); + var utc = +d + d.getTimezoneOffset() * 60000; + var rval = forge$9.util.createBuffer(); + rval.putInt32(utc); + rval.putBytes(forge$9.random.getBytes(28)); + return rval; +}; + +/** + * Creates a TLS record with the given type and data. + * + * @param c the connection. + * @param options: + * type: the record type. + * data: the plain text data in a byte buffer. + * + * @return the created record. + */ +tls$1.createRecord = function(c, options) { + if(!options.data) { + return null; + } + var record = { + type: options.type, + version: { + major: c.version.major, + minor: c.version.minor + }, + length: options.data.length(), + fragment: options.data + }; + return record; +}; + +/** + * Creates a TLS alert record. + * + * @param c the connection. + * @param alert: + * level: the TLS alert level. + * description: the TLS alert description. + * + * @return the created alert record. + */ +tls$1.createAlert = function(c, alert) { + var b = forge$9.util.createBuffer(); + b.putByte(alert.level); + b.putByte(alert.description); + return tls$1.createRecord(c, { + type: tls$1.ContentType.alert, + data: b + }); +}; + +/* The structure of a TLS handshake message. + * + * struct { + * HandshakeType msg_type; // handshake type + * uint24 length; // bytes in message + * select(HandshakeType) { + * case hello_request: HelloRequest; + * case client_hello: ClientHello; + * case server_hello: ServerHello; + * case certificate: Certificate; + * case server_key_exchange: ServerKeyExchange; + * case certificate_request: CertificateRequest; + * case server_hello_done: ServerHelloDone; + * case certificate_verify: CertificateVerify; + * case client_key_exchange: ClientKeyExchange; + * case finished: Finished; + * } body; + * } Handshake; + */ + +/** + * Creates a ClientHello message. + * + * opaque SessionID<0..32>; + * enum { null(0), deflate(1), (255) } CompressionMethod; + * uint8 CipherSuite[2]; + * + * struct { + * ProtocolVersion client_version; + * Random random; + * SessionID session_id; + * CipherSuite cipher_suites<2..2^16-2>; + * CompressionMethod compression_methods<1..2^8-1>; + * select(extensions_present) { + * case false: + * struct {}; + * case true: + * Extension extensions<0..2^16-1>; + * }; + * } ClientHello; + * + * The extension format for extended client hellos and server hellos is: + * + * struct { + * ExtensionType extension_type; + * opaque extension_data<0..2^16-1>; + * } Extension; + * + * Here: + * + * - "extension_type" identifies the particular extension type. + * - "extension_data" contains information specific to the particular + * extension type. + * + * The extension types defined in this document are: + * + * enum { + * server_name(0), max_fragment_length(1), + * client_certificate_url(2), trusted_ca_keys(3), + * truncated_hmac(4), status_request(5), (65535) + * } ExtensionType; + * + * @param c the connection. + * + * @return the ClientHello byte buffer. + */ +tls$1.createClientHello = function(c) { + // save hello version + c.session.clientHelloVersion = { + major: c.version.major, + minor: c.version.minor + }; + + // create supported cipher suites + var cipherSuites = forge$9.util.createBuffer(); + for(var i = 0; i < c.cipherSuites.length; ++i) { + var cs = c.cipherSuites[i]; + cipherSuites.putByte(cs.id[0]); + cipherSuites.putByte(cs.id[1]); + } + var cSuites = cipherSuites.length(); + + // create supported compression methods, null always supported, but + // also support deflate if connection has inflate and deflate methods + var compressionMethods = forge$9.util.createBuffer(); + compressionMethods.putByte(tls$1.CompressionMethod.none); + // FIXME: deflate support disabled until issues with raw deflate data + // without zlib headers are resolved + /* + if(c.inflate !== null && c.deflate !== null) { + compressionMethods.putByte(tls.CompressionMethod.deflate); + } + */ + var cMethods = compressionMethods.length(); + + // create TLS SNI (server name indication) extension if virtual host + // has been specified, see RFC 3546 + var extensions = forge$9.util.createBuffer(); + if(c.virtualHost) { + // create extension struct + var ext = forge$9.util.createBuffer(); + ext.putByte(0x00); // type server_name (ExtensionType is 2 bytes) + ext.putByte(0x00); + + /* In order to provide the server name, clients MAY include an + * extension of type "server_name" in the (extended) client hello. + * The "extension_data" field of this extension SHALL contain + * "ServerNameList" where: + * + * struct { + * NameType name_type; + * select(name_type) { + * case host_name: HostName; + * } name; + * } ServerName; + * + * enum { + * host_name(0), (255) + * } NameType; + * + * opaque HostName<1..2^16-1>; + * + * struct { + * ServerName server_name_list<1..2^16-1> + * } ServerNameList; + */ + var serverName = forge$9.util.createBuffer(); + serverName.putByte(0x00); // type host_name + writeVector(serverName, 2, forge$9.util.createBuffer(c.virtualHost)); + + // ServerNameList is in extension_data + var snList = forge$9.util.createBuffer(); + writeVector(snList, 2, serverName); + writeVector(ext, 2, snList); + extensions.putBuffer(ext); + } + var extLength = extensions.length(); + if(extLength > 0) { + // add extension vector length + extLength += 2; + } + + // determine length of the handshake message + // cipher suites and compression methods size will need to be + // updated if more get added to the list + var sessionId = c.session.id; + var length = + sessionId.length + 1 + // session ID vector + 2 + // version (major + minor) + 4 + 28 + // random time and random bytes + 2 + cSuites + // cipher suites vector + 1 + cMethods + // compression methods vector + extLength; // extensions vector + + // build record fragment + var rval = forge$9.util.createBuffer(); + rval.putByte(tls$1.HandshakeType.client_hello); + rval.putInt24(length); // handshake length + rval.putByte(c.version.major); // major version + rval.putByte(c.version.minor); // minor version + rval.putBytes(c.session.sp.client_random); // random time + bytes + writeVector(rval, 1, forge$9.util.createBuffer(sessionId)); + writeVector(rval, 2, cipherSuites); + writeVector(rval, 1, compressionMethods); + if(extLength > 0) { + writeVector(rval, 2, extensions); + } + return rval; +}; + +/** + * Creates a ServerHello message. + * + * @param c the connection. + * + * @return the ServerHello byte buffer. + */ +tls$1.createServerHello = function(c) { + // determine length of the handshake message + var sessionId = c.session.id; + var length = + sessionId.length + 1 + // session ID vector + 2 + // version (major + minor) + 4 + 28 + // random time and random bytes + 2 + // chosen cipher suite + 1; // chosen compression method + + // build record fragment + var rval = forge$9.util.createBuffer(); + rval.putByte(tls$1.HandshakeType.server_hello); + rval.putInt24(length); // handshake length + rval.putByte(c.version.major); // major version + rval.putByte(c.version.minor); // minor version + rval.putBytes(c.session.sp.server_random); // random time + bytes + writeVector(rval, 1, forge$9.util.createBuffer(sessionId)); + rval.putByte(c.session.cipherSuite.id[0]); + rval.putByte(c.session.cipherSuite.id[1]); + rval.putByte(c.session.compressionMethod); + return rval; +}; + +/** + * Creates a Certificate message. + * + * When this message will be sent: + * This is the first message the client can send after receiving a server + * hello done message and the first message the server can send after + * sending a ServerHello. This client message is only sent if the server + * requests a certificate. If no suitable certificate is available, the + * client should send a certificate message containing no certificates. If + * client authentication is required by the server for the handshake to + * continue, it may respond with a fatal handshake failure alert. + * + * opaque ASN.1Cert<1..2^24-1>; + * + * struct { + * ASN.1Cert certificate_list<0..2^24-1>; + * } Certificate; + * + * @param c the connection. + * + * @return the Certificate byte buffer. + */ +tls$1.createCertificate = function(c) { + // TODO: check certificate request to ensure types are supported + + // get a certificate (a certificate as a PEM string) + var client = (c.entity === tls$1.ConnectionEnd.client); + var cert = null; + if(c.getCertificate) { + var hint; + if(client) { + hint = c.session.certificateRequest; + } else { + hint = c.session.extensions.server_name.serverNameList; + } + cert = c.getCertificate(c, hint); + } + + // buffer to hold certificate list + var certList = forge$9.util.createBuffer(); + if(cert !== null) { + try { + // normalize cert to a chain of certificates + if(!forge$9.util.isArray(cert)) { + cert = [cert]; + } + var asn1 = null; + for(var i = 0; i < cert.length; ++i) { + var msg = forge$9.pem.decode(cert[i])[0]; + if(msg.type !== 'CERTIFICATE' && + msg.type !== 'X509 CERTIFICATE' && + msg.type !== 'TRUSTED CERTIFICATE') { + var error = new Error('Could not convert certificate from PEM; PEM ' + + 'header type is not "CERTIFICATE", "X509 CERTIFICATE", or ' + + '"TRUSTED CERTIFICATE".'); + error.headerType = msg.type; + throw error; + } + if(msg.procType && msg.procType.type === 'ENCRYPTED') { + throw new Error('Could not convert certificate from PEM; PEM is encrypted.'); + } + + var der = forge$9.util.createBuffer(msg.body); + if(asn1 === null) { + asn1 = forge$9.asn1.fromDer(der.bytes(), false); + } + + // certificate entry is itself a vector with 3 length bytes + var certBuffer = forge$9.util.createBuffer(); + writeVector(certBuffer, 3, der); + + // add cert vector to cert list vector + certList.putBuffer(certBuffer); + } + + // save certificate + cert = forge$9.pki.certificateFromAsn1(asn1); + if(client) { + c.session.clientCertificate = cert; + } else { + c.session.serverCertificate = cert; + } + } catch(ex) { + return c.error(c, { + message: 'Could not send certificate list.', + cause: ex, + send: true, + alert: { + level: tls$1.Alert.Level.fatal, + description: tls$1.Alert.Description.bad_certificate + } + }); + } + } + + // determine length of the handshake message + var length = 3 + certList.length(); // cert list vector + + // build record fragment + var rval = forge$9.util.createBuffer(); + rval.putByte(tls$1.HandshakeType.certificate); + rval.putInt24(length); + writeVector(rval, 3, certList); + return rval; +}; + +/** + * Creates a ClientKeyExchange message. + * + * When this message will be sent: + * This message is always sent by the client. It will immediately follow the + * client certificate message, if it is sent. Otherwise it will be the first + * message sent by the client after it receives the server hello done + * message. + * + * Meaning of this message: + * With this message, the premaster secret is set, either though direct + * transmission of the RSA-encrypted secret, or by the transmission of + * Diffie-Hellman parameters which will allow each side to agree upon the + * same premaster secret. When the key exchange method is DH_RSA or DH_DSS, + * client certification has been requested, and the client was able to + * respond with a certificate which contained a Diffie-Hellman public key + * whose parameters (group and generator) matched those specified by the + * server in its certificate, this message will not contain any data. + * + * Meaning of this message: + * If RSA is being used for key agreement and authentication, the client + * generates a 48-byte premaster secret, encrypts it using the public key + * from the server's certificate or the temporary RSA key provided in a + * server key exchange message, and sends the result in an encrypted + * premaster secret message. This structure is a variant of the client + * key exchange message, not a message in itself. + * + * struct { + * select(KeyExchangeAlgorithm) { + * case rsa: EncryptedPreMasterSecret; + * case diffie_hellman: ClientDiffieHellmanPublic; + * } exchange_keys; + * } ClientKeyExchange; + * + * struct { + * ProtocolVersion client_version; + * opaque random[46]; + * } PreMasterSecret; + * + * struct { + * public-key-encrypted PreMasterSecret pre_master_secret; + * } EncryptedPreMasterSecret; + * + * A public-key-encrypted element is encoded as a vector <0..2^16-1>. + * + * @param c the connection. + * + * @return the ClientKeyExchange byte buffer. + */ +tls$1.createClientKeyExchange = function(c) { + // create buffer to encrypt + var b = forge$9.util.createBuffer(); + + // add highest client-supported protocol to help server avoid version + // rollback attacks + b.putByte(c.session.clientHelloVersion.major); + b.putByte(c.session.clientHelloVersion.minor); + + // generate and add 46 random bytes + b.putBytes(forge$9.random.getBytes(46)); + + // save pre-master secret + var sp = c.session.sp; + sp.pre_master_secret = b.getBytes(); + + // RSA-encrypt the pre-master secret + var key = c.session.serverCertificate.publicKey; + b = key.encrypt(sp.pre_master_secret); + + /* Note: The encrypted pre-master secret will be stored in a + public-key-encrypted opaque vector that has the length prefixed using + 2 bytes, so include those 2 bytes in the handshake message length. This + is done as a minor optimization instead of calling writeVector(). */ + + // determine length of the handshake message + var length = b.length + 2; + + // build record fragment + var rval = forge$9.util.createBuffer(); + rval.putByte(tls$1.HandshakeType.client_key_exchange); + rval.putInt24(length); + // add vector length bytes + rval.putInt16(b.length); + rval.putBytes(b); + return rval; +}; + +/** + * Creates a ServerKeyExchange message. + * + * @param c the connection. + * + * @return the ServerKeyExchange byte buffer. + */ +tls$1.createServerKeyExchange = function(c) { + + // build record fragment + var rval = forge$9.util.createBuffer(); + return rval; +}; + +/** + * Gets the signed data used to verify a client-side certificate. See + * tls.createCertificateVerify() for details. + * + * @param c the connection. + * @param callback the callback to call once the signed data is ready. + */ +tls$1.getClientSignature = function(c, callback) { + // generate data to RSA encrypt + var b = forge$9.util.createBuffer(); + b.putBuffer(c.session.md5.digest()); + b.putBuffer(c.session.sha1.digest()); + b = b.getBytes(); + + // create default signing function as necessary + c.getSignature = c.getSignature || function(c, b, callback) { + // do rsa encryption, call callback + var privateKey = null; + if(c.getPrivateKey) { + try { + privateKey = c.getPrivateKey(c, c.session.clientCertificate); + privateKey = forge$9.pki.privateKeyFromPem(privateKey); + } catch(ex) { + c.error(c, { + message: 'Could not get private key.', + cause: ex, + send: true, + alert: { + level: tls$1.Alert.Level.fatal, + description: tls$1.Alert.Description.internal_error + } + }); + } + } + if(privateKey === null) { + c.error(c, { + message: 'No private key set.', + send: true, + alert: { + level: tls$1.Alert.Level.fatal, + description: tls$1.Alert.Description.internal_error + } + }); + } else { + b = privateKey.sign(b, null); + } + callback(c, b); + }; + + // get client signature + c.getSignature(c, b, callback); +}; + +/** + * Creates a CertificateVerify message. + * + * Meaning of this message: + * This structure conveys the client's Diffie-Hellman public value + * (Yc) if it was not already included in the client's certificate. + * The encoding used for Yc is determined by the enumerated + * PublicValueEncoding. This structure is a variant of the client + * key exchange message, not a message in itself. + * + * When this message will be sent: + * This message is used to provide explicit verification of a client + * certificate. This message is only sent following a client + * certificate that has signing capability (i.e. all certificates + * except those containing fixed Diffie-Hellman parameters). When + * sent, it will immediately follow the client key exchange message. + * + * struct { + * Signature signature; + * } CertificateVerify; + * + * CertificateVerify.signature.md5_hash + * MD5(handshake_messages); + * + * Certificate.signature.sha_hash + * SHA(handshake_messages); + * + * Here handshake_messages refers to all handshake messages sent or + * received starting at client hello up to but not including this + * message, including the type and length fields of the handshake + * messages. + * + * select(SignatureAlgorithm) { + * case anonymous: struct { }; + * case rsa: + * digitally-signed struct { + * opaque md5_hash[16]; + * opaque sha_hash[20]; + * }; + * case dsa: + * digitally-signed struct { + * opaque sha_hash[20]; + * }; + * } Signature; + * + * In digital signing, one-way hash functions are used as input for a + * signing algorithm. A digitally-signed element is encoded as an opaque + * vector <0..2^16-1>, where the length is specified by the signing + * algorithm and key. + * + * In RSA signing, a 36-byte structure of two hashes (one SHA and one + * MD5) is signed (encrypted with the private key). It is encoded with + * PKCS #1 block type 0 or type 1 as described in [PKCS1]. + * + * In DSS, the 20 bytes of the SHA hash are run directly through the + * Digital Signing Algorithm with no additional hashing. + * + * @param c the connection. + * @param signature the signature to include in the message. + * + * @return the CertificateVerify byte buffer. + */ +tls$1.createCertificateVerify = function(c, signature) { + /* Note: The signature will be stored in a "digitally-signed" opaque + vector that has the length prefixed using 2 bytes, so include those + 2 bytes in the handshake message length. This is done as a minor + optimization instead of calling writeVector(). */ + + // determine length of the handshake message + var length = signature.length + 2; + + // build record fragment + var rval = forge$9.util.createBuffer(); + rval.putByte(tls$1.HandshakeType.certificate_verify); + rval.putInt24(length); + // add vector length bytes + rval.putInt16(signature.length); + rval.putBytes(signature); + return rval; +}; + +/** + * Creates a CertificateRequest message. + * + * @param c the connection. + * + * @return the CertificateRequest byte buffer. + */ +tls$1.createCertificateRequest = function(c) { + // TODO: support other certificate types + var certTypes = forge$9.util.createBuffer(); + + // common RSA certificate type + certTypes.putByte(0x01); + + // add distinguished names from CA store + var cAs = forge$9.util.createBuffer(); + for(var key in c.caStore.certs) { + var cert = c.caStore.certs[key]; + var dn = forge$9.pki.distinguishedNameToAsn1(cert.subject); + var byteBuffer = forge$9.asn1.toDer(dn); + cAs.putInt16(byteBuffer.length()); + cAs.putBuffer(byteBuffer); + } + + // TODO: TLS 1.2+ has a different format + + // determine length of the handshake message + var length = + 1 + certTypes.length() + + 2 + cAs.length(); + + // build record fragment + var rval = forge$9.util.createBuffer(); + rval.putByte(tls$1.HandshakeType.certificate_request); + rval.putInt24(length); + writeVector(rval, 1, certTypes); + writeVector(rval, 2, cAs); + return rval; +}; + +/** + * Creates a ServerHelloDone message. + * + * @param c the connection. + * + * @return the ServerHelloDone byte buffer. + */ +tls$1.createServerHelloDone = function(c) { + // build record fragment + var rval = forge$9.util.createBuffer(); + rval.putByte(tls$1.HandshakeType.server_hello_done); + rval.putInt24(0); + return rval; +}; + +/** + * Creates a ChangeCipherSpec message. + * + * The change cipher spec protocol exists to signal transitions in + * ciphering strategies. The protocol consists of a single message, + * which is encrypted and compressed under the current (not the pending) + * connection state. The message consists of a single byte of value 1. + * + * struct { + * enum { change_cipher_spec(1), (255) } type; + * } ChangeCipherSpec; + * + * @return the ChangeCipherSpec byte buffer. + */ +tls$1.createChangeCipherSpec = function() { + var rval = forge$9.util.createBuffer(); + rval.putByte(0x01); + return rval; +}; + +/** + * Creates a Finished message. + * + * struct { + * opaque verify_data[12]; + * } Finished; + * + * verify_data + * PRF(master_secret, finished_label, MD5(handshake_messages) + + * SHA-1(handshake_messages)) [0..11]; + * + * finished_label + * For Finished messages sent by the client, the string "client + * finished". For Finished messages sent by the server, the + * string "server finished". + * + * handshake_messages + * All of the data from all handshake messages up to but not + * including this message. This is only data visible at the + * handshake layer and does not include record layer headers. + * This is the concatenation of all the Handshake structures as + * defined in 7.4 exchanged thus far. + * + * @param c the connection. + * + * @return the Finished byte buffer. + */ +tls$1.createFinished = function(c) { + // generate verify_data + var b = forge$9.util.createBuffer(); + b.putBuffer(c.session.md5.digest()); + b.putBuffer(c.session.sha1.digest()); + + // TODO: determine prf function and verify length for TLS 1.2 + var client = (c.entity === tls$1.ConnectionEnd.client); + var sp = c.session.sp; + var vdl = 12; + var prf = prf_TLS1; + var label = client ? 'client finished' : 'server finished'; + b = prf(sp.master_secret, label, b.getBytes(), vdl); + + // build record fragment + var rval = forge$9.util.createBuffer(); + rval.putByte(tls$1.HandshakeType.finished); + rval.putInt24(b.length()); + rval.putBuffer(b); + return rval; +}; + +/** + * Creates a HeartbeatMessage (See RFC 6520). + * + * struct { + * HeartbeatMessageType type; + * uint16 payload_length; + * opaque payload[HeartbeatMessage.payload_length]; + * opaque padding[padding_length]; + * } HeartbeatMessage; + * + * The total length of a HeartbeatMessage MUST NOT exceed 2^14 or + * max_fragment_length when negotiated as defined in [RFC6066]. + * + * type: The message type, either heartbeat_request or heartbeat_response. + * + * payload_length: The length of the payload. + * + * payload: The payload consists of arbitrary content. + * + * padding: The padding is random content that MUST be ignored by the + * receiver. The length of a HeartbeatMessage is TLSPlaintext.length + * for TLS and DTLSPlaintext.length for DTLS. Furthermore, the + * length of the type field is 1 byte, and the length of the + * payload_length is 2. Therefore, the padding_length is + * TLSPlaintext.length - payload_length - 3 for TLS and + * DTLSPlaintext.length - payload_length - 3 for DTLS. The + * padding_length MUST be at least 16. + * + * The sender of a HeartbeatMessage MUST use a random padding of at + * least 16 bytes. The padding of a received HeartbeatMessage message + * MUST be ignored. + * + * If the payload_length of a received HeartbeatMessage is too large, + * the received HeartbeatMessage MUST be discarded silently. + * + * @param c the connection. + * @param type the tls.HeartbeatMessageType. + * @param payload the heartbeat data to send as the payload. + * @param [payloadLength] the payload length to use, defaults to the + * actual payload length. + * + * @return the HeartbeatRequest byte buffer. + */ +tls$1.createHeartbeat = function(type, payload, payloadLength) { + if(typeof payloadLength === 'undefined') { + payloadLength = payload.length; + } + // build record fragment + var rval = forge$9.util.createBuffer(); + rval.putByte(type); // heartbeat message type + rval.putInt16(payloadLength); // payload length + rval.putBytes(payload); // payload + // padding + var plaintextLength = rval.length(); + var paddingLength = Math.max(16, plaintextLength - payloadLength - 3); + rval.putBytes(forge$9.random.getBytes(paddingLength)); + return rval; +}; + +/** + * Fragments, compresses, encrypts, and queues a record for delivery. + * + * @param c the connection. + * @param record the record to queue. + */ +tls$1.queue = function(c, record) { + // error during record creation + if(!record) { + return; + } + + if(record.fragment.length() === 0) { + if(record.type === tls$1.ContentType.handshake || + record.type === tls$1.ContentType.alert || + record.type === tls$1.ContentType.change_cipher_spec) { + // Empty handshake, alert of change cipher spec messages are not allowed per the TLS specification and should not be sent. + return; + } + } + + // if the record is a handshake record, update handshake hashes + if(record.type === tls$1.ContentType.handshake) { + var bytes = record.fragment.bytes(); + c.session.md5.update(bytes); + c.session.sha1.update(bytes); + bytes = null; + } + + // handle record fragmentation + var records; + if(record.fragment.length() <= tls$1.MaxFragment) { + records = [record]; + } else { + // fragment data as long as it is too long + records = []; + var data = record.fragment.bytes(); + while(data.length > tls$1.MaxFragment) { + records.push(tls$1.createRecord(c, { + type: record.type, + data: forge$9.util.createBuffer(data.slice(0, tls$1.MaxFragment)) + })); + data = data.slice(tls$1.MaxFragment); + } + // add last record + if(data.length > 0) { + records.push(tls$1.createRecord(c, { + type: record.type, + data: forge$9.util.createBuffer(data) + })); + } + } + + // compress and encrypt all fragmented records + for(var i = 0; i < records.length && !c.fail; ++i) { + // update the record using current write state + var rec = records[i]; + var s = c.state.current.write; + if(s.update(c, rec)) { + // store record + c.records.push(rec); + } + } +}; + +/** + * Flushes all queued records to the output buffer and calls the + * tlsDataReady() handler on the given connection. + * + * @param c the connection. + * + * @return true on success, false on failure. + */ +tls$1.flush = function(c) { + for(var i = 0; i < c.records.length; ++i) { + var record = c.records[i]; + + // add record header and fragment + c.tlsData.putByte(record.type); + c.tlsData.putByte(record.version.major); + c.tlsData.putByte(record.version.minor); + c.tlsData.putInt16(record.fragment.length()); + c.tlsData.putBuffer(c.records[i].fragment); + } + c.records = []; + return c.tlsDataReady(c); +}; + +/** + * Maps a pki.certificateError to a tls.Alert.Description. + * + * @param error the error to map. + * + * @return the alert description. + */ +var _certErrorToAlertDesc = function(error) { + switch(error) { + case true: + return true; + case forge$9.pki.certificateError.bad_certificate: + return tls$1.Alert.Description.bad_certificate; + case forge$9.pki.certificateError.unsupported_certificate: + return tls$1.Alert.Description.unsupported_certificate; + case forge$9.pki.certificateError.certificate_revoked: + return tls$1.Alert.Description.certificate_revoked; + case forge$9.pki.certificateError.certificate_expired: + return tls$1.Alert.Description.certificate_expired; + case forge$9.pki.certificateError.certificate_unknown: + return tls$1.Alert.Description.certificate_unknown; + case forge$9.pki.certificateError.unknown_ca: + return tls$1.Alert.Description.unknown_ca; + default: + return tls$1.Alert.Description.bad_certificate; + } +}; + +/** + * Maps a tls.Alert.Description to a pki.certificateError. + * + * @param desc the alert description. + * + * @return the certificate error. + */ +var _alertDescToCertError = function(desc) { + switch(desc) { + case true: + return true; + case tls$1.Alert.Description.bad_certificate: + return forge$9.pki.certificateError.bad_certificate; + case tls$1.Alert.Description.unsupported_certificate: + return forge$9.pki.certificateError.unsupported_certificate; + case tls$1.Alert.Description.certificate_revoked: + return forge$9.pki.certificateError.certificate_revoked; + case tls$1.Alert.Description.certificate_expired: + return forge$9.pki.certificateError.certificate_expired; + case tls$1.Alert.Description.certificate_unknown: + return forge$9.pki.certificateError.certificate_unknown; + case tls$1.Alert.Description.unknown_ca: + return forge$9.pki.certificateError.unknown_ca; + default: + return forge$9.pki.certificateError.bad_certificate; + } +}; + +/** + * Verifies a certificate chain against the given connection's + * Certificate Authority store. + * + * @param c the TLS connection. + * @param chain the certificate chain to verify, with the root or highest + * authority at the end. + * + * @return true if successful, false if not. + */ +tls$1.verifyCertificateChain = function(c, chain) { + try { + // Make a copy of c.verifyOptions so that we can modify options.verify + // without modifying c.verifyOptions. + var options = {}; + for (var key in c.verifyOptions) { + options[key] = c.verifyOptions[key]; + } + + options.verify = function(vfd, depth, chain) { + // convert pki.certificateError to tls alert description + var desc = _certErrorToAlertDesc(vfd); + + // call application callback + var ret = c.verify(c, vfd, depth, chain); + if(ret !== true) { + if(typeof ret === 'object' && !forge$9.util.isArray(ret)) { + // throw custom error + var error = new Error('The application rejected the certificate.'); + error.send = true; + error.alert = { + level: tls$1.Alert.Level.fatal, + description: tls$1.Alert.Description.bad_certificate + }; + if(ret.message) { + error.message = ret.message; + } + if(ret.alert) { + error.alert.description = ret.alert; + } + throw error; + } + + // convert tls alert description to pki.certificateError + if(ret !== vfd) { + ret = _alertDescToCertError(ret); + } + } + + return ret; + }; + + // verify chain + forge$9.pki.verifyCertificateChain(c.caStore, chain, options); + } catch(ex) { + // build tls error if not already customized + var err = ex; + if(typeof err !== 'object' || forge$9.util.isArray(err)) { + err = { + send: true, + alert: { + level: tls$1.Alert.Level.fatal, + description: _certErrorToAlertDesc(ex) + } + }; + } + if(!('send' in err)) { + err.send = true; + } + if(!('alert' in err)) { + err.alert = { + level: tls$1.Alert.Level.fatal, + description: _certErrorToAlertDesc(err.error) + }; + } + + // send error + c.error(c, err); + } + + return !c.fail; +}; + +/** + * Creates a new TLS session cache. + * + * @param cache optional map of session ID to cached session. + * @param capacity the maximum size for the cache (default: 100). + * + * @return the new TLS session cache. + */ +tls$1.createSessionCache = function(cache, capacity) { + var rval = null; + + // assume input is already a session cache object + if(cache && cache.getSession && cache.setSession && cache.order) { + rval = cache; + } else { + // create cache + rval = {}; + rval.cache = cache || {}; + rval.capacity = Math.max(capacity || 100, 1); + rval.order = []; + + // store order for sessions, delete session overflow + for(var key in cache) { + if(rval.order.length <= capacity) { + rval.order.push(key); + } else { + delete cache[key]; + } + } + + // get a session from a session ID (or get any session) + rval.getSession = function(sessionId) { + var session = null; + var key = null; + + // if session ID provided, use it + if(sessionId) { + key = forge$9.util.bytesToHex(sessionId); + } else if(rval.order.length > 0) { + // get first session from cache + key = rval.order[0]; + } + + if(key !== null && key in rval.cache) { + // get cached session and remove from cache + session = rval.cache[key]; + delete rval.cache[key]; + for(var i in rval.order) { + if(rval.order[i] === key) { + rval.order.splice(i, 1); + break; + } + } + } + + return session; + }; + + // set a session in the cache + rval.setSession = function(sessionId, session) { + // remove session from cache if at capacity + if(rval.order.length === rval.capacity) { + var key = rval.order.shift(); + delete rval.cache[key]; + } + // add session to cache + var key = forge$9.util.bytesToHex(sessionId); + rval.order.push(key); + rval.cache[key] = session; + }; + } + + return rval; +}; + +/** + * Creates a new TLS connection. + * + * See public createConnection() docs for more details. + * + * @param options the options for this connection. + * + * @return the new TLS connection. + */ +tls$1.createConnection = function(options) { + var caStore = null; + if(options.caStore) { + // if CA store is an array, convert it to a CA store object + if(forge$9.util.isArray(options.caStore)) { + caStore = forge$9.pki.createCaStore(options.caStore); + } else { + caStore = options.caStore; + } + } else { + // create empty CA store + caStore = forge$9.pki.createCaStore(); + } + + // setup default cipher suites + var cipherSuites = options.cipherSuites || null; + if(cipherSuites === null) { + cipherSuites = []; + for(var key in tls$1.CipherSuites) { + cipherSuites.push(tls$1.CipherSuites[key]); + } + } + + // set default entity + var entity = (options.server || false) ? + tls$1.ConnectionEnd.server : tls$1.ConnectionEnd.client; + + // create session cache if requested + var sessionCache = options.sessionCache ? + tls$1.createSessionCache(options.sessionCache) : null; + + // create TLS connection + var c = { + version: {major: tls$1.Version.major, minor: tls$1.Version.minor}, + entity: entity, + sessionId: options.sessionId, + caStore: caStore, + sessionCache: sessionCache, + cipherSuites: cipherSuites, + connected: options.connected, + virtualHost: options.virtualHost || null, + verifyClient: options.verifyClient || false, + verify: options.verify || function(cn, vfd, dpth, cts) {return vfd;}, + verifyOptions: options.verifyOptions || {}, + getCertificate: options.getCertificate || null, + getPrivateKey: options.getPrivateKey || null, + getSignature: options.getSignature || null, + input: forge$9.util.createBuffer(), + tlsData: forge$9.util.createBuffer(), + data: forge$9.util.createBuffer(), + tlsDataReady: options.tlsDataReady, + dataReady: options.dataReady, + heartbeatReceived: options.heartbeatReceived, + closed: options.closed, + error: function(c, ex) { + // set origin if not set + ex.origin = ex.origin || + ((c.entity === tls$1.ConnectionEnd.client) ? 'client' : 'server'); + + // send TLS alert + if(ex.send) { + tls$1.queue(c, tls$1.createAlert(c, ex.alert)); + tls$1.flush(c); + } + + // error is fatal by default + var fatal = (ex.fatal !== false); + if(fatal) { + // set fail flag + c.fail = true; + } + + // call error handler first + options.error(c, ex); + + if(fatal) { + // fatal error, close connection, do not clear fail + c.close(false); + } + }, + deflate: options.deflate || null, + inflate: options.inflate || null + }; + + /** + * Resets a closed TLS connection for reuse. Called in c.close(). + * + * @param clearFail true to clear the fail flag (default: true). + */ + c.reset = function(clearFail) { + c.version = {major: tls$1.Version.major, minor: tls$1.Version.minor}; + c.record = null; + c.session = null; + c.peerCertificate = null; + c.state = { + pending: null, + current: null + }; + c.expect = (c.entity === tls$1.ConnectionEnd.client) ? SHE : CHE; + c.fragmented = null; + c.records = []; + c.open = false; + c.handshakes = 0; + c.handshaking = false; + c.isConnected = false; + c.fail = !(clearFail || typeof(clearFail) === 'undefined'); + c.input.clear(); + c.tlsData.clear(); + c.data.clear(); + c.state.current = tls$1.createConnectionState(c); + }; + + // do initial reset of connection + c.reset(); + + /** + * Updates the current TLS engine state based on the given record. + * + * @param c the TLS connection. + * @param record the TLS record to act on. + */ + var _update = function(c, record) { + // get record handler (align type in table by subtracting lowest) + var aligned = record.type - tls$1.ContentType.change_cipher_spec; + var handlers = ctTable[c.entity][c.expect]; + if(aligned in handlers) { + handlers[aligned](c, record); + } else { + // unexpected record + tls$1.handleUnexpected(c, record); + } + }; + + /** + * Reads the record header and initializes the next record on the given + * connection. + * + * @param c the TLS connection with the next record. + * + * @return 0 if the input data could be processed, otherwise the + * number of bytes required for data to be processed. + */ + var _readRecordHeader = function(c) { + var rval = 0; + + // get input buffer and its length + var b = c.input; + var len = b.length(); + + // need at least 5 bytes to initialize a record + if(len < 5) { + rval = 5 - len; + } else { + // enough bytes for header + // initialize record + c.record = { + type: b.getByte(), + version: { + major: b.getByte(), + minor: b.getByte() + }, + length: b.getInt16(), + fragment: forge$9.util.createBuffer(), + ready: false + }; + + // check record version + var compatibleVersion = (c.record.version.major === c.version.major); + if(compatibleVersion && c.session && c.session.version) { + // session version already set, require same minor version + compatibleVersion = (c.record.version.minor === c.version.minor); + } + if(!compatibleVersion) { + c.error(c, { + message: 'Incompatible TLS version.', + send: true, + alert: { + level: tls$1.Alert.Level.fatal, + description: tls$1.Alert.Description.protocol_version + } + }); + } + } + + return rval; + }; + + /** + * Reads the next record's contents and appends its message to any + * previously fragmented message. + * + * @param c the TLS connection with the next record. + * + * @return 0 if the input data could be processed, otherwise the + * number of bytes required for data to be processed. + */ + var _readRecord = function(c) { + var rval = 0; + + // ensure there is enough input data to get the entire record + var b = c.input; + var len = b.length(); + if(len < c.record.length) { + // not enough data yet, return how much is required + rval = c.record.length - len; + } else { + // there is enough data to parse the pending record + // fill record fragment and compact input buffer + c.record.fragment.putBytes(b.getBytes(c.record.length)); + b.compact(); + + // update record using current read state + var s = c.state.current.read; + if(s.update(c, c.record)) { + // see if there is a previously fragmented message that the + // new record's message fragment should be appended to + if(c.fragmented !== null) { + // if the record type matches a previously fragmented + // record, append the record fragment to it + if(c.fragmented.type === c.record.type) { + // concatenate record fragments + c.fragmented.fragment.putBuffer(c.record.fragment); + c.record = c.fragmented; + } else { + // error, invalid fragmented record + c.error(c, { + message: 'Invalid fragmented record.', + send: true, + alert: { + level: tls$1.Alert.Level.fatal, + description: + tls$1.Alert.Description.unexpected_message + } + }); + } + } + + // record is now ready + c.record.ready = true; + } + } + + return rval; + }; + + /** + * Performs a handshake using the TLS Handshake Protocol, as a client. + * + * This method should only be called if the connection is in client mode. + * + * @param sessionId the session ID to use, null to start a new one. + */ + c.handshake = function(sessionId) { + // error to call this in non-client mode + if(c.entity !== tls$1.ConnectionEnd.client) { + // not fatal error + c.error(c, { + message: 'Cannot initiate handshake as a server.', + fatal: false + }); + } else if(c.handshaking) { + // handshake is already in progress, fail but not fatal error + c.error(c, { + message: 'Handshake already in progress.', + fatal: false + }); + } else { + // clear fail flag on reuse + if(c.fail && !c.open && c.handshakes === 0) { + c.fail = false; + } + + // now handshaking + c.handshaking = true; + + // default to blank (new session) + sessionId = sessionId || ''; + + // if a session ID was specified, try to find it in the cache + var session = null; + if(sessionId.length > 0) { + if(c.sessionCache) { + session = c.sessionCache.getSession(sessionId); + } + + // matching session not found in cache, clear session ID + if(session === null) { + sessionId = ''; + } + } + + // no session given, grab a session from the cache, if available + if(sessionId.length === 0 && c.sessionCache) { + session = c.sessionCache.getSession(); + if(session !== null) { + sessionId = session.id; + } + } + + // set up session + c.session = { + id: sessionId, + version: null, + cipherSuite: null, + compressionMethod: null, + serverCertificate: null, + certificateRequest: null, + clientCertificate: null, + sp: {}, + md5: forge$9.md.md5.create(), + sha1: forge$9.md.sha1.create() + }; + + // use existing session information + if(session) { + // only update version on connection, session version not yet set + c.version = session.version; + c.session.sp = session.sp; + } + + // generate new client random + c.session.sp.client_random = tls$1.createRandom().getBytes(); + + // connection now open + c.open = true; + + // send hello + tls$1.queue(c, tls$1.createRecord(c, { + type: tls$1.ContentType.handshake, + data: tls$1.createClientHello(c) + })); + tls$1.flush(c); + } + }; + + /** + * Called when TLS protocol data has been received from somewhere and should + * be processed by the TLS engine. + * + * @param data the TLS protocol data, as a string, to process. + * + * @return 0 if the data could be processed, otherwise the number of bytes + * required for data to be processed. + */ + c.process = function(data) { + var rval = 0; + + // buffer input data + if(data) { + c.input.putBytes(data); + } + + // process next record if no failure, process will be called after + // each record is handled (since handling can be asynchronous) + if(!c.fail) { + // reset record if ready and now empty + if(c.record !== null && + c.record.ready && c.record.fragment.isEmpty()) { + c.record = null; + } + + // if there is no pending record, try to read record header + if(c.record === null) { + rval = _readRecordHeader(c); + } + + // read the next record (if record not yet ready) + if(!c.fail && c.record !== null && !c.record.ready) { + rval = _readRecord(c); + } + + // record ready to be handled, update engine state + if(!c.fail && c.record !== null && c.record.ready) { + _update(c, c.record); + } + } + + return rval; + }; + + /** + * Requests that application data be packaged into a TLS record. The + * tlsDataReady handler will be called when the TLS record(s) have been + * prepared. + * + * @param data the application data, as a raw 'binary' encoded string, to + * be sent; to send utf-16/utf-8 string data, use the return value + * of util.encodeUtf8(str). + * + * @return true on success, false on failure. + */ + c.prepare = function(data) { + tls$1.queue(c, tls$1.createRecord(c, { + type: tls$1.ContentType.application_data, + data: forge$9.util.createBuffer(data) + })); + return tls$1.flush(c); + }; + + /** + * Requests that a heartbeat request be packaged into a TLS record for + * transmission. The tlsDataReady handler will be called when TLS record(s) + * have been prepared. + * + * When a heartbeat response has been received, the heartbeatReceived + * handler will be called with the matching payload. This handler can + * be used to clear a retransmission timer, etc. + * + * @param payload the heartbeat data to send as the payload in the message. + * @param [payloadLength] the payload length to use, defaults to the + * actual payload length. + * + * @return true on success, false on failure. + */ + c.prepareHeartbeatRequest = function(payload, payloadLength) { + if(payload instanceof forge$9.util.ByteBuffer) { + payload = payload.bytes(); + } + if(typeof payloadLength === 'undefined') { + payloadLength = payload.length; + } + c.expectedHeartbeatPayload = payload; + tls$1.queue(c, tls$1.createRecord(c, { + type: tls$1.ContentType.heartbeat, + data: tls$1.createHeartbeat( + tls$1.HeartbeatMessageType.heartbeat_request, payload, payloadLength) + })); + return tls$1.flush(c); + }; + + /** + * Closes the connection (sends a close_notify alert). + * + * @param clearFail true to clear the fail flag (default: true). + */ + c.close = function(clearFail) { + // save session if connection didn't fail + if(!c.fail && c.sessionCache && c.session) { + // only need to preserve session ID, version, and security params + var session = { + id: c.session.id, + version: c.session.version, + sp: c.session.sp + }; + session.sp.keys = null; + c.sessionCache.setSession(session.id, session); + } + + if(c.open) { + // connection no longer open, clear input + c.open = false; + c.input.clear(); + + // if connected or handshaking, send an alert + if(c.isConnected || c.handshaking) { + c.isConnected = c.handshaking = false; + + // send close_notify alert + tls$1.queue(c, tls$1.createAlert(c, { + level: tls$1.Alert.Level.warning, + description: tls$1.Alert.Description.close_notify + })); + tls$1.flush(c); + } + + // call handler + c.closed(c); + } + + // reset TLS connection, do not clear fail flag + c.reset(clearFail); + }; + + return c; +}; + +/* TLS API */ +forge$9.tls = forge$9.tls || {}; + +// expose non-functions +for(var key in tls$1) { + if(typeof tls$1[key] !== 'function') { + forge$9.tls[key] = tls$1[key]; + } +} + +// expose prf_tls1 for testing +forge$9.tls.prf_tls1 = prf_TLS1; + +// expose sha1 hmac method +forge$9.tls.hmac_sha1 = hmac_sha1; + +// expose session cache creation +forge$9.tls.createSessionCache = tls$1.createSessionCache; + +/** + * Creates a new TLS connection. This does not make any assumptions about the + * transport layer that TLS is working on top of, ie: it does not assume there + * is a TCP/IP connection or establish one. A TLS connection is totally + * abstracted away from the layer is runs on top of, it merely establishes a + * secure channel between a client" and a "server". + * + * A TLS connection contains 4 connection states: pending read and write, and + * current read and write. + * + * At initialization, the current read and write states will be null. Only once + * the security parameters have been set and the keys have been generated can + * the pending states be converted into current states. Current states will be + * updated for each record processed. + * + * A custom certificate verify callback may be provided to check information + * like the common name on the server's certificate. It will be called for + * every certificate in the chain. It has the following signature: + * + * variable func(c, certs, index, preVerify) + * Where: + * c The TLS connection + * verified Set to true if certificate was verified, otherwise the alert + * tls.Alert.Description for why the certificate failed. + * depth The current index in the chain, where 0 is the server's cert. + * certs The certificate chain, *NOTE* if the server was anonymous then + * the chain will be empty. + * + * The function returns true on success and on failure either the appropriate + * tls.Alert.Description or an object with 'alert' set to the appropriate + * tls.Alert.Description and 'message' set to a custom error message. If true + * is not returned then the connection will abort using, in order of + * availability, first the returned alert description, second the preVerify + * alert description, and lastly the default 'bad_certificate'. + * + * There are three callbacks that can be used to make use of client-side + * certificates where each takes the TLS connection as the first parameter: + * + * getCertificate(conn, hint) + * The second parameter is a hint as to which certificate should be + * returned. If the connection entity is a client, then the hint will be + * the CertificateRequest message from the server that is part of the + * TLS protocol. If the connection entity is a server, then it will be + * the servername list provided via an SNI extension the ClientHello, if + * one was provided (empty array if not). The hint can be examined to + * determine which certificate to use (advanced). Most implementations + * will just return a certificate. The return value must be a + * PEM-formatted certificate or an array of PEM-formatted certificates + * that constitute a certificate chain, with the first in the array/chain + * being the client's certificate. + * getPrivateKey(conn, certificate) + * The second parameter is an forge.pki X.509 certificate object that + * is associated with the requested private key. The return value must + * be a PEM-formatted private key. + * getSignature(conn, bytes, callback) + * This callback can be used instead of getPrivateKey if the private key + * is not directly accessible in javascript or should not be. For + * instance, a secure external web service could provide the signature + * in exchange for appropriate credentials. The second parameter is a + * string of bytes to be signed that are part of the TLS protocol. These + * bytes are used to verify that the private key for the previously + * provided client-side certificate is accessible to the client. The + * callback is a function that takes 2 parameters, the TLS connection + * and the RSA encrypted (signed) bytes as a string. This callback must + * be called once the signature is ready. + * + * @param options the options for this connection: + * server: true if the connection is server-side, false for client. + * sessionId: a session ID to reuse, null for a new connection. + * caStore: an array of certificates to trust. + * sessionCache: a session cache to use. + * cipherSuites: an optional array of cipher suites to use, + * see tls.CipherSuites. + * connected: function(conn) called when the first handshake completes. + * virtualHost: the virtual server name to use in a TLS SNI extension. + * verifyClient: true to require a client certificate in server mode, + * 'optional' to request one, false not to (default: false). + * verify: a handler used to custom verify certificates in the chain. + * verifyOptions: an object with options for the certificate chain validation. + * See documentation of pki.verifyCertificateChain for possible options. + * verifyOptions.verify is ignored. If you wish to specify a verify handler + * use the verify key. + * getCertificate: an optional callback used to get a certificate or + * a chain of certificates (as an array). + * getPrivateKey: an optional callback used to get a private key. + * getSignature: an optional callback used to get a signature. + * tlsDataReady: function(conn) called when TLS protocol data has been + * prepared and is ready to be used (typically sent over a socket + * connection to its destination), read from conn.tlsData buffer. + * dataReady: function(conn) called when application data has + * been parsed from a TLS record and should be consumed by the + * application, read from conn.data buffer. + * closed: function(conn) called when the connection has been closed. + * error: function(conn, error) called when there was an error. + * deflate: function(inBytes) if provided, will deflate TLS records using + * the deflate algorithm if the server supports it. + * inflate: function(inBytes) if provided, will inflate TLS records using + * the deflate algorithm if the server supports it. + * + * @return the new TLS connection. + */ +forge$9.tls.createConnection = tls$1.createConnection; + +/** + * A Javascript implementation of AES Cipher Suites for TLS. + * + * @author Dave Longley + * + * Copyright (c) 2009-2015 Digital Bazaar, Inc. + * + */ + +var forge$8 = forge$D; + + + +var tls = forge$8.tls; + +/** + * Supported cipher suites. + */ +tls.CipherSuites['TLS_RSA_WITH_AES_128_CBC_SHA'] = { + id: [0x00, 0x2f], + name: 'TLS_RSA_WITH_AES_128_CBC_SHA', + initSecurityParameters: function(sp) { + sp.bulk_cipher_algorithm = tls.BulkCipherAlgorithm.aes; + sp.cipher_type = tls.CipherType.block; + sp.enc_key_length = 16; + sp.block_length = 16; + sp.fixed_iv_length = 16; + sp.record_iv_length = 16; + sp.mac_algorithm = tls.MACAlgorithm.hmac_sha1; + sp.mac_length = 20; + sp.mac_key_length = 20; + }, + initConnectionState: initConnectionState +}; +tls.CipherSuites['TLS_RSA_WITH_AES_256_CBC_SHA'] = { + id: [0x00, 0x35], + name: 'TLS_RSA_WITH_AES_256_CBC_SHA', + initSecurityParameters: function(sp) { + sp.bulk_cipher_algorithm = tls.BulkCipherAlgorithm.aes; + sp.cipher_type = tls.CipherType.block; + sp.enc_key_length = 32; + sp.block_length = 16; + sp.fixed_iv_length = 16; + sp.record_iv_length = 16; + sp.mac_algorithm = tls.MACAlgorithm.hmac_sha1; + sp.mac_length = 20; + sp.mac_key_length = 20; + }, + initConnectionState: initConnectionState +}; + +function initConnectionState(state, c, sp) { + var client = (c.entity === forge$8.tls.ConnectionEnd.client); + + // cipher setup + state.read.cipherState = { + init: false, + cipher: forge$8.cipher.createDecipher('AES-CBC', client ? + sp.keys.server_write_key : sp.keys.client_write_key), + iv: client ? sp.keys.server_write_IV : sp.keys.client_write_IV + }; + state.write.cipherState = { + init: false, + cipher: forge$8.cipher.createCipher('AES-CBC', client ? + sp.keys.client_write_key : sp.keys.server_write_key), + iv: client ? sp.keys.client_write_IV : sp.keys.server_write_IV + }; + state.read.cipherFunction = decrypt_aes_cbc_sha1; + state.write.cipherFunction = encrypt_aes_cbc_sha1; + + // MAC setup + state.read.macLength = state.write.macLength = sp.mac_length; + state.read.macFunction = state.write.macFunction = tls.hmac_sha1; +} + +/** + * Encrypts the TLSCompressed record into a TLSCipherText record using AES + * in CBC mode. + * + * @param record the TLSCompressed record to encrypt. + * @param s the ConnectionState to use. + * + * @return true on success, false on failure. + */ +function encrypt_aes_cbc_sha1(record, s) { + var rval = false; + + // append MAC to fragment, update sequence number + var mac = s.macFunction(s.macKey, s.sequenceNumber, record); + record.fragment.putBytes(mac); + s.updateSequenceNumber(); + + // TLS 1.1+ use an explicit IV every time to protect against CBC attacks + var iv; + if(record.version.minor === tls.Versions.TLS_1_0.minor) { + // use the pre-generated IV when initializing for TLS 1.0, otherwise use + // the residue from the previous encryption + iv = s.cipherState.init ? null : s.cipherState.iv; + } else { + iv = forge$8.random.getBytesSync(16); + } + + s.cipherState.init = true; + + // start cipher + var cipher = s.cipherState.cipher; + cipher.start({iv: iv}); + + // TLS 1.1+ write IV into output + if(record.version.minor >= tls.Versions.TLS_1_1.minor) { + cipher.output.putBytes(iv); + } + + // do encryption (default padding is appropriate) + cipher.update(record.fragment); + if(cipher.finish(encrypt_aes_cbc_sha1_padding)) { + // set record fragment to encrypted output + record.fragment = cipher.output; + record.length = record.fragment.length(); + rval = true; + } + + return rval; +} + +/** + * Handles padding for aes_cbc_sha1 in encrypt mode. + * + * @param blockSize the block size. + * @param input the input buffer. + * @param decrypt true in decrypt mode, false in encrypt mode. + * + * @return true on success, false on failure. + */ +function encrypt_aes_cbc_sha1_padding(blockSize, input, decrypt) { + /* The encrypted data length (TLSCiphertext.length) is one more than the sum + of SecurityParameters.block_length, TLSCompressed.length, + SecurityParameters.mac_length, and padding_length. + + The padding may be any length up to 255 bytes long, as long as it results in + the TLSCiphertext.length being an integral multiple of the block length. + Lengths longer than necessary might be desirable to frustrate attacks on a + protocol based on analysis of the lengths of exchanged messages. Each uint8 + in the padding data vector must be filled with the padding length value. + + The padding length should be such that the total size of the + GenericBlockCipher structure is a multiple of the cipher's block length. + Legal values range from zero to 255, inclusive. This length specifies the + length of the padding field exclusive of the padding_length field itself. + + This is slightly different from PKCS#7 because the padding value is 1 + less than the actual number of padding bytes if you include the + padding_length uint8 itself as a padding byte. */ + if(!decrypt) { + // get the number of padding bytes required to reach the blockSize and + // subtract 1 for the padding value (to make room for the padding_length + // uint8) + var padding = blockSize - (input.length() % blockSize); + input.fillWithByte(padding - 1, padding); + } + return true; +} + +/** + * Handles padding for aes_cbc_sha1 in decrypt mode. + * + * @param blockSize the block size. + * @param output the output buffer. + * @param decrypt true in decrypt mode, false in encrypt mode. + * + * @return true on success, false on failure. + */ +function decrypt_aes_cbc_sha1_padding(blockSize, output, decrypt) { + var rval = true; + if(decrypt) { + /* The last byte in the output specifies the number of padding bytes not + including itself. Each of the padding bytes has the same value as that + last byte (known as the padding_length). Here we check all padding + bytes to ensure they have the value of padding_length even if one of + them is bad in order to ward-off timing attacks. */ + var len = output.length(); + var paddingLength = output.last(); + for(var i = len - 1 - paddingLength; i < len - 1; ++i) { + rval = rval && (output.at(i) == paddingLength); + } + if(rval) { + // trim off padding bytes and last padding length byte + output.truncate(paddingLength + 1); + } + } + return rval; +} + +/** + * Decrypts a TLSCipherText record into a TLSCompressed record using + * AES in CBC mode. + * + * @param record the TLSCipherText record to decrypt. + * @param s the ConnectionState to use. + * + * @return true on success, false on failure. + */ +function decrypt_aes_cbc_sha1(record, s) { + var rval = false; + + var iv; + if(record.version.minor === tls.Versions.TLS_1_0.minor) { + // use pre-generated IV when initializing for TLS 1.0, otherwise use the + // residue from the previous decryption + iv = s.cipherState.init ? null : s.cipherState.iv; + } else { + // TLS 1.1+ use an explicit IV every time to protect against CBC attacks + // that is appended to the record fragment + iv = record.fragment.getBytes(16); + } + + s.cipherState.init = true; + + // start cipher + var cipher = s.cipherState.cipher; + cipher.start({iv: iv}); + + // do decryption + cipher.update(record.fragment); + rval = cipher.finish(decrypt_aes_cbc_sha1_padding); + + // even if decryption fails, keep going to minimize timing attacks + + // decrypted data: + // first (len - 20) bytes = application data + // last 20 bytes = MAC + var macLen = s.macLength; + + // create a random MAC to check against should the mac length check fail + // Note: do this regardless of the failure to keep timing consistent + var mac = forge$8.random.getBytesSync(macLen); + + // get fragment and mac + var len = cipher.output.length(); + if(len >= macLen) { + record.fragment = cipher.output.getBytes(len - macLen); + mac = cipher.output.getBytes(macLen); + } else { + // bad data, but get bytes anyway to try to keep timing consistent + record.fragment = cipher.output.getBytes(); + } + record.fragment = forge$8.util.createBuffer(record.fragment); + record.length = record.fragment.length(); + + // see if data integrity checks out, update sequence number + var mac2 = s.macFunction(s.macKey, s.sequenceNumber, record); + s.updateSequenceNumber(); + rval = compareMacs(s.macKey, mac, mac2) && rval; + return rval; +} + +/** + * Safely compare two MACs. This function will compare two MACs in a way + * that protects against timing attacks. + * + * TODO: Expose elsewhere as a utility API. + * + * See: https://www.nccgroup.trust/us/about-us/newsroom-and-events/blog/2011/february/double-hmac-verification/ + * + * @param key the MAC key to use. + * @param mac1 as a binary-encoded string of bytes. + * @param mac2 as a binary-encoded string of bytes. + * + * @return true if the MACs are the same, false if not. + */ +function compareMacs(key, mac1, mac2) { + var hmac = forge$8.hmac.create(); + + hmac.start('SHA1', key); + hmac.update(mac1); + mac1 = hmac.digest().getBytes(); + + hmac.start(null, null); + hmac.update(mac2); + mac2 = hmac.digest().getBytes(); + + return mac1 === mac2; +} + +/** + * Secure Hash Algorithm with a 1024-bit block size implementation. + * + * This includes: SHA-512, SHA-384, SHA-512/224, and SHA-512/256. For + * SHA-256 (block size 512 bits), see sha256.js. + * + * See FIPS 180-4 for details. + * + * @author Dave Longley + * + * Copyright (c) 2014-2015 Digital Bazaar, Inc. + */ + +var forge$7 = forge$D; + + + +var sha512$1 = forge$7.sha512 = forge$7.sha512 || {}; + +// SHA-512 +forge$7.md.sha512 = forge$7.md.algorithms.sha512 = sha512$1; + +// SHA-384 +var sha384 = forge$7.sha384 = forge$7.sha512.sha384 = forge$7.sha512.sha384 || {}; +sha384.create = function() { + return sha512$1.create('SHA-384'); +}; +forge$7.md.sha384 = forge$7.md.algorithms.sha384 = sha384; + +// SHA-512/256 +forge$7.sha512.sha256 = forge$7.sha512.sha256 || { + create: function() { + return sha512$1.create('SHA-512/256'); + } +}; +forge$7.md['sha512/256'] = forge$7.md.algorithms['sha512/256'] = + forge$7.sha512.sha256; + +// SHA-512/224 +forge$7.sha512.sha224 = forge$7.sha512.sha224 || { + create: function() { + return sha512$1.create('SHA-512/224'); + } +}; +forge$7.md['sha512/224'] = forge$7.md.algorithms['sha512/224'] = + forge$7.sha512.sha224; + +/** + * Creates a SHA-2 message digest object. + * + * @param algorithm the algorithm to use (SHA-512, SHA-384, SHA-512/224, + * SHA-512/256). + * + * @return a message digest object. + */ +sha512$1.create = function(algorithm) { + // do initialization as necessary + if(!_initialized) { + _init(); + } + + if(typeof algorithm === 'undefined') { + algorithm = 'SHA-512'; + } + + if(!(algorithm in _states)) { + throw new Error('Invalid SHA-512 algorithm: ' + algorithm); + } + + // SHA-512 state contains eight 64-bit integers (each as two 32-bit ints) + var _state = _states[algorithm]; + var _h = null; + + // input buffer + var _input = forge$7.util.createBuffer(); + + // used for 64-bit word storage + var _w = new Array(80); + for(var wi = 0; wi < 80; ++wi) { + _w[wi] = new Array(2); + } + + // determine digest length by algorithm name (default) + var digestLength = 64; + switch(algorithm) { + case 'SHA-384': + digestLength = 48; + break; + case 'SHA-512/256': + digestLength = 32; + break; + case 'SHA-512/224': + digestLength = 28; + break; + } + + // message digest object + var md = { + // SHA-512 => sha512 + algorithm: algorithm.replace('-', '').toLowerCase(), + blockLength: 128, + digestLength: digestLength, + // 56-bit length of message so far (does not including padding) + messageLength: 0, + // true message length + fullMessageLength: null, + // size of message length in bytes + messageLengthSize: 16 + }; + + /** + * Starts the digest. + * + * @return this digest object. + */ + md.start = function() { + // up to 56-bit message length for convenience + md.messageLength = 0; + + // full message length (set md.messageLength128 for backwards-compatibility) + md.fullMessageLength = md.messageLength128 = []; + var int32s = md.messageLengthSize / 4; + for(var i = 0; i < int32s; ++i) { + md.fullMessageLength.push(0); + } + _input = forge$7.util.createBuffer(); + _h = new Array(_state.length); + for(var i = 0; i < _state.length; ++i) { + _h[i] = _state[i].slice(0); + } + return md; + }; + // start digest automatically for first time + md.start(); + + /** + * Updates the digest with the given message input. The given input can + * treated as raw input (no encoding will be applied) or an encoding of + * 'utf8' maybe given to encode the input using UTF-8. + * + * @param msg the message input to update with. + * @param encoding the encoding to use (default: 'raw', other: 'utf8'). + * + * @return this digest object. + */ + md.update = function(msg, encoding) { + if(encoding === 'utf8') { + msg = forge$7.util.encodeUtf8(msg); + } + + // update message length + var len = msg.length; + md.messageLength += len; + len = [(len / 0x100000000) >>> 0, len >>> 0]; + for(var i = md.fullMessageLength.length - 1; i >= 0; --i) { + md.fullMessageLength[i] += len[1]; + len[1] = len[0] + ((md.fullMessageLength[i] / 0x100000000) >>> 0); + md.fullMessageLength[i] = md.fullMessageLength[i] >>> 0; + len[0] = ((len[1] / 0x100000000) >>> 0); + } + + // add bytes to input buffer + _input.putBytes(msg); + + // process bytes + _update(_h, _w, _input); + + // compact input buffer every 2K or if empty + if(_input.read > 2048 || _input.length() === 0) { + _input.compact(); + } + + return md; + }; + + /** + * Produces the digest. + * + * @return a byte buffer containing the digest value. + */ + md.digest = function() { + /* Note: Here we copy the remaining bytes in the input buffer and + add the appropriate SHA-512 padding. Then we do the final update + on a copy of the state so that if the user wants to get + intermediate digests they can do so. */ + + /* Determine the number of bytes that must be added to the message + to ensure its length is congruent to 896 mod 1024. In other words, + the data to be digested must be a multiple of 1024 bits (or 128 bytes). + This data includes the message, some padding, and the length of the + message. Since the length of the message will be encoded as 16 bytes (128 + bits), that means that the last segment of the data must have 112 bytes + (896 bits) of message and padding. Therefore, the length of the message + plus the padding must be congruent to 896 mod 1024 because + 1024 - 128 = 896. + + In order to fill up the message length it must be filled with + padding that begins with 1 bit followed by all 0 bits. Padding + must *always* be present, so if the message length is already + congruent to 896 mod 1024, then 1024 padding bits must be added. */ + + var finalBlock = forge$7.util.createBuffer(); + finalBlock.putBytes(_input.bytes()); + + // compute remaining size to be digested (include message length size) + var remaining = ( + md.fullMessageLength[md.fullMessageLength.length - 1] + + md.messageLengthSize); + + // add padding for overflow blockSize - overflow + // _padding starts with 1 byte with first bit is set (byte value 128), then + // there may be up to (blockSize - 1) other pad bytes + var overflow = remaining & (md.blockLength - 1); + finalBlock.putBytes(_padding.substr(0, md.blockLength - overflow)); + + // serialize message length in bits in big-endian order; since length + // is stored in bytes we multiply by 8 and add carry from next int + var next, carry; + var bits = md.fullMessageLength[0] * 8; + for(var i = 0; i < md.fullMessageLength.length - 1; ++i) { + next = md.fullMessageLength[i + 1] * 8; + carry = (next / 0x100000000) >>> 0; + bits += carry; + finalBlock.putInt32(bits >>> 0); + bits = next >>> 0; + } + finalBlock.putInt32(bits); + + var h = new Array(_h.length); + for(var i = 0; i < _h.length; ++i) { + h[i] = _h[i].slice(0); + } + _update(h, _w, finalBlock); + var rval = forge$7.util.createBuffer(); + var hlen; + if(algorithm === 'SHA-512') { + hlen = h.length; + } else if(algorithm === 'SHA-384') { + hlen = h.length - 2; + } else { + hlen = h.length - 4; + } + for(var i = 0; i < hlen; ++i) { + rval.putInt32(h[i][0]); + if(i !== hlen - 1 || algorithm !== 'SHA-512/224') { + rval.putInt32(h[i][1]); + } + } + return rval; + }; + + return md; +}; + +// sha-512 padding bytes not initialized yet +var _padding = null; +var _initialized = false; + +// table of constants +var _k = null; + +// initial hash states +var _states = null; + +/** + * Initializes the constant tables. + */ +function _init() { + // create padding + _padding = String.fromCharCode(128); + _padding += forge$7.util.fillString(String.fromCharCode(0x00), 128); + + // create K table for SHA-512 + _k = [ + [0x428a2f98, 0xd728ae22], [0x71374491, 0x23ef65cd], + [0xb5c0fbcf, 0xec4d3b2f], [0xe9b5dba5, 0x8189dbbc], + [0x3956c25b, 0xf348b538], [0x59f111f1, 0xb605d019], + [0x923f82a4, 0xaf194f9b], [0xab1c5ed5, 0xda6d8118], + [0xd807aa98, 0xa3030242], [0x12835b01, 0x45706fbe], + [0x243185be, 0x4ee4b28c], [0x550c7dc3, 0xd5ffb4e2], + [0x72be5d74, 0xf27b896f], [0x80deb1fe, 0x3b1696b1], + [0x9bdc06a7, 0x25c71235], [0xc19bf174, 0xcf692694], + [0xe49b69c1, 0x9ef14ad2], [0xefbe4786, 0x384f25e3], + [0x0fc19dc6, 0x8b8cd5b5], [0x240ca1cc, 0x77ac9c65], + [0x2de92c6f, 0x592b0275], [0x4a7484aa, 0x6ea6e483], + [0x5cb0a9dc, 0xbd41fbd4], [0x76f988da, 0x831153b5], + [0x983e5152, 0xee66dfab], [0xa831c66d, 0x2db43210], + [0xb00327c8, 0x98fb213f], [0xbf597fc7, 0xbeef0ee4], + [0xc6e00bf3, 0x3da88fc2], [0xd5a79147, 0x930aa725], + [0x06ca6351, 0xe003826f], [0x14292967, 0x0a0e6e70], + [0x27b70a85, 0x46d22ffc], [0x2e1b2138, 0x5c26c926], + [0x4d2c6dfc, 0x5ac42aed], [0x53380d13, 0x9d95b3df], + [0x650a7354, 0x8baf63de], [0x766a0abb, 0x3c77b2a8], + [0x81c2c92e, 0x47edaee6], [0x92722c85, 0x1482353b], + [0xa2bfe8a1, 0x4cf10364], [0xa81a664b, 0xbc423001], + [0xc24b8b70, 0xd0f89791], [0xc76c51a3, 0x0654be30], + [0xd192e819, 0xd6ef5218], [0xd6990624, 0x5565a910], + [0xf40e3585, 0x5771202a], [0x106aa070, 0x32bbd1b8], + [0x19a4c116, 0xb8d2d0c8], [0x1e376c08, 0x5141ab53], + [0x2748774c, 0xdf8eeb99], [0x34b0bcb5, 0xe19b48a8], + [0x391c0cb3, 0xc5c95a63], [0x4ed8aa4a, 0xe3418acb], + [0x5b9cca4f, 0x7763e373], [0x682e6ff3, 0xd6b2b8a3], + [0x748f82ee, 0x5defb2fc], [0x78a5636f, 0x43172f60], + [0x84c87814, 0xa1f0ab72], [0x8cc70208, 0x1a6439ec], + [0x90befffa, 0x23631e28], [0xa4506ceb, 0xde82bde9], + [0xbef9a3f7, 0xb2c67915], [0xc67178f2, 0xe372532b], + [0xca273ece, 0xea26619c], [0xd186b8c7, 0x21c0c207], + [0xeada7dd6, 0xcde0eb1e], [0xf57d4f7f, 0xee6ed178], + [0x06f067aa, 0x72176fba], [0x0a637dc5, 0xa2c898a6], + [0x113f9804, 0xbef90dae], [0x1b710b35, 0x131c471b], + [0x28db77f5, 0x23047d84], [0x32caab7b, 0x40c72493], + [0x3c9ebe0a, 0x15c9bebc], [0x431d67c4, 0x9c100d4c], + [0x4cc5d4be, 0xcb3e42b6], [0x597f299c, 0xfc657e2a], + [0x5fcb6fab, 0x3ad6faec], [0x6c44198c, 0x4a475817] + ]; + + // initial hash states + _states = {}; + _states['SHA-512'] = [ + [0x6a09e667, 0xf3bcc908], + [0xbb67ae85, 0x84caa73b], + [0x3c6ef372, 0xfe94f82b], + [0xa54ff53a, 0x5f1d36f1], + [0x510e527f, 0xade682d1], + [0x9b05688c, 0x2b3e6c1f], + [0x1f83d9ab, 0xfb41bd6b], + [0x5be0cd19, 0x137e2179] + ]; + _states['SHA-384'] = [ + [0xcbbb9d5d, 0xc1059ed8], + [0x629a292a, 0x367cd507], + [0x9159015a, 0x3070dd17], + [0x152fecd8, 0xf70e5939], + [0x67332667, 0xffc00b31], + [0x8eb44a87, 0x68581511], + [0xdb0c2e0d, 0x64f98fa7], + [0x47b5481d, 0xbefa4fa4] + ]; + _states['SHA-512/256'] = [ + [0x22312194, 0xFC2BF72C], + [0x9F555FA3, 0xC84C64C2], + [0x2393B86B, 0x6F53B151], + [0x96387719, 0x5940EABD], + [0x96283EE2, 0xA88EFFE3], + [0xBE5E1E25, 0x53863992], + [0x2B0199FC, 0x2C85B8AA], + [0x0EB72DDC, 0x81C52CA2] + ]; + _states['SHA-512/224'] = [ + [0x8C3D37C8, 0x19544DA2], + [0x73E19966, 0x89DCD4D6], + [0x1DFAB7AE, 0x32FF9C82], + [0x679DD514, 0x582F9FCF], + [0x0F6D2B69, 0x7BD44DA8], + [0x77E36F73, 0x04C48942], + [0x3F9D85A8, 0x6A1D36C8], + [0x1112E6AD, 0x91D692A1] + ]; + + // now initialized + _initialized = true; +} + +/** + * Updates a SHA-512 state with the given byte buffer. + * + * @param s the SHA-512 state to update. + * @param w the array to use to store words. + * @param bytes the byte buffer to update with. + */ +function _update(s, w, bytes) { + // consume 512 bit (128 byte) chunks + var t1_hi, t1_lo; + var t2_hi, t2_lo; + var s0_hi, s0_lo; + var s1_hi, s1_lo; + var ch_hi, ch_lo; + var maj_hi, maj_lo; + var a_hi, a_lo; + var b_hi, b_lo; + var c_hi, c_lo; + var d_hi, d_lo; + var e_hi, e_lo; + var f_hi, f_lo; + var g_hi, g_lo; + var h_hi, h_lo; + var i, hi, lo, w2, w7, w15, w16; + var len = bytes.length(); + while(len >= 128) { + // the w array will be populated with sixteen 64-bit big-endian words + // and then extended into 64 64-bit words according to SHA-512 + for(i = 0; i < 16; ++i) { + w[i][0] = bytes.getInt32() >>> 0; + w[i][1] = bytes.getInt32() >>> 0; + } + for(; i < 80; ++i) { + // for word 2 words ago: ROTR 19(x) ^ ROTR 61(x) ^ SHR 6(x) + w2 = w[i - 2]; + hi = w2[0]; + lo = w2[1]; + + // high bits + t1_hi = ( + ((hi >>> 19) | (lo << 13)) ^ // ROTR 19 + ((lo >>> 29) | (hi << 3)) ^ // ROTR 61/(swap + ROTR 29) + (hi >>> 6)) >>> 0; // SHR 6 + // low bits + t1_lo = ( + ((hi << 13) | (lo >>> 19)) ^ // ROTR 19 + ((lo << 3) | (hi >>> 29)) ^ // ROTR 61/(swap + ROTR 29) + ((hi << 26) | (lo >>> 6))) >>> 0; // SHR 6 + + // for word 15 words ago: ROTR 1(x) ^ ROTR 8(x) ^ SHR 7(x) + w15 = w[i - 15]; + hi = w15[0]; + lo = w15[1]; + + // high bits + t2_hi = ( + ((hi >>> 1) | (lo << 31)) ^ // ROTR 1 + ((hi >>> 8) | (lo << 24)) ^ // ROTR 8 + (hi >>> 7)) >>> 0; // SHR 7 + // low bits + t2_lo = ( + ((hi << 31) | (lo >>> 1)) ^ // ROTR 1 + ((hi << 24) | (lo >>> 8)) ^ // ROTR 8 + ((hi << 25) | (lo >>> 7))) >>> 0; // SHR 7 + + // sum(t1, word 7 ago, t2, word 16 ago) modulo 2^64 (carry lo overflow) + w7 = w[i - 7]; + w16 = w[i - 16]; + lo = (t1_lo + w7[1] + t2_lo + w16[1]); + w[i][0] = (t1_hi + w7[0] + t2_hi + w16[0] + + ((lo / 0x100000000) >>> 0)) >>> 0; + w[i][1] = lo >>> 0; + } + + // initialize hash value for this chunk + a_hi = s[0][0]; + a_lo = s[0][1]; + b_hi = s[1][0]; + b_lo = s[1][1]; + c_hi = s[2][0]; + c_lo = s[2][1]; + d_hi = s[3][0]; + d_lo = s[3][1]; + e_hi = s[4][0]; + e_lo = s[4][1]; + f_hi = s[5][0]; + f_lo = s[5][1]; + g_hi = s[6][0]; + g_lo = s[6][1]; + h_hi = s[7][0]; + h_lo = s[7][1]; + + // round function + for(i = 0; i < 80; ++i) { + // Sum1(e) = ROTR 14(e) ^ ROTR 18(e) ^ ROTR 41(e) + s1_hi = ( + ((e_hi >>> 14) | (e_lo << 18)) ^ // ROTR 14 + ((e_hi >>> 18) | (e_lo << 14)) ^ // ROTR 18 + ((e_lo >>> 9) | (e_hi << 23))) >>> 0; // ROTR 41/(swap + ROTR 9) + s1_lo = ( + ((e_hi << 18) | (e_lo >>> 14)) ^ // ROTR 14 + ((e_hi << 14) | (e_lo >>> 18)) ^ // ROTR 18 + ((e_lo << 23) | (e_hi >>> 9))) >>> 0; // ROTR 41/(swap + ROTR 9) + + // Ch(e, f, g) (optimized the same way as SHA-1) + ch_hi = (g_hi ^ (e_hi & (f_hi ^ g_hi))) >>> 0; + ch_lo = (g_lo ^ (e_lo & (f_lo ^ g_lo))) >>> 0; + + // Sum0(a) = ROTR 28(a) ^ ROTR 34(a) ^ ROTR 39(a) + s0_hi = ( + ((a_hi >>> 28) | (a_lo << 4)) ^ // ROTR 28 + ((a_lo >>> 2) | (a_hi << 30)) ^ // ROTR 34/(swap + ROTR 2) + ((a_lo >>> 7) | (a_hi << 25))) >>> 0; // ROTR 39/(swap + ROTR 7) + s0_lo = ( + ((a_hi << 4) | (a_lo >>> 28)) ^ // ROTR 28 + ((a_lo << 30) | (a_hi >>> 2)) ^ // ROTR 34/(swap + ROTR 2) + ((a_lo << 25) | (a_hi >>> 7))) >>> 0; // ROTR 39/(swap + ROTR 7) + + // Maj(a, b, c) (optimized the same way as SHA-1) + maj_hi = ((a_hi & b_hi) | (c_hi & (a_hi ^ b_hi))) >>> 0; + maj_lo = ((a_lo & b_lo) | (c_lo & (a_lo ^ b_lo))) >>> 0; + + // main algorithm + // t1 = (h + s1 + ch + _k[i] + _w[i]) modulo 2^64 (carry lo overflow) + lo = (h_lo + s1_lo + ch_lo + _k[i][1] + w[i][1]); + t1_hi = (h_hi + s1_hi + ch_hi + _k[i][0] + w[i][0] + + ((lo / 0x100000000) >>> 0)) >>> 0; + t1_lo = lo >>> 0; + + // t2 = s0 + maj modulo 2^64 (carry lo overflow) + lo = s0_lo + maj_lo; + t2_hi = (s0_hi + maj_hi + ((lo / 0x100000000) >>> 0)) >>> 0; + t2_lo = lo >>> 0; + + h_hi = g_hi; + h_lo = g_lo; + + g_hi = f_hi; + g_lo = f_lo; + + f_hi = e_hi; + f_lo = e_lo; + + // e = (d + t1) modulo 2^64 (carry lo overflow) + lo = d_lo + t1_lo; + e_hi = (d_hi + t1_hi + ((lo / 0x100000000) >>> 0)) >>> 0; + e_lo = lo >>> 0; + + d_hi = c_hi; + d_lo = c_lo; + + c_hi = b_hi; + c_lo = b_lo; + + b_hi = a_hi; + b_lo = a_lo; + + // a = (t1 + t2) modulo 2^64 (carry lo overflow) + lo = t1_lo + t2_lo; + a_hi = (t1_hi + t2_hi + ((lo / 0x100000000) >>> 0)) >>> 0; + a_lo = lo >>> 0; + } + + // update hash state (additional modulo 2^64) + lo = s[0][1] + a_lo; + s[0][0] = (s[0][0] + a_hi + ((lo / 0x100000000) >>> 0)) >>> 0; + s[0][1] = lo >>> 0; + + lo = s[1][1] + b_lo; + s[1][0] = (s[1][0] + b_hi + ((lo / 0x100000000) >>> 0)) >>> 0; + s[1][1] = lo >>> 0; + + lo = s[2][1] + c_lo; + s[2][0] = (s[2][0] + c_hi + ((lo / 0x100000000) >>> 0)) >>> 0; + s[2][1] = lo >>> 0; + + lo = s[3][1] + d_lo; + s[3][0] = (s[3][0] + d_hi + ((lo / 0x100000000) >>> 0)) >>> 0; + s[3][1] = lo >>> 0; + + lo = s[4][1] + e_lo; + s[4][0] = (s[4][0] + e_hi + ((lo / 0x100000000) >>> 0)) >>> 0; + s[4][1] = lo >>> 0; + + lo = s[5][1] + f_lo; + s[5][0] = (s[5][0] + f_hi + ((lo / 0x100000000) >>> 0)) >>> 0; + s[5][1] = lo >>> 0; + + lo = s[6][1] + g_lo; + s[6][0] = (s[6][0] + g_hi + ((lo / 0x100000000) >>> 0)) >>> 0; + s[6][1] = lo >>> 0; + + lo = s[7][1] + h_lo; + s[7][0] = (s[7][0] + h_hi + ((lo / 0x100000000) >>> 0)) >>> 0; + s[7][1] = lo >>> 0; + + len -= 128; + } +} + +var asn1Validator$1 = {}; + +/** + * Copyright (c) 2019 Digital Bazaar, Inc. + */ + +var forge$6 = forge$D; + +var asn1$1 = forge$6.asn1; + +asn1Validator$1.privateKeyValidator = { + // PrivateKeyInfo + name: 'PrivateKeyInfo', + tagClass: asn1$1.Class.UNIVERSAL, + type: asn1$1.Type.SEQUENCE, + constructed: true, + value: [{ + // Version (INTEGER) + name: 'PrivateKeyInfo.version', + tagClass: asn1$1.Class.UNIVERSAL, + type: asn1$1.Type.INTEGER, + constructed: false, + capture: 'privateKeyVersion' + }, { + // privateKeyAlgorithm + name: 'PrivateKeyInfo.privateKeyAlgorithm', + tagClass: asn1$1.Class.UNIVERSAL, + type: asn1$1.Type.SEQUENCE, + constructed: true, + value: [{ + name: 'AlgorithmIdentifier.algorithm', + tagClass: asn1$1.Class.UNIVERSAL, + type: asn1$1.Type.OID, + constructed: false, + capture: 'privateKeyOid' + }] + }, { + // PrivateKey + name: 'PrivateKeyInfo', + tagClass: asn1$1.Class.UNIVERSAL, + type: asn1$1.Type.OCTETSTRING, + constructed: false, + capture: 'privateKey' + }] +}; + +asn1Validator$1.publicKeyValidator = { + name: 'SubjectPublicKeyInfo', + tagClass: asn1$1.Class.UNIVERSAL, + type: asn1$1.Type.SEQUENCE, + constructed: true, + captureAsn1: 'subjectPublicKeyInfo', + value: [{ + name: 'SubjectPublicKeyInfo.AlgorithmIdentifier', + tagClass: asn1$1.Class.UNIVERSAL, + type: asn1$1.Type.SEQUENCE, + constructed: true, + value: [{ + name: 'AlgorithmIdentifier.algorithm', + tagClass: asn1$1.Class.UNIVERSAL, + type: asn1$1.Type.OID, + constructed: false, + capture: 'publicKeyOid' + }] + }, + // capture group for ed25519PublicKey + { + tagClass: asn1$1.Class.UNIVERSAL, + type: asn1$1.Type.BITSTRING, + constructed: false, + composed: true, + captureBitStringValue: 'ed25519PublicKey' + } + // FIXME: this is capture group for rsaPublicKey, use it in this API or + // discard? + /* { + // subjectPublicKey + name: 'SubjectPublicKeyInfo.subjectPublicKey', + tagClass: asn1.Class.UNIVERSAL, + type: asn1.Type.BITSTRING, + constructed: false, + value: [{ + // RSAPublicKey + name: 'SubjectPublicKeyInfo.subjectPublicKey.RSAPublicKey', + tagClass: asn1.Class.UNIVERSAL, + type: asn1.Type.SEQUENCE, + constructed: true, + optional: true, + captureAsn1: 'rsaPublicKey' + }] + } */ + ] +}; + +/** + * JavaScript implementation of Ed25519. + * + * Copyright (c) 2017-2019 Digital Bazaar, Inc. + * + * This implementation is based on the most excellent TweetNaCl which is + * in the public domain. Many thanks to its contributors: + * + * https://github.com/dchest/tweetnacl-js + */ + +var forge$5 = forge$D; + + + + +var asn1Validator = asn1Validator$1; +var publicKeyValidator = asn1Validator.publicKeyValidator; +var privateKeyValidator = asn1Validator.privateKeyValidator; + +if(typeof BigInteger$1 === 'undefined') { + var BigInteger$1 = forge$5.jsbn.BigInteger; +} + +var ByteBuffer = forge$5.util.ByteBuffer; +var NativeBuffer = typeof Buffer === 'undefined' ? Uint8Array : Buffer; + +/* + * Ed25519 algorithms, see RFC 8032: + * https://tools.ietf.org/html/rfc8032 + */ +forge$5.pki = forge$5.pki || {}; +forge$5.pki.ed25519 = forge$5.ed25519 = forge$5.ed25519 || {}; +var ed25519 = forge$5.ed25519; + +ed25519.constants = {}; +ed25519.constants.PUBLIC_KEY_BYTE_LENGTH = 32; +ed25519.constants.PRIVATE_KEY_BYTE_LENGTH = 64; +ed25519.constants.SEED_BYTE_LENGTH = 32; +ed25519.constants.SIGN_BYTE_LENGTH = 64; +ed25519.constants.HASH_BYTE_LENGTH = 64; + +ed25519.generateKeyPair = function(options) { + options = options || {}; + var seed = options.seed; + if(seed === undefined) { + // generate seed + seed = forge$5.random.getBytesSync(ed25519.constants.SEED_BYTE_LENGTH); + } else if(typeof seed === 'string') { + if(seed.length !== ed25519.constants.SEED_BYTE_LENGTH) { + throw new TypeError( + '"seed" must be ' + ed25519.constants.SEED_BYTE_LENGTH + + ' bytes in length.'); + } + } else if(!(seed instanceof Uint8Array)) { + throw new TypeError( + '"seed" must be a node.js Buffer, Uint8Array, or a binary string.'); + } + + seed = messageToNativeBuffer({message: seed, encoding: 'binary'}); + + var pk = new NativeBuffer(ed25519.constants.PUBLIC_KEY_BYTE_LENGTH); + var sk = new NativeBuffer(ed25519.constants.PRIVATE_KEY_BYTE_LENGTH); + for(var i = 0; i < 32; ++i) { + sk[i] = seed[i]; + } + crypto_sign_keypair(pk, sk); + return {publicKey: pk, privateKey: sk}; +}; + +/** + * Converts a private key from a RFC8410 ASN.1 encoding. + * + * @param obj - The asn1 representation of a private key. + * + * @returns {Object} keyInfo - The key information. + * @returns {Buffer|Uint8Array} keyInfo.privateKeyBytes - 32 private key bytes. + */ +ed25519.privateKeyFromAsn1 = function(obj) { + var capture = {}; + var errors = []; + var valid = forge$5.asn1.validate(obj, privateKeyValidator, capture, errors); + if(!valid) { + var error = new Error('Invalid Key.'); + error.errors = errors; + throw error; + } + var oid = forge$5.asn1.derToOid(capture.privateKeyOid); + var ed25519Oid = forge$5.oids.EdDSA25519; + if(oid !== ed25519Oid) { + throw new Error('Invalid OID "' + oid + '"; OID must be "' + + ed25519Oid + '".'); + } + var privateKey = capture.privateKey; + // manually extract the private key bytes from nested octet string, see FIXME: + // https://github.com/digitalbazaar/forge/blob/master/lib/asn1.js#L542 + var privateKeyBytes = messageToNativeBuffer({ + message: forge$5.asn1.fromDer(privateKey).value, + encoding: 'binary' + }); + // TODO: RFC8410 specifies a format for encoding the public key bytes along + // with the private key bytes. `publicKeyBytes` can be returned in the + // future. https://tools.ietf.org/html/rfc8410#section-10.3 + return {privateKeyBytes: privateKeyBytes}; +}; + +/** + * Converts a public key from a RFC8410 ASN.1 encoding. + * + * @param obj - The asn1 representation of a public key. + * + * @return {Buffer|Uint8Array} - 32 public key bytes. + */ +ed25519.publicKeyFromAsn1 = function(obj) { + // get SubjectPublicKeyInfo + var capture = {}; + var errors = []; + var valid = forge$5.asn1.validate(obj, publicKeyValidator, capture, errors); + if(!valid) { + var error = new Error('Invalid Key.'); + error.errors = errors; + throw error; + } + var oid = forge$5.asn1.derToOid(capture.publicKeyOid); + var ed25519Oid = forge$5.oids.EdDSA25519; + if(oid !== ed25519Oid) { + throw new Error('Invalid OID "' + oid + '"; OID must be "' + + ed25519Oid + '".'); + } + var publicKeyBytes = capture.ed25519PublicKey; + if(publicKeyBytes.length !== ed25519.constants.PUBLIC_KEY_BYTE_LENGTH) { + throw new Error('Key length is invalid.'); + } + return messageToNativeBuffer({ + message: publicKeyBytes, + encoding: 'binary' + }); +}; + +ed25519.publicKeyFromPrivateKey = function(options) { + options = options || {}; + var privateKey = messageToNativeBuffer({ + message: options.privateKey, encoding: 'binary' + }); + if(privateKey.length !== ed25519.constants.PRIVATE_KEY_BYTE_LENGTH) { + throw new TypeError( + '"options.privateKey" must have a byte length of ' + + ed25519.constants.PRIVATE_KEY_BYTE_LENGTH); + } + + var pk = new NativeBuffer(ed25519.constants.PUBLIC_KEY_BYTE_LENGTH); + for(var i = 0; i < pk.length; ++i) { + pk[i] = privateKey[32 + i]; + } + return pk; +}; + +ed25519.sign = function(options) { + options = options || {}; + var msg = messageToNativeBuffer(options); + var privateKey = messageToNativeBuffer({ + message: options.privateKey, + encoding: 'binary' + }); + if(privateKey.length === ed25519.constants.SEED_BYTE_LENGTH) { + var keyPair = ed25519.generateKeyPair({seed: privateKey}); + privateKey = keyPair.privateKey; + } else if(privateKey.length !== ed25519.constants.PRIVATE_KEY_BYTE_LENGTH) { + throw new TypeError( + '"options.privateKey" must have a byte length of ' + + ed25519.constants.SEED_BYTE_LENGTH + ' or ' + + ed25519.constants.PRIVATE_KEY_BYTE_LENGTH); + } + + var signedMsg = new NativeBuffer( + ed25519.constants.SIGN_BYTE_LENGTH + msg.length); + crypto_sign(signedMsg, msg, msg.length, privateKey); + + var sig = new NativeBuffer(ed25519.constants.SIGN_BYTE_LENGTH); + for(var i = 0; i < sig.length; ++i) { + sig[i] = signedMsg[i]; + } + return sig; +}; + +ed25519.verify = function(options) { + options = options || {}; + var msg = messageToNativeBuffer(options); + if(options.signature === undefined) { + throw new TypeError( + '"options.signature" must be a node.js Buffer, a Uint8Array, a forge ' + + 'ByteBuffer, or a binary string.'); + } + var sig = messageToNativeBuffer({ + message: options.signature, + encoding: 'binary' + }); + if(sig.length !== ed25519.constants.SIGN_BYTE_LENGTH) { + throw new TypeError( + '"options.signature" must have a byte length of ' + + ed25519.constants.SIGN_BYTE_LENGTH); + } + var publicKey = messageToNativeBuffer({ + message: options.publicKey, + encoding: 'binary' + }); + if(publicKey.length !== ed25519.constants.PUBLIC_KEY_BYTE_LENGTH) { + throw new TypeError( + '"options.publicKey" must have a byte length of ' + + ed25519.constants.PUBLIC_KEY_BYTE_LENGTH); + } + + var sm = new NativeBuffer(ed25519.constants.SIGN_BYTE_LENGTH + msg.length); + var m = new NativeBuffer(ed25519.constants.SIGN_BYTE_LENGTH + msg.length); + var i; + for(i = 0; i < ed25519.constants.SIGN_BYTE_LENGTH; ++i) { + sm[i] = sig[i]; + } + for(i = 0; i < msg.length; ++i) { + sm[i + ed25519.constants.SIGN_BYTE_LENGTH] = msg[i]; + } + return (crypto_sign_open(m, sm, sm.length, publicKey) >= 0); +}; + +function messageToNativeBuffer(options) { + var message = options.message; + if(message instanceof Uint8Array || message instanceof NativeBuffer) { + return message; + } + + var encoding = options.encoding; + if(message === undefined) { + if(options.md) { + // TODO: more rigorous validation that `md` is a MessageDigest + message = options.md.digest().getBytes(); + encoding = 'binary'; + } else { + throw new TypeError('"options.message" or "options.md" not specified.'); + } + } + + if(typeof message === 'string' && !encoding) { + throw new TypeError('"options.encoding" must be "binary" or "utf8".'); + } + + if(typeof message === 'string') { + if(typeof Buffer !== 'undefined') { + return Buffer.from(message, encoding); + } + message = new ByteBuffer(message, encoding); + } else if(!(message instanceof ByteBuffer)) { + throw new TypeError( + '"options.message" must be a node.js Buffer, a Uint8Array, a forge ' + + 'ByteBuffer, or a string with "options.encoding" specifying its ' + + 'encoding.'); + } + + // convert to native buffer + var buffer = new NativeBuffer(message.length()); + for(var i = 0; i < buffer.length; ++i) { + buffer[i] = message.at(i); + } + return buffer; +} + +var gf0 = gf(); +var gf1 = gf([1]); +var D = gf([ + 0x78a3, 0x1359, 0x4dca, 0x75eb, 0xd8ab, 0x4141, 0x0a4d, 0x0070, + 0xe898, 0x7779, 0x4079, 0x8cc7, 0xfe73, 0x2b6f, 0x6cee, 0x5203]); +var D2 = gf([ + 0xf159, 0x26b2, 0x9b94, 0xebd6, 0xb156, 0x8283, 0x149a, 0x00e0, + 0xd130, 0xeef3, 0x80f2, 0x198e, 0xfce7, 0x56df, 0xd9dc, 0x2406]); +var X = gf([ + 0xd51a, 0x8f25, 0x2d60, 0xc956, 0xa7b2, 0x9525, 0xc760, 0x692c, + 0xdc5c, 0xfdd6, 0xe231, 0xc0a4, 0x53fe, 0xcd6e, 0x36d3, 0x2169]); +var Y = gf([ + 0x6658, 0x6666, 0x6666, 0x6666, 0x6666, 0x6666, 0x6666, 0x6666, + 0x6666, 0x6666, 0x6666, 0x6666, 0x6666, 0x6666, 0x6666, 0x6666]); +var L = new Float64Array([ + 0xed, 0xd3, 0xf5, 0x5c, 0x1a, 0x63, 0x12, 0x58, + 0xd6, 0x9c, 0xf7, 0xa2, 0xde, 0xf9, 0xde, 0x14, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0x10]); +var I = gf([ + 0xa0b0, 0x4a0e, 0x1b27, 0xc4ee, 0xe478, 0xad2f, 0x1806, 0x2f43, + 0xd7a7, 0x3dfb, 0x0099, 0x2b4d, 0xdf0b, 0x4fc1, 0x2480, 0x2b83]); + +// TODO: update forge buffer implementation to use `Buffer` or `Uint8Array`, +// whichever is available, to improve performance +function sha512(msg, msgLen) { + // Note: `out` and `msg` are NativeBuffer + var md = forge$5.md.sha512.create(); + var buffer = new ByteBuffer(msg); + md.update(buffer.getBytes(msgLen), 'binary'); + var hash = md.digest().getBytes(); + if(typeof Buffer !== 'undefined') { + return Buffer.from(hash, 'binary'); + } + var out = new NativeBuffer(ed25519.constants.HASH_BYTE_LENGTH); + for(var i = 0; i < 64; ++i) { + out[i] = hash.charCodeAt(i); + } + return out; +} + +function crypto_sign_keypair(pk, sk) { + var p = [gf(), gf(), gf(), gf()]; + var i; + + var d = sha512(sk, 32); + d[0] &= 248; + d[31] &= 127; + d[31] |= 64; + + scalarbase(p, d); + pack(pk, p); + + for(i = 0; i < 32; ++i) { + sk[i + 32] = pk[i]; + } + return 0; +} + +// Note: difference from C - smlen returned, not passed as argument. +function crypto_sign(sm, m, n, sk) { + var i, j, x = new Float64Array(64); + var p = [gf(), gf(), gf(), gf()]; + + var d = sha512(sk, 32); + d[0] &= 248; + d[31] &= 127; + d[31] |= 64; + + var smlen = n + 64; + for(i = 0; i < n; ++i) { + sm[64 + i] = m[i]; + } + for(i = 0; i < 32; ++i) { + sm[32 + i] = d[32 + i]; + } + + var r = sha512(sm.subarray(32), n + 32); + reduce(r); + scalarbase(p, r); + pack(sm, p); + + for(i = 32; i < 64; ++i) { + sm[i] = sk[i]; + } + var h = sha512(sm, n + 64); + reduce(h); + + for(i = 32; i < 64; ++i) { + x[i] = 0; + } + for(i = 0; i < 32; ++i) { + x[i] = r[i]; + } + for(i = 0; i < 32; ++i) { + for(j = 0; j < 32; j++) { + x[i + j] += h[i] * d[j]; + } + } + + modL(sm.subarray(32), x); + return smlen; +} + +function crypto_sign_open(m, sm, n, pk) { + var i, mlen; + var t = new NativeBuffer(32); + var p = [gf(), gf(), gf(), gf()], + q = [gf(), gf(), gf(), gf()]; + + mlen = -1; + if(n < 64) { + return -1; + } + + if(unpackneg(q, pk)) { + return -1; + } + + for(i = 0; i < n; ++i) { + m[i] = sm[i]; + } + for(i = 0; i < 32; ++i) { + m[i + 32] = pk[i]; + } + var h = sha512(m, n); + reduce(h); + scalarmult(p, q, h); + + scalarbase(q, sm.subarray(32)); + add(p, q); + pack(t, p); + + n -= 64; + if(crypto_verify_32(sm, 0, t, 0)) { + for(i = 0; i < n; ++i) { + m[i] = 0; + } + return -1; + } + + for(i = 0; i < n; ++i) { + m[i] = sm[i + 64]; + } + mlen = n; + return mlen; +} + +function modL(r, x) { + var carry, i, j, k; + for(i = 63; i >= 32; --i) { + carry = 0; + for(j = i - 32, k = i - 12; j < k; ++j) { + x[j] += carry - 16 * x[i] * L[j - (i - 32)]; + carry = (x[j] + 128) >> 8; + x[j] -= carry * 256; + } + x[j] += carry; + x[i] = 0; + } + carry = 0; + for(j = 0; j < 32; ++j) { + x[j] += carry - (x[31] >> 4) * L[j]; + carry = x[j] >> 8; + x[j] &= 255; + } + for(j = 0; j < 32; ++j) { + x[j] -= carry * L[j]; + } + for(i = 0; i < 32; ++i) { + x[i + 1] += x[i] >> 8; + r[i] = x[i] & 255; + } +} + +function reduce(r) { + var x = new Float64Array(64); + for(var i = 0; i < 64; ++i) { + x[i] = r[i]; + r[i] = 0; + } + modL(r, x); +} + +function add(p, q) { + var a = gf(), b = gf(), c = gf(), + d = gf(), e = gf(), f = gf(), + g = gf(), h = gf(), t = gf(); + + Z(a, p[1], p[0]); + Z(t, q[1], q[0]); + M(a, a, t); + A(b, p[0], p[1]); + A(t, q[0], q[1]); + M(b, b, t); + M(c, p[3], q[3]); + M(c, c, D2); + M(d, p[2], q[2]); + A(d, d, d); + Z(e, b, a); + Z(f, d, c); + A(g, d, c); + A(h, b, a); + + M(p[0], e, f); + M(p[1], h, g); + M(p[2], g, f); + M(p[3], e, h); +} + +function cswap(p, q, b) { + for(var i = 0; i < 4; ++i) { + sel25519(p[i], q[i], b); + } +} + +function pack(r, p) { + var tx = gf(), ty = gf(), zi = gf(); + inv25519(zi, p[2]); + M(tx, p[0], zi); + M(ty, p[1], zi); + pack25519(r, ty); + r[31] ^= par25519(tx) << 7; +} + +function pack25519(o, n) { + var i, j, b; + var m = gf(), t = gf(); + for(i = 0; i < 16; ++i) { + t[i] = n[i]; + } + car25519(t); + car25519(t); + car25519(t); + for(j = 0; j < 2; ++j) { + m[0] = t[0] - 0xffed; + for(i = 1; i < 15; ++i) { + m[i] = t[i] - 0xffff - ((m[i - 1] >> 16) & 1); + m[i-1] &= 0xffff; + } + m[15] = t[15] - 0x7fff - ((m[14] >> 16) & 1); + b = (m[15] >> 16) & 1; + m[14] &= 0xffff; + sel25519(t, m, 1 - b); + } + for (i = 0; i < 16; i++) { + o[2 * i] = t[i] & 0xff; + o[2 * i + 1] = t[i] >> 8; + } +} + +function unpackneg(r, p) { + var t = gf(), chk = gf(), num = gf(), + den = gf(), den2 = gf(), den4 = gf(), + den6 = gf(); + + set25519(r[2], gf1); + unpack25519(r[1], p); + S(num, r[1]); + M(den, num, D); + Z(num, num, r[2]); + A(den, r[2], den); + + S(den2, den); + S(den4, den2); + M(den6, den4, den2); + M(t, den6, num); + M(t, t, den); + + pow2523(t, t); + M(t, t, num); + M(t, t, den); + M(t, t, den); + M(r[0], t, den); + + S(chk, r[0]); + M(chk, chk, den); + if(neq25519(chk, num)) { + M(r[0], r[0], I); + } + + S(chk, r[0]); + M(chk, chk, den); + if(neq25519(chk, num)) { + return -1; + } + + if(par25519(r[0]) === (p[31] >> 7)) { + Z(r[0], gf0, r[0]); + } + + M(r[3], r[0], r[1]); + return 0; +} + +function unpack25519(o, n) { + var i; + for(i = 0; i < 16; ++i) { + o[i] = n[2 * i] + (n[2 * i + 1] << 8); + } + o[15] &= 0x7fff; +} + +function pow2523(o, i) { + var c = gf(); + var a; + for(a = 0; a < 16; ++a) { + c[a] = i[a]; + } + for(a = 250; a >= 0; --a) { + S(c, c); + if(a !== 1) { + M(c, c, i); + } + } + for(a = 0; a < 16; ++a) { + o[a] = c[a]; + } +} + +function neq25519(a, b) { + var c = new NativeBuffer(32); + var d = new NativeBuffer(32); + pack25519(c, a); + pack25519(d, b); + return crypto_verify_32(c, 0, d, 0); +} + +function crypto_verify_32(x, xi, y, yi) { + return vn(x, xi, y, yi, 32); +} + +function vn(x, xi, y, yi, n) { + var i, d = 0; + for(i = 0; i < n; ++i) { + d |= x[xi + i] ^ y[yi + i]; + } + return (1 & ((d - 1) >>> 8)) - 1; +} + +function par25519(a) { + var d = new NativeBuffer(32); + pack25519(d, a); + return d[0] & 1; +} + +function scalarmult(p, q, s) { + var b, i; + set25519(p[0], gf0); + set25519(p[1], gf1); + set25519(p[2], gf1); + set25519(p[3], gf0); + for(i = 255; i >= 0; --i) { + b = (s[(i / 8)|0] >> (i & 7)) & 1; + cswap(p, q, b); + add(q, p); + add(p, p); + cswap(p, q, b); + } +} + +function scalarbase(p, s) { + var q = [gf(), gf(), gf(), gf()]; + set25519(q[0], X); + set25519(q[1], Y); + set25519(q[2], gf1); + M(q[3], X, Y); + scalarmult(p, q, s); +} + +function set25519(r, a) { + var i; + for(i = 0; i < 16; i++) { + r[i] = a[i] | 0; + } +} + +function inv25519(o, i) { + var c = gf(); + var a; + for(a = 0; a < 16; ++a) { + c[a] = i[a]; + } + for(a = 253; a >= 0; --a) { + S(c, c); + if(a !== 2 && a !== 4) { + M(c, c, i); + } + } + for(a = 0; a < 16; ++a) { + o[a] = c[a]; + } +} + +function car25519(o) { + var i, v, c = 1; + for(i = 0; i < 16; ++i) { + v = o[i] + c + 65535; + c = Math.floor(v / 65536); + o[i] = v - c * 65536; + } + o[0] += c - 1 + 37 * (c - 1); +} + +function sel25519(p, q, b) { + var t, c = ~(b - 1); + for(var i = 0; i < 16; ++i) { + t = c & (p[i] ^ q[i]); + p[i] ^= t; + q[i] ^= t; + } +} + +function gf(init) { + var i, r = new Float64Array(16); + if(init) { + for(i = 0; i < init.length; ++i) { + r[i] = init[i]; + } + } + return r; +} + +function A(o, a, b) { + for(var i = 0; i < 16; ++i) { + o[i] = a[i] + b[i]; + } +} + +function Z(o, a, b) { + for(var i = 0; i < 16; ++i) { + o[i] = a[i] - b[i]; + } +} + +function S(o, a) { + M(o, a, a); +} + +function M(o, a, b) { + var v, c, + t0 = 0, t1 = 0, t2 = 0, t3 = 0, t4 = 0, t5 = 0, t6 = 0, t7 = 0, + t8 = 0, t9 = 0, t10 = 0, t11 = 0, t12 = 0, t13 = 0, t14 = 0, t15 = 0, + t16 = 0, t17 = 0, t18 = 0, t19 = 0, t20 = 0, t21 = 0, t22 = 0, t23 = 0, + t24 = 0, t25 = 0, t26 = 0, t27 = 0, t28 = 0, t29 = 0, t30 = 0, + b0 = b[0], + b1 = b[1], + b2 = b[2], + b3 = b[3], + b4 = b[4], + b5 = b[5], + b6 = b[6], + b7 = b[7], + b8 = b[8], + b9 = b[9], + b10 = b[10], + b11 = b[11], + b12 = b[12], + b13 = b[13], + b14 = b[14], + b15 = b[15]; + + v = a[0]; + t0 += v * b0; + t1 += v * b1; + t2 += v * b2; + t3 += v * b3; + t4 += v * b4; + t5 += v * b5; + t6 += v * b6; + t7 += v * b7; + t8 += v * b8; + t9 += v * b9; + t10 += v * b10; + t11 += v * b11; + t12 += v * b12; + t13 += v * b13; + t14 += v * b14; + t15 += v * b15; + v = a[1]; + t1 += v * b0; + t2 += v * b1; + t3 += v * b2; + t4 += v * b3; + t5 += v * b4; + t6 += v * b5; + t7 += v * b6; + t8 += v * b7; + t9 += v * b8; + t10 += v * b9; + t11 += v * b10; + t12 += v * b11; + t13 += v * b12; + t14 += v * b13; + t15 += v * b14; + t16 += v * b15; + v = a[2]; + t2 += v * b0; + t3 += v * b1; + t4 += v * b2; + t5 += v * b3; + t6 += v * b4; + t7 += v * b5; + t8 += v * b6; + t9 += v * b7; + t10 += v * b8; + t11 += v * b9; + t12 += v * b10; + t13 += v * b11; + t14 += v * b12; + t15 += v * b13; + t16 += v * b14; + t17 += v * b15; + v = a[3]; + t3 += v * b0; + t4 += v * b1; + t5 += v * b2; + t6 += v * b3; + t7 += v * b4; + t8 += v * b5; + t9 += v * b6; + t10 += v * b7; + t11 += v * b8; + t12 += v * b9; + t13 += v * b10; + t14 += v * b11; + t15 += v * b12; + t16 += v * b13; + t17 += v * b14; + t18 += v * b15; + v = a[4]; + t4 += v * b0; + t5 += v * b1; + t6 += v * b2; + t7 += v * b3; + t8 += v * b4; + t9 += v * b5; + t10 += v * b6; + t11 += v * b7; + t12 += v * b8; + t13 += v * b9; + t14 += v * b10; + t15 += v * b11; + t16 += v * b12; + t17 += v * b13; + t18 += v * b14; + t19 += v * b15; + v = a[5]; + t5 += v * b0; + t6 += v * b1; + t7 += v * b2; + t8 += v * b3; + t9 += v * b4; + t10 += v * b5; + t11 += v * b6; + t12 += v * b7; + t13 += v * b8; + t14 += v * b9; + t15 += v * b10; + t16 += v * b11; + t17 += v * b12; + t18 += v * b13; + t19 += v * b14; + t20 += v * b15; + v = a[6]; + t6 += v * b0; + t7 += v * b1; + t8 += v * b2; + t9 += v * b3; + t10 += v * b4; + t11 += v * b5; + t12 += v * b6; + t13 += v * b7; + t14 += v * b8; + t15 += v * b9; + t16 += v * b10; + t17 += v * b11; + t18 += v * b12; + t19 += v * b13; + t20 += v * b14; + t21 += v * b15; + v = a[7]; + t7 += v * b0; + t8 += v * b1; + t9 += v * b2; + t10 += v * b3; + t11 += v * b4; + t12 += v * b5; + t13 += v * b6; + t14 += v * b7; + t15 += v * b8; + t16 += v * b9; + t17 += v * b10; + t18 += v * b11; + t19 += v * b12; + t20 += v * b13; + t21 += v * b14; + t22 += v * b15; + v = a[8]; + t8 += v * b0; + t9 += v * b1; + t10 += v * b2; + t11 += v * b3; + t12 += v * b4; + t13 += v * b5; + t14 += v * b6; + t15 += v * b7; + t16 += v * b8; + t17 += v * b9; + t18 += v * b10; + t19 += v * b11; + t20 += v * b12; + t21 += v * b13; + t22 += v * b14; + t23 += v * b15; + v = a[9]; + t9 += v * b0; + t10 += v * b1; + t11 += v * b2; + t12 += v * b3; + t13 += v * b4; + t14 += v * b5; + t15 += v * b6; + t16 += v * b7; + t17 += v * b8; + t18 += v * b9; + t19 += v * b10; + t20 += v * b11; + t21 += v * b12; + t22 += v * b13; + t23 += v * b14; + t24 += v * b15; + v = a[10]; + t10 += v * b0; + t11 += v * b1; + t12 += v * b2; + t13 += v * b3; + t14 += v * b4; + t15 += v * b5; + t16 += v * b6; + t17 += v * b7; + t18 += v * b8; + t19 += v * b9; + t20 += v * b10; + t21 += v * b11; + t22 += v * b12; + t23 += v * b13; + t24 += v * b14; + t25 += v * b15; + v = a[11]; + t11 += v * b0; + t12 += v * b1; + t13 += v * b2; + t14 += v * b3; + t15 += v * b4; + t16 += v * b5; + t17 += v * b6; + t18 += v * b7; + t19 += v * b8; + t20 += v * b9; + t21 += v * b10; + t22 += v * b11; + t23 += v * b12; + t24 += v * b13; + t25 += v * b14; + t26 += v * b15; + v = a[12]; + t12 += v * b0; + t13 += v * b1; + t14 += v * b2; + t15 += v * b3; + t16 += v * b4; + t17 += v * b5; + t18 += v * b6; + t19 += v * b7; + t20 += v * b8; + t21 += v * b9; + t22 += v * b10; + t23 += v * b11; + t24 += v * b12; + t25 += v * b13; + t26 += v * b14; + t27 += v * b15; + v = a[13]; + t13 += v * b0; + t14 += v * b1; + t15 += v * b2; + t16 += v * b3; + t17 += v * b4; + t18 += v * b5; + t19 += v * b6; + t20 += v * b7; + t21 += v * b8; + t22 += v * b9; + t23 += v * b10; + t24 += v * b11; + t25 += v * b12; + t26 += v * b13; + t27 += v * b14; + t28 += v * b15; + v = a[14]; + t14 += v * b0; + t15 += v * b1; + t16 += v * b2; + t17 += v * b3; + t18 += v * b4; + t19 += v * b5; + t20 += v * b6; + t21 += v * b7; + t22 += v * b8; + t23 += v * b9; + t24 += v * b10; + t25 += v * b11; + t26 += v * b12; + t27 += v * b13; + t28 += v * b14; + t29 += v * b15; + v = a[15]; + t15 += v * b0; + t16 += v * b1; + t17 += v * b2; + t18 += v * b3; + t19 += v * b4; + t20 += v * b5; + t21 += v * b6; + t22 += v * b7; + t23 += v * b8; + t24 += v * b9; + t25 += v * b10; + t26 += v * b11; + t27 += v * b12; + t28 += v * b13; + t29 += v * b14; + t30 += v * b15; + + t0 += 38 * t16; + t1 += 38 * t17; + t2 += 38 * t18; + t3 += 38 * t19; + t4 += 38 * t20; + t5 += 38 * t21; + t6 += 38 * t22; + t7 += 38 * t23; + t8 += 38 * t24; + t9 += 38 * t25; + t10 += 38 * t26; + t11 += 38 * t27; + t12 += 38 * t28; + t13 += 38 * t29; + t14 += 38 * t30; + // t15 left as is + + // first car + c = 1; + v = t0 + c + 65535; c = Math.floor(v / 65536); t0 = v - c * 65536; + v = t1 + c + 65535; c = Math.floor(v / 65536); t1 = v - c * 65536; + v = t2 + c + 65535; c = Math.floor(v / 65536); t2 = v - c * 65536; + v = t3 + c + 65535; c = Math.floor(v / 65536); t3 = v - c * 65536; + v = t4 + c + 65535; c = Math.floor(v / 65536); t4 = v - c * 65536; + v = t5 + c + 65535; c = Math.floor(v / 65536); t5 = v - c * 65536; + v = t6 + c + 65535; c = Math.floor(v / 65536); t6 = v - c * 65536; + v = t7 + c + 65535; c = Math.floor(v / 65536); t7 = v - c * 65536; + v = t8 + c + 65535; c = Math.floor(v / 65536); t8 = v - c * 65536; + v = t9 + c + 65535; c = Math.floor(v / 65536); t9 = v - c * 65536; + v = t10 + c + 65535; c = Math.floor(v / 65536); t10 = v - c * 65536; + v = t11 + c + 65535; c = Math.floor(v / 65536); t11 = v - c * 65536; + v = t12 + c + 65535; c = Math.floor(v / 65536); t12 = v - c * 65536; + v = t13 + c + 65535; c = Math.floor(v / 65536); t13 = v - c * 65536; + v = t14 + c + 65535; c = Math.floor(v / 65536); t14 = v - c * 65536; + v = t15 + c + 65535; c = Math.floor(v / 65536); t15 = v - c * 65536; + t0 += c-1 + 37 * (c-1); + + // second car + c = 1; + v = t0 + c + 65535; c = Math.floor(v / 65536); t0 = v - c * 65536; + v = t1 + c + 65535; c = Math.floor(v / 65536); t1 = v - c * 65536; + v = t2 + c + 65535; c = Math.floor(v / 65536); t2 = v - c * 65536; + v = t3 + c + 65535; c = Math.floor(v / 65536); t3 = v - c * 65536; + v = t4 + c + 65535; c = Math.floor(v / 65536); t4 = v - c * 65536; + v = t5 + c + 65535; c = Math.floor(v / 65536); t5 = v - c * 65536; + v = t6 + c + 65535; c = Math.floor(v / 65536); t6 = v - c * 65536; + v = t7 + c + 65535; c = Math.floor(v / 65536); t7 = v - c * 65536; + v = t8 + c + 65535; c = Math.floor(v / 65536); t8 = v - c * 65536; + v = t9 + c + 65535; c = Math.floor(v / 65536); t9 = v - c * 65536; + v = t10 + c + 65535; c = Math.floor(v / 65536); t10 = v - c * 65536; + v = t11 + c + 65535; c = Math.floor(v / 65536); t11 = v - c * 65536; + v = t12 + c + 65535; c = Math.floor(v / 65536); t12 = v - c * 65536; + v = t13 + c + 65535; c = Math.floor(v / 65536); t13 = v - c * 65536; + v = t14 + c + 65535; c = Math.floor(v / 65536); t14 = v - c * 65536; + v = t15 + c + 65535; c = Math.floor(v / 65536); t15 = v - c * 65536; + t0 += c-1 + 37 * (c-1); + + o[ 0] = t0; + o[ 1] = t1; + o[ 2] = t2; + o[ 3] = t3; + o[ 4] = t4; + o[ 5] = t5; + o[ 6] = t6; + o[ 7] = t7; + o[ 8] = t8; + o[ 9] = t9; + o[10] = t10; + o[11] = t11; + o[12] = t12; + o[13] = t13; + o[14] = t14; + o[15] = t15; +} + +/** + * Javascript implementation of RSA-KEM. + * + * @author Lautaro Cozzani Rodriguez + * @author Dave Longley + * + * Copyright (c) 2014 Lautaro Cozzani + * Copyright (c) 2014 Digital Bazaar, Inc. + */ + +var forge$4 = forge$D; + + + + +forge$4.kem = forge$4.kem || {}; + +var BigInteger = forge$4.jsbn.BigInteger; + +/** + * The API for the RSA Key Encapsulation Mechanism (RSA-KEM) from ISO 18033-2. + */ +forge$4.kem.rsa = {}; + +/** + * Creates an RSA KEM API object for generating a secret asymmetric key. + * + * The symmetric key may be generated via a call to 'encrypt', which will + * produce a ciphertext to be transmitted to the recipient and a key to be + * kept secret. The ciphertext is a parameter to be passed to 'decrypt' which + * will produce the same secret key for the recipient to use to decrypt a + * message that was encrypted with the secret key. + * + * @param kdf the KDF API to use (eg: new forge.kem.kdf1()). + * @param options the options to use. + * [prng] a custom crypto-secure pseudo-random number generator to use, + * that must define "getBytesSync". + */ +forge$4.kem.rsa.create = function(kdf, options) { + options = options || {}; + var prng = options.prng || forge$4.random; + + var kem = {}; + + /** + * Generates a secret key and its encapsulation. + * + * @param publicKey the RSA public key to encrypt with. + * @param keyLength the length, in bytes, of the secret key to generate. + * + * @return an object with: + * encapsulation: the ciphertext for generating the secret key, as a + * binary-encoded string of bytes. + * key: the secret key to use for encrypting a message. + */ + kem.encrypt = function(publicKey, keyLength) { + // generate a random r where 1 < r < n + var byteLength = Math.ceil(publicKey.n.bitLength() / 8); + var r; + do { + r = new BigInteger( + forge$4.util.bytesToHex(prng.getBytesSync(byteLength)), + 16).mod(publicKey.n); + } while(r.compareTo(BigInteger.ONE) <= 0); + + // prepend r with zeros + r = forge$4.util.hexToBytes(r.toString(16)); + var zeros = byteLength - r.length; + if(zeros > 0) { + r = forge$4.util.fillString(String.fromCharCode(0), zeros) + r; + } + + // encrypt the random + var encapsulation = publicKey.encrypt(r, 'NONE'); + + // generate the secret key + var key = kdf.generate(r, keyLength); + + return {encapsulation: encapsulation, key: key}; + }; + + /** + * Decrypts an encapsulated secret key. + * + * @param privateKey the RSA private key to decrypt with. + * @param encapsulation the ciphertext for generating the secret key, as + * a binary-encoded string of bytes. + * @param keyLength the length, in bytes, of the secret key to generate. + * + * @return the secret key as a binary-encoded string of bytes. + */ + kem.decrypt = function(privateKey, encapsulation, keyLength) { + // decrypt the encapsulation and generate the secret key + var r = privateKey.decrypt(encapsulation, 'NONE'); + return kdf.generate(r, keyLength); + }; + + return kem; +}; + +// TODO: add forge.kem.kdf.create('KDF1', {md: ..., ...}) API? + +/** + * Creates a key derivation API object that implements KDF1 per ISO 18033-2. + * + * @param md the hash API to use. + * @param [digestLength] an optional digest length that must be positive and + * less than or equal to md.digestLength. + * + * @return a KDF1 API object. + */ +forge$4.kem.kdf1 = function(md, digestLength) { + _createKDF(this, md, 0, digestLength || md.digestLength); +}; + +/** + * Creates a key derivation API object that implements KDF2 per ISO 18033-2. + * + * @param md the hash API to use. + * @param [digestLength] an optional digest length that must be positive and + * less than or equal to md.digestLength. + * + * @return a KDF2 API object. + */ +forge$4.kem.kdf2 = function(md, digestLength) { + _createKDF(this, md, 1, digestLength || md.digestLength); +}; + +/** + * Creates a KDF1 or KDF2 API object. + * + * @param md the hash API to use. + * @param counterStart the starting index for the counter. + * @param digestLength the digest length to use. + * + * @return the KDF API object. + */ +function _createKDF(kdf, md, counterStart, digestLength) { + /** + * Generate a key of the specified length. + * + * @param x the binary-encoded byte string to generate a key from. + * @param length the number of bytes to generate (the size of the key). + * + * @return the key as a binary-encoded string. + */ + kdf.generate = function(x, length) { + var key = new forge$4.util.ByteBuffer(); + + // run counter from counterStart to ceil(length / Hash.len) + var k = Math.ceil(length / digestLength) + counterStart; + + var c = new forge$4.util.ByteBuffer(); + for(var i = counterStart; i < k; ++i) { + // I2OSP(i, 4): convert counter to an octet string of 4 octets + c.putInt32(i); + + // digest 'x' and the counter and add the result to the key + md.start(); + md.update(x + c.getBytes()); + var hash = md.digest(); + key.putBytes(hash.getBytes(digestLength)); + } + + // truncate to the correct key length + key.truncate(key.length() - length); + return key.getBytes(); + }; +} + +/** + * Cross-browser support for logging in a web application. + * + * @author David I. Lehn + * + * Copyright (c) 2008-2013 Digital Bazaar, Inc. + */ + +var forge$3 = forge$D; + + +/* LOG API */ +forge$3.log = forge$3.log || {}; + +/** + * Application logging system. + * + * Each logger level available as it's own function of the form: + * forge.log.level(category, args...) + * The category is an arbitrary string, and the args are the same as + * Firebug's console.log API. By default the call will be output as: + * 'LEVEL [category] , args[1], ...' + * This enables proper % formatting via the first argument. + * Each category is enabled by default but can be enabled or disabled with + * the setCategoryEnabled() function. + */ +// list of known levels +forge$3.log.levels = [ + 'none', 'error', 'warning', 'info', 'debug', 'verbose', 'max']; +// info on the levels indexed by name: +// index: level index +// name: uppercased display name +var sLevelInfo = {}; +// list of loggers +var sLoggers = []; +/** + * Standard console logger. If no console support is enabled this will + * remain null. Check before using. + */ +var sConsoleLogger = null; + +// logger flags +/** + * Lock the level at the current value. Used in cases where user config may + * set the level such that only critical messages are seen but more verbose + * messages are needed for debugging or other purposes. + */ +forge$3.log.LEVEL_LOCKED = (1 << 1); +/** + * Always call log function. By default, the logging system will check the + * message level against logger.level before calling the log function. This + * flag allows the function to do its own check. + */ +forge$3.log.NO_LEVEL_CHECK = (1 << 2); +/** + * Perform message interpolation with the passed arguments. "%" style + * fields in log messages will be replaced by arguments as needed. Some + * loggers, such as Firebug, may do this automatically. The original log + * message will be available as 'message' and the interpolated version will + * be available as 'fullMessage'. + */ +forge$3.log.INTERPOLATE = (1 << 3); + +// setup each log level +for(var i = 0; i < forge$3.log.levels.length; ++i) { + var level = forge$3.log.levels[i]; + sLevelInfo[level] = { + index: i, + name: level.toUpperCase() + }; +} + +/** + * Message logger. Will dispatch a message to registered loggers as needed. + * + * @param message message object + */ +forge$3.log.logMessage = function(message) { + var messageLevelIndex = sLevelInfo[message.level].index; + for(var i = 0; i < sLoggers.length; ++i) { + var logger = sLoggers[i]; + if(logger.flags & forge$3.log.NO_LEVEL_CHECK) { + logger.f(message); + } else { + // get logger level + var loggerLevelIndex = sLevelInfo[logger.level].index; + // check level + if(messageLevelIndex <= loggerLevelIndex) { + // message critical enough, call logger + logger.f(logger, message); + } + } + } +}; + +/** + * Sets the 'standard' key on a message object to: + * "LEVEL [category] " + message + * + * @param message a message log object + */ +forge$3.log.prepareStandard = function(message) { + if(!('standard' in message)) { + message.standard = + sLevelInfo[message.level].name + + //' ' + +message.timestamp + + ' [' + message.category + '] ' + + message.message; + } +}; + +/** + * Sets the 'full' key on a message object to the original message + * interpolated via % formatting with the message arguments. + * + * @param message a message log object. + */ +forge$3.log.prepareFull = function(message) { + if(!('full' in message)) { + // copy args and insert message at the front + var args = [message.message]; + args = args.concat([] || message['arguments']); + // format the message + message.full = forge$3.util.format.apply(this, args); + } +}; + +/** + * Applies both preparseStandard() and prepareFull() to a message object and + * store result in 'standardFull'. + * + * @param message a message log object. + */ +forge$3.log.prepareStandardFull = function(message) { + if(!('standardFull' in message)) { + // FIXME implement 'standardFull' logging + forge$3.log.prepareStandard(message); + message.standardFull = message.standard; + } +}; + +// create log level functions +{ + // levels for which we want functions + var levels = ['error', 'warning', 'info', 'debug', 'verbose']; + for(var i = 0; i < levels.length; ++i) { + // wrap in a function to ensure proper level var is passed + (function(level) { + // create function for this level + forge$3.log[level] = function(category, message/*, args...*/) { + // convert arguments to real array, remove category and message + var args = Array.prototype.slice.call(arguments).slice(2); + // create message object + // Note: interpolation and standard formatting is done lazily + var msg = { + timestamp: new Date(), + level: level, + category: category, + message: message, + 'arguments': args + /*standard*/ + /*full*/ + /*fullMessage*/ + }; + // process this message + forge$3.log.logMessage(msg); + }; + })(levels[i]); + } +} + +/** + * Creates a new logger with specified custom logging function. + * + * The logging function has a signature of: + * function(logger, message) + * logger: current logger + * message: object: + * level: level id + * category: category + * message: string message + * arguments: Array of extra arguments + * fullMessage: interpolated message and arguments if INTERPOLATE flag set + * + * @param logFunction a logging function which takes a log message object + * as a parameter. + * + * @return a logger object. + */ +forge$3.log.makeLogger = function(logFunction) { + var logger = { + flags: 0, + f: logFunction + }; + forge$3.log.setLevel(logger, 'none'); + return logger; +}; + +/** + * Sets the current log level on a logger. + * + * @param logger the target logger. + * @param level the new maximum log level as a string. + * + * @return true if set, false if not. + */ +forge$3.log.setLevel = function(logger, level) { + var rval = false; + if(logger && !(logger.flags & forge$3.log.LEVEL_LOCKED)) { + for(var i = 0; i < forge$3.log.levels.length; ++i) { + var aValidLevel = forge$3.log.levels[i]; + if(level == aValidLevel) { + // set level + logger.level = level; + rval = true; + break; + } + } + } + + return rval; +}; + +/** + * Locks the log level at its current value. + * + * @param logger the target logger. + * @param lock boolean lock value, default to true. + */ +forge$3.log.lock = function(logger, lock) { + if(typeof lock === 'undefined' || lock) { + logger.flags |= forge$3.log.LEVEL_LOCKED; + } else { + logger.flags &= ~forge$3.log.LEVEL_LOCKED; + } +}; + +/** + * Adds a logger. + * + * @param logger the logger object. + */ +forge$3.log.addLogger = function(logger) { + sLoggers.push(logger); +}; + +// setup the console logger if possible, else create fake console.log +if(typeof(console) !== 'undefined' && 'log' in console) { + var logger; + if(console.error && console.warn && console.info && console.debug) { + // looks like Firebug-style logging is available + // level handlers map + var levelHandlers = { + error: console.error, + warning: console.warn, + info: console.info, + debug: console.debug, + verbose: console.debug + }; + var f = function(logger, message) { + forge$3.log.prepareStandard(message); + var handler = levelHandlers[message.level]; + // prepend standard message and concat args + var args = [message.standard]; + args = args.concat(message['arguments'].slice()); + // apply to low-level console function + handler.apply(console, args); + }; + logger = forge$3.log.makeLogger(f); + } else { + // only appear to have basic console.log + var f = function(logger, message) { + forge$3.log.prepareStandardFull(message); + console.log(message.standardFull); + }; + logger = forge$3.log.makeLogger(f); + } + forge$3.log.setLevel(logger, 'debug'); + forge$3.log.addLogger(logger); + sConsoleLogger = logger; +} else { + // define fake console.log to avoid potential script errors on + // browsers that do not have console logging + console = { + log: function() {} + }; +} + +/* + * Check for logging control query vars in current URL. + * + * console.level= + * Set's the console log level by name. Useful to override defaults and + * allow more verbose logging before a user config is loaded. + * + * console.lock= + * Lock the console log level at whatever level it is set at. This is run + * after console.level is processed. Useful to force a level of verbosity + * that could otherwise be limited by a user config. + */ +if(sConsoleLogger !== null && + typeof window !== 'undefined' && window.location +) { + var query = new URL(window.location.href).searchParams; + if(query.has('console.level')) { + // set with last value + forge$3.log.setLevel( + sConsoleLogger, query.get('console.level').slice(-1)[0]); + } + if(query.has('console.lock')) { + // set with last value + var lock = query.get('console.lock').slice(-1)[0]; + if(lock == 'true') { + forge$3.log.lock(sConsoleLogger); + } + } +} + +// provide public access to console logger +forge$3.log.consoleLogger = sConsoleLogger; + +/** + * Javascript implementation of PKCS#7 v1.5. + * + * @author Stefan Siegl + * @author Dave Longley + * + * Copyright (c) 2012 Stefan Siegl + * Copyright (c) 2012-2015 Digital Bazaar, Inc. + * + * Currently this implementation only supports ContentType of EnvelopedData, + * EncryptedData, or SignedData at the root level. The top level elements may + * contain only a ContentInfo of ContentType Data, i.e. plain data. Further + * nesting is not (yet) supported. + * + * The Forge validators for PKCS #7's ASN.1 structures are available from + * a separate file pkcs7asn1.js, since those are referenced from other + * PKCS standards like PKCS #12. + */ + +var forge$2 = forge$D; + + + + + + + + + + +// shortcut for ASN.1 API +var asn1 = forge$2.asn1; + +// shortcut for PKCS#7 API +var p7 = forge$2.pkcs7 = forge$2.pkcs7 || {}; + +/** + * Converts a PKCS#7 message from PEM format. + * + * @param pem the PEM-formatted PKCS#7 message. + * + * @return the PKCS#7 message. + */ +p7.messageFromPem = function(pem) { + var msg = forge$2.pem.decode(pem)[0]; + + if(msg.type !== 'PKCS7') { + var error = new Error('Could not convert PKCS#7 message from PEM; PEM ' + + 'header type is not "PKCS#7".'); + error.headerType = msg.type; + throw error; + } + if(msg.procType && msg.procType.type === 'ENCRYPTED') { + throw new Error('Could not convert PKCS#7 message from PEM; PEM is encrypted.'); + } + + // convert DER to ASN.1 object + var obj = asn1.fromDer(msg.body); + + return p7.messageFromAsn1(obj); +}; + +/** + * Converts a PKCS#7 message to PEM format. + * + * @param msg The PKCS#7 message object + * @param maxline The maximum characters per line, defaults to 64. + * + * @return The PEM-formatted PKCS#7 message. + */ +p7.messageToPem = function(msg, maxline) { + // convert to ASN.1, then DER, then PEM-encode + var pemObj = { + type: 'PKCS7', + body: asn1.toDer(msg.toAsn1()).getBytes() + }; + return forge$2.pem.encode(pemObj, {maxline: maxline}); +}; + +/** + * Converts a PKCS#7 message from an ASN.1 object. + * + * @param obj the ASN.1 representation of a ContentInfo. + * + * @return the PKCS#7 message. + */ +p7.messageFromAsn1 = function(obj) { + // validate root level ContentInfo and capture data + var capture = {}; + var errors = []; + if(!asn1.validate(obj, p7.asn1.contentInfoValidator, capture, errors)) { + var error = new Error('Cannot read PKCS#7 message. ' + + 'ASN.1 object is not an PKCS#7 ContentInfo.'); + error.errors = errors; + throw error; + } + + var contentType = asn1.derToOid(capture.contentType); + var msg; + + switch(contentType) { + case forge$2.pki.oids.envelopedData: + msg = p7.createEnvelopedData(); + break; + + case forge$2.pki.oids.encryptedData: + msg = p7.createEncryptedData(); + break; + + case forge$2.pki.oids.signedData: + msg = p7.createSignedData(); + break; + + default: + throw new Error('Cannot read PKCS#7 message. ContentType with OID ' + + contentType + ' is not (yet) supported.'); + } + + msg.fromAsn1(capture.content.value[0]); + return msg; +}; + +p7.createSignedData = function() { + var msg = null; + msg = { + type: forge$2.pki.oids.signedData, + version: 1, + certificates: [], + crls: [], + // TODO: add json-formatted signer stuff here? + signers: [], + // populated during sign() + digestAlgorithmIdentifiers: [], + contentInfo: null, + signerInfos: [], + + fromAsn1: function(obj) { + // validate SignedData content block and capture data. + _fromAsn1(msg, obj, p7.asn1.signedDataValidator); + msg.certificates = []; + msg.crls = []; + msg.digestAlgorithmIdentifiers = []; + msg.contentInfo = null; + msg.signerInfos = []; + + if(msg.rawCapture.certificates) { + var certs = msg.rawCapture.certificates.value; + for(var i = 0; i < certs.length; ++i) { + msg.certificates.push(forge$2.pki.certificateFromAsn1(certs[i])); + } + } + + // TODO: parse crls + }, + + toAsn1: function() { + // degenerate case with no content + if(!msg.contentInfo) { + msg.sign(); + } + + var certs = []; + for(var i = 0; i < msg.certificates.length; ++i) { + certs.push(forge$2.pki.certificateToAsn1(msg.certificates[i])); + } + + var crls = []; + // TODO: implement CRLs + + // [0] SignedData + var signedData = asn1.create(asn1.Class.CONTEXT_SPECIFIC, 0, true, [ + asn1.create(asn1.Class.UNIVERSAL, asn1.Type.SEQUENCE, true, [ + // Version + asn1.create(asn1.Class.UNIVERSAL, asn1.Type.INTEGER, false, + asn1.integerToDer(msg.version).getBytes()), + // DigestAlgorithmIdentifiers + asn1.create( + asn1.Class.UNIVERSAL, asn1.Type.SET, true, + msg.digestAlgorithmIdentifiers), + // ContentInfo + msg.contentInfo + ]) + ]); + if(certs.length > 0) { + // [0] IMPLICIT ExtendedCertificatesAndCertificates OPTIONAL + signedData.value[0].value.push( + asn1.create(asn1.Class.CONTEXT_SPECIFIC, 0, true, certs)); + } + if(crls.length > 0) { + // [1] IMPLICIT CertificateRevocationLists OPTIONAL + signedData.value[0].value.push( + asn1.create(asn1.Class.CONTEXT_SPECIFIC, 1, true, crls)); + } + // SignerInfos + signedData.value[0].value.push( + asn1.create(asn1.Class.UNIVERSAL, asn1.Type.SET, true, + msg.signerInfos)); + + // ContentInfo + return asn1.create( + asn1.Class.UNIVERSAL, asn1.Type.SEQUENCE, true, [ + // ContentType + asn1.create(asn1.Class.UNIVERSAL, asn1.Type.OID, false, + asn1.oidToDer(msg.type).getBytes()), + // [0] SignedData + signedData + ]); + }, + + /** + * Add (another) entity to list of signers. + * + * Note: If authenticatedAttributes are provided, then, per RFC 2315, + * they must include at least two attributes: content type and + * message digest. The message digest attribute value will be + * auto-calculated during signing and will be ignored if provided. + * + * Here's an example of providing these two attributes: + * + * forge.pkcs7.createSignedData(); + * p7.addSigner({ + * issuer: cert.issuer.attributes, + * serialNumber: cert.serialNumber, + * key: privateKey, + * digestAlgorithm: forge.pki.oids.sha1, + * authenticatedAttributes: [{ + * type: forge.pki.oids.contentType, + * value: forge.pki.oids.data + * }, { + * type: forge.pki.oids.messageDigest + * }] + * }); + * + * TODO: Support [subjectKeyIdentifier] as signer's ID. + * + * @param signer the signer information: + * key the signer's private key. + * [certificate] a certificate containing the public key + * associated with the signer's private key; use this option as + * an alternative to specifying signer.issuer and + * signer.serialNumber. + * [issuer] the issuer attributes (eg: cert.issuer.attributes). + * [serialNumber] the signer's certificate's serial number in + * hexadecimal (eg: cert.serialNumber). + * [digestAlgorithm] the message digest OID, as a string, to use + * (eg: forge.pki.oids.sha1). + * [authenticatedAttributes] an optional array of attributes + * to also sign along with the content. + */ + addSigner: function(signer) { + var issuer = signer.issuer; + var serialNumber = signer.serialNumber; + if(signer.certificate) { + var cert = signer.certificate; + if(typeof cert === 'string') { + cert = forge$2.pki.certificateFromPem(cert); + } + issuer = cert.issuer.attributes; + serialNumber = cert.serialNumber; + } + var key = signer.key; + if(!key) { + throw new Error( + 'Could not add PKCS#7 signer; no private key specified.'); + } + if(typeof key === 'string') { + key = forge$2.pki.privateKeyFromPem(key); + } + + // ensure OID known for digest algorithm + var digestAlgorithm = signer.digestAlgorithm || forge$2.pki.oids.sha1; + switch(digestAlgorithm) { + case forge$2.pki.oids.sha1: + case forge$2.pki.oids.sha256: + case forge$2.pki.oids.sha384: + case forge$2.pki.oids.sha512: + case forge$2.pki.oids.md5: + break; + default: + throw new Error( + 'Could not add PKCS#7 signer; unknown message digest algorithm: ' + + digestAlgorithm); + } + + // if authenticatedAttributes is present, then the attributes + // must contain at least PKCS #9 content-type and message-digest + var authenticatedAttributes = signer.authenticatedAttributes || []; + if(authenticatedAttributes.length > 0) { + var contentType = false; + var messageDigest = false; + for(var i = 0; i < authenticatedAttributes.length; ++i) { + var attr = authenticatedAttributes[i]; + if(!contentType && attr.type === forge$2.pki.oids.contentType) { + contentType = true; + if(messageDigest) { + break; + } + continue; + } + if(!messageDigest && attr.type === forge$2.pki.oids.messageDigest) { + messageDigest = true; + if(contentType) { + break; + } + continue; + } + } + + if(!contentType || !messageDigest) { + throw new Error('Invalid signer.authenticatedAttributes. If ' + + 'signer.authenticatedAttributes is specified, then it must ' + + 'contain at least two attributes, PKCS #9 content-type and ' + + 'PKCS #9 message-digest.'); + } + } + + msg.signers.push({ + key: key, + version: 1, + issuer: issuer, + serialNumber: serialNumber, + digestAlgorithm: digestAlgorithm, + signatureAlgorithm: forge$2.pki.oids.rsaEncryption, + signature: null, + authenticatedAttributes: authenticatedAttributes, + unauthenticatedAttributes: [] + }); + }, + + /** + * Signs the content. + * @param options Options to apply when signing: + * [detached] boolean. If signing should be done in detached mode. Defaults to false. + */ + sign: function(options) { + options = options || {}; + // auto-generate content info + if(typeof msg.content !== 'object' || msg.contentInfo === null) { + // use Data ContentInfo + msg.contentInfo = asn1.create( + asn1.Class.UNIVERSAL, asn1.Type.SEQUENCE, true, [ + // ContentType + asn1.create(asn1.Class.UNIVERSAL, asn1.Type.OID, false, + asn1.oidToDer(forge$2.pki.oids.data).getBytes()) + ]); + + // add actual content, if present + if('content' in msg) { + var content; + if(msg.content instanceof forge$2.util.ByteBuffer) { + content = msg.content.bytes(); + } else if(typeof msg.content === 'string') { + content = forge$2.util.encodeUtf8(msg.content); + } + + if (options.detached) { + msg.detachedContent = asn1.create(asn1.Class.UNIVERSAL, asn1.Type.OCTETSTRING, false, content); + } else { + msg.contentInfo.value.push( + // [0] EXPLICIT content + asn1.create(asn1.Class.CONTEXT_SPECIFIC, 0, true, [ + asn1.create(asn1.Class.UNIVERSAL, asn1.Type.OCTETSTRING, false, + content) + ])); + } + } + } + + // no signers, return early (degenerate case for certificate container) + if(msg.signers.length === 0) { + return; + } + + // generate digest algorithm identifiers + var mds = addDigestAlgorithmIds(); + + // generate signerInfos + addSignerInfos(mds); + }, + + verify: function() { + throw new Error('PKCS#7 signature verification not yet implemented.'); + }, + + /** + * Add a certificate. + * + * @param cert the certificate to add. + */ + addCertificate: function(cert) { + // convert from PEM + if(typeof cert === 'string') { + cert = forge$2.pki.certificateFromPem(cert); + } + msg.certificates.push(cert); + }, + + /** + * Add a certificate revokation list. + * + * @param crl the certificate revokation list to add. + */ + addCertificateRevokationList: function(crl) { + throw new Error('PKCS#7 CRL support not yet implemented.'); + } + }; + return msg; + + function addDigestAlgorithmIds() { + var mds = {}; + + for(var i = 0; i < msg.signers.length; ++i) { + var signer = msg.signers[i]; + var oid = signer.digestAlgorithm; + if(!(oid in mds)) { + // content digest + mds[oid] = forge$2.md[forge$2.pki.oids[oid]].create(); + } + if(signer.authenticatedAttributes.length === 0) { + // no custom attributes to digest; use content message digest + signer.md = mds[oid]; + } else { + // custom attributes to be digested; use own message digest + // TODO: optimize to just copy message digest state if that + // feature is ever supported with message digests + signer.md = forge$2.md[forge$2.pki.oids[oid]].create(); + } + } + + // add unique digest algorithm identifiers + msg.digestAlgorithmIdentifiers = []; + for(var oid in mds) { + msg.digestAlgorithmIdentifiers.push( + // AlgorithmIdentifier + asn1.create(asn1.Class.UNIVERSAL, asn1.Type.SEQUENCE, true, [ + // algorithm + asn1.create(asn1.Class.UNIVERSAL, asn1.Type.OID, false, + asn1.oidToDer(oid).getBytes()), + // parameters (null) + asn1.create(asn1.Class.UNIVERSAL, asn1.Type.NULL, false, '') + ])); + } + + return mds; + } + + function addSignerInfos(mds) { + var content; + + if (msg.detachedContent) { + // Signature has been made in detached mode. + content = msg.detachedContent; + } else { + // Note: ContentInfo is a SEQUENCE with 2 values, second value is + // the content field and is optional for a ContentInfo but required here + // since signers are present + // get ContentInfo content + content = msg.contentInfo.value[1]; + // skip [0] EXPLICIT content wrapper + content = content.value[0]; + } + + if(!content) { + throw new Error( + 'Could not sign PKCS#7 message; there is no content to sign.'); + } + + // get ContentInfo content type + var contentType = asn1.derToOid(msg.contentInfo.value[0].value); + + // serialize content + var bytes = asn1.toDer(content); + + // skip identifier and length per RFC 2315 9.3 + // skip identifier (1 byte) + bytes.getByte(); + // read and discard length bytes + asn1.getBerValueLength(bytes); + bytes = bytes.getBytes(); + + // digest content DER value bytes + for(var oid in mds) { + mds[oid].start().update(bytes); + } + + // sign content + var signingTime = new Date(); + for(var i = 0; i < msg.signers.length; ++i) { + var signer = msg.signers[i]; + + if(signer.authenticatedAttributes.length === 0) { + // if ContentInfo content type is not "Data", then + // authenticatedAttributes must be present per RFC 2315 + if(contentType !== forge$2.pki.oids.data) { + throw new Error( + 'Invalid signer; authenticatedAttributes must be present ' + + 'when the ContentInfo content type is not PKCS#7 Data.'); + } + } else { + // process authenticated attributes + // [0] IMPLICIT + signer.authenticatedAttributesAsn1 = asn1.create( + asn1.Class.CONTEXT_SPECIFIC, 0, true, []); + + // per RFC 2315, attributes are to be digested using a SET container + // not the above [0] IMPLICIT container + var attrsAsn1 = asn1.create( + asn1.Class.UNIVERSAL, asn1.Type.SET, true, []); + + for(var ai = 0; ai < signer.authenticatedAttributes.length; ++ai) { + var attr = signer.authenticatedAttributes[ai]; + if(attr.type === forge$2.pki.oids.messageDigest) { + // use content message digest as value + attr.value = mds[signer.digestAlgorithm].digest(); + } else if(attr.type === forge$2.pki.oids.signingTime) { + // auto-populate signing time if not already set + if(!attr.value) { + attr.value = signingTime; + } + } + + // convert to ASN.1 and push onto Attributes SET (for signing) and + // onto authenticatedAttributesAsn1 to complete SignedData ASN.1 + // TODO: optimize away duplication + attrsAsn1.value.push(_attributeToAsn1(attr)); + signer.authenticatedAttributesAsn1.value.push(_attributeToAsn1(attr)); + } + + // DER-serialize and digest SET OF attributes only + bytes = asn1.toDer(attrsAsn1).getBytes(); + signer.md.start().update(bytes); + } + + // sign digest + signer.signature = signer.key.sign(signer.md, 'RSASSA-PKCS1-V1_5'); + } + + // add signer info + msg.signerInfos = _signersToAsn1(msg.signers); + } +}; + +/** + * Creates an empty PKCS#7 message of type EncryptedData. + * + * @return the message. + */ +p7.createEncryptedData = function() { + var msg = null; + msg = { + type: forge$2.pki.oids.encryptedData, + version: 0, + encryptedContent: { + algorithm: forge$2.pki.oids['aes256-CBC'] + }, + + /** + * Reads an EncryptedData content block (in ASN.1 format) + * + * @param obj The ASN.1 representation of the EncryptedData content block + */ + fromAsn1: function(obj) { + // Validate EncryptedData content block and capture data. + _fromAsn1(msg, obj, p7.asn1.encryptedDataValidator); + }, + + /** + * Decrypt encrypted content + * + * @param key The (symmetric) key as a byte buffer + */ + decrypt: function(key) { + if(key !== undefined) { + msg.encryptedContent.key = key; + } + _decryptContent(msg); + } + }; + return msg; +}; + +/** + * Creates an empty PKCS#7 message of type EnvelopedData. + * + * @return the message. + */ +p7.createEnvelopedData = function() { + var msg = null; + msg = { + type: forge$2.pki.oids.envelopedData, + version: 0, + recipients: [], + encryptedContent: { + algorithm: forge$2.pki.oids['aes256-CBC'] + }, + + /** + * Reads an EnvelopedData content block (in ASN.1 format) + * + * @param obj the ASN.1 representation of the EnvelopedData content block. + */ + fromAsn1: function(obj) { + // validate EnvelopedData content block and capture data + var capture = _fromAsn1(msg, obj, p7.asn1.envelopedDataValidator); + msg.recipients = _recipientsFromAsn1(capture.recipientInfos.value); + }, + + toAsn1: function() { + // ContentInfo + return asn1.create(asn1.Class.UNIVERSAL, asn1.Type.SEQUENCE, true, [ + // ContentType + asn1.create(asn1.Class.UNIVERSAL, asn1.Type.OID, false, + asn1.oidToDer(msg.type).getBytes()), + // [0] EnvelopedData + asn1.create(asn1.Class.CONTEXT_SPECIFIC, 0, true, [ + asn1.create(asn1.Class.UNIVERSAL, asn1.Type.SEQUENCE, true, [ + // Version + asn1.create(asn1.Class.UNIVERSAL, asn1.Type.INTEGER, false, + asn1.integerToDer(msg.version).getBytes()), + // RecipientInfos + asn1.create(asn1.Class.UNIVERSAL, asn1.Type.SET, true, + _recipientsToAsn1(msg.recipients)), + // EncryptedContentInfo + asn1.create(asn1.Class.UNIVERSAL, asn1.Type.SEQUENCE, true, + _encryptedContentToAsn1(msg.encryptedContent)) + ]) + ]) + ]); + }, + + /** + * Find recipient by X.509 certificate's issuer. + * + * @param cert the certificate with the issuer to look for. + * + * @return the recipient object. + */ + findRecipient: function(cert) { + var sAttr = cert.issuer.attributes; + + for(var i = 0; i < msg.recipients.length; ++i) { + var r = msg.recipients[i]; + var rAttr = r.issuer; + + if(r.serialNumber !== cert.serialNumber) { + continue; + } + + if(rAttr.length !== sAttr.length) { + continue; + } + + var match = true; + for(var j = 0; j < sAttr.length; ++j) { + if(rAttr[j].type !== sAttr[j].type || + rAttr[j].value !== sAttr[j].value) { + match = false; + break; + } + } + + if(match) { + return r; + } + } + + return null; + }, + + /** + * Decrypt enveloped content + * + * @param recipient The recipient object related to the private key + * @param privKey The (RSA) private key object + */ + decrypt: function(recipient, privKey) { + if(msg.encryptedContent.key === undefined && recipient !== undefined && + privKey !== undefined) { + switch(recipient.encryptedContent.algorithm) { + case forge$2.pki.oids.rsaEncryption: + case forge$2.pki.oids.desCBC: + var key = privKey.decrypt(recipient.encryptedContent.content); + msg.encryptedContent.key = forge$2.util.createBuffer(key); + break; + + default: + throw new Error('Unsupported asymmetric cipher, ' + + 'OID ' + recipient.encryptedContent.algorithm); + } + } + + _decryptContent(msg); + }, + + /** + * Add (another) entity to list of recipients. + * + * @param cert The certificate of the entity to add. + */ + addRecipient: function(cert) { + msg.recipients.push({ + version: 0, + issuer: cert.issuer.attributes, + serialNumber: cert.serialNumber, + encryptedContent: { + // We simply assume rsaEncryption here, since forge.pki only + // supports RSA so far. If the PKI module supports other + // ciphers one day, we need to modify this one as well. + algorithm: forge$2.pki.oids.rsaEncryption, + key: cert.publicKey + } + }); + }, + + /** + * Encrypt enveloped content. + * + * This function supports two optional arguments, cipher and key, which + * can be used to influence symmetric encryption. Unless cipher is + * provided, the cipher specified in encryptedContent.algorithm is used + * (defaults to AES-256-CBC). If no key is provided, encryptedContent.key + * is (re-)used. If that one's not set, a random key will be generated + * automatically. + * + * @param [key] The key to be used for symmetric encryption. + * @param [cipher] The OID of the symmetric cipher to use. + */ + encrypt: function(key, cipher) { + // Part 1: Symmetric encryption + if(msg.encryptedContent.content === undefined) { + cipher = cipher || msg.encryptedContent.algorithm; + key = key || msg.encryptedContent.key; + + var keyLen, ivLen, ciphFn; + switch(cipher) { + case forge$2.pki.oids['aes128-CBC']: + keyLen = 16; + ivLen = 16; + ciphFn = forge$2.aes.createEncryptionCipher; + break; + + case forge$2.pki.oids['aes192-CBC']: + keyLen = 24; + ivLen = 16; + ciphFn = forge$2.aes.createEncryptionCipher; + break; + + case forge$2.pki.oids['aes256-CBC']: + keyLen = 32; + ivLen = 16; + ciphFn = forge$2.aes.createEncryptionCipher; + break; + + case forge$2.pki.oids['des-EDE3-CBC']: + keyLen = 24; + ivLen = 8; + ciphFn = forge$2.des.createEncryptionCipher; + break; + + default: + throw new Error('Unsupported symmetric cipher, OID ' + cipher); + } + + if(key === undefined) { + key = forge$2.util.createBuffer(forge$2.random.getBytes(keyLen)); + } else if(key.length() != keyLen) { + throw new Error('Symmetric key has wrong length; ' + + 'got ' + key.length() + ' bytes, expected ' + keyLen + '.'); + } + + // Keep a copy of the key & IV in the object, so the caller can + // use it for whatever reason. + msg.encryptedContent.algorithm = cipher; + msg.encryptedContent.key = key; + msg.encryptedContent.parameter = forge$2.util.createBuffer( + forge$2.random.getBytes(ivLen)); + + var ciph = ciphFn(key); + ciph.start(msg.encryptedContent.parameter.copy()); + ciph.update(msg.content); + + // The finish function does PKCS#7 padding by default, therefore + // no action required by us. + if(!ciph.finish()) { + throw new Error('Symmetric encryption failed.'); + } + + msg.encryptedContent.content = ciph.output; + } + + // Part 2: asymmetric encryption for each recipient + for(var i = 0; i < msg.recipients.length; ++i) { + var recipient = msg.recipients[i]; + + // Nothing to do, encryption already done. + if(recipient.encryptedContent.content !== undefined) { + continue; + } + + switch(recipient.encryptedContent.algorithm) { + case forge$2.pki.oids.rsaEncryption: + recipient.encryptedContent.content = + recipient.encryptedContent.key.encrypt( + msg.encryptedContent.key.data); + break; + + default: + throw new Error('Unsupported asymmetric cipher, OID ' + + recipient.encryptedContent.algorithm); + } + } + } + }; + return msg; +}; + +/** + * Converts a single recipient from an ASN.1 object. + * + * @param obj the ASN.1 RecipientInfo. + * + * @return the recipient object. + */ +function _recipientFromAsn1(obj) { + // validate EnvelopedData content block and capture data + var capture = {}; + var errors = []; + if(!asn1.validate(obj, p7.asn1.recipientInfoValidator, capture, errors)) { + var error = new Error('Cannot read PKCS#7 RecipientInfo. ' + + 'ASN.1 object is not an PKCS#7 RecipientInfo.'); + error.errors = errors; + throw error; + } + + return { + version: capture.version.charCodeAt(0), + issuer: forge$2.pki.RDNAttributesAsArray(capture.issuer), + serialNumber: forge$2.util.createBuffer(capture.serial).toHex(), + encryptedContent: { + algorithm: asn1.derToOid(capture.encAlgorithm), + parameter: capture.encParameter ? capture.encParameter.value : undefined, + content: capture.encKey + } + }; +} + +/** + * Converts a single recipient object to an ASN.1 object. + * + * @param obj the recipient object. + * + * @return the ASN.1 RecipientInfo. + */ +function _recipientToAsn1(obj) { + return asn1.create(asn1.Class.UNIVERSAL, asn1.Type.SEQUENCE, true, [ + // Version + asn1.create(asn1.Class.UNIVERSAL, asn1.Type.INTEGER, false, + asn1.integerToDer(obj.version).getBytes()), + // IssuerAndSerialNumber + asn1.create(asn1.Class.UNIVERSAL, asn1.Type.SEQUENCE, true, [ + // Name + forge$2.pki.distinguishedNameToAsn1({attributes: obj.issuer}), + // Serial + asn1.create(asn1.Class.UNIVERSAL, asn1.Type.INTEGER, false, + forge$2.util.hexToBytes(obj.serialNumber)) + ]), + // KeyEncryptionAlgorithmIdentifier + asn1.create(asn1.Class.UNIVERSAL, asn1.Type.SEQUENCE, true, [ + // Algorithm + asn1.create(asn1.Class.UNIVERSAL, asn1.Type.OID, false, + asn1.oidToDer(obj.encryptedContent.algorithm).getBytes()), + // Parameter, force NULL, only RSA supported for now. + asn1.create(asn1.Class.UNIVERSAL, asn1.Type.NULL, false, '') + ]), + // EncryptedKey + asn1.create(asn1.Class.UNIVERSAL, asn1.Type.OCTETSTRING, false, + obj.encryptedContent.content) + ]); +} + +/** + * Map a set of RecipientInfo ASN.1 objects to recipient objects. + * + * @param infos an array of ASN.1 representations RecipientInfo (i.e. SET OF). + * + * @return an array of recipient objects. + */ +function _recipientsFromAsn1(infos) { + var ret = []; + for(var i = 0; i < infos.length; ++i) { + ret.push(_recipientFromAsn1(infos[i])); + } + return ret; +} + +/** + * Map an array of recipient objects to ASN.1 RecipientInfo objects. + * + * @param recipients an array of recipientInfo objects. + * + * @return an array of ASN.1 RecipientInfos. + */ +function _recipientsToAsn1(recipients) { + var ret = []; + for(var i = 0; i < recipients.length; ++i) { + ret.push(_recipientToAsn1(recipients[i])); + } + return ret; +} + +/** + * Converts a single signerInfo object to an ASN.1 object. + * + * @param obj the signerInfo object. + * + * @return the ASN.1 representation of a SignerInfo. + */ +function _signerToAsn1(obj) { + // SignerInfo + var rval = asn1.create(asn1.Class.UNIVERSAL, asn1.Type.SEQUENCE, true, [ + // version + asn1.create(asn1.Class.UNIVERSAL, asn1.Type.INTEGER, false, + asn1.integerToDer(obj.version).getBytes()), + // issuerAndSerialNumber + asn1.create(asn1.Class.UNIVERSAL, asn1.Type.SEQUENCE, true, [ + // name + forge$2.pki.distinguishedNameToAsn1({attributes: obj.issuer}), + // serial + asn1.create(asn1.Class.UNIVERSAL, asn1.Type.INTEGER, false, + forge$2.util.hexToBytes(obj.serialNumber)) + ]), + // digestAlgorithm + asn1.create(asn1.Class.UNIVERSAL, asn1.Type.SEQUENCE, true, [ + // algorithm + asn1.create(asn1.Class.UNIVERSAL, asn1.Type.OID, false, + asn1.oidToDer(obj.digestAlgorithm).getBytes()), + // parameters (null) + asn1.create(asn1.Class.UNIVERSAL, asn1.Type.NULL, false, '') + ]) + ]); + + // authenticatedAttributes (OPTIONAL) + if(obj.authenticatedAttributesAsn1) { + // add ASN.1 previously generated during signing + rval.value.push(obj.authenticatedAttributesAsn1); + } + + // digestEncryptionAlgorithm + rval.value.push(asn1.create(asn1.Class.UNIVERSAL, asn1.Type.SEQUENCE, true, [ + // algorithm + asn1.create(asn1.Class.UNIVERSAL, asn1.Type.OID, false, + asn1.oidToDer(obj.signatureAlgorithm).getBytes()), + // parameters (null) + asn1.create(asn1.Class.UNIVERSAL, asn1.Type.NULL, false, '') + ])); + + // encryptedDigest + rval.value.push(asn1.create( + asn1.Class.UNIVERSAL, asn1.Type.OCTETSTRING, false, obj.signature)); + + // unauthenticatedAttributes (OPTIONAL) + if(obj.unauthenticatedAttributes.length > 0) { + // [1] IMPLICIT + var attrsAsn1 = asn1.create(asn1.Class.CONTEXT_SPECIFIC, 1, true, []); + for(var i = 0; i < obj.unauthenticatedAttributes.length; ++i) { + var attr = obj.unauthenticatedAttributes[i]; + attrsAsn1.values.push(_attributeToAsn1(attr)); + } + rval.value.push(attrsAsn1); + } + + return rval; +} + +/** + * Map an array of signer objects to ASN.1 objects. + * + * @param signers an array of signer objects. + * + * @return an array of ASN.1 SignerInfos. + */ +function _signersToAsn1(signers) { + var ret = []; + for(var i = 0; i < signers.length; ++i) { + ret.push(_signerToAsn1(signers[i])); + } + return ret; +} + +/** + * Convert an attribute object to an ASN.1 Attribute. + * + * @param attr the attribute object. + * + * @return the ASN.1 Attribute. + */ +function _attributeToAsn1(attr) { + var value; + + // TODO: generalize to support more attributes + if(attr.type === forge$2.pki.oids.contentType) { + value = asn1.create(asn1.Class.UNIVERSAL, asn1.Type.OID, false, + asn1.oidToDer(attr.value).getBytes()); + } else if(attr.type === forge$2.pki.oids.messageDigest) { + value = asn1.create(asn1.Class.UNIVERSAL, asn1.Type.OCTETSTRING, false, + attr.value.bytes()); + } else if(attr.type === forge$2.pki.oids.signingTime) { + /* Note per RFC 2985: Dates between 1 January 1950 and 31 December 2049 + (inclusive) MUST be encoded as UTCTime. Any dates with year values + before 1950 or after 2049 MUST be encoded as GeneralizedTime. [Further,] + UTCTime values MUST be expressed in Greenwich Mean Time (Zulu) and MUST + include seconds (i.e., times are YYMMDDHHMMSSZ), even where the + number of seconds is zero. Midnight (GMT) must be represented as + "YYMMDD000000Z". */ + // TODO: make these module-level constants + var jan_1_1950 = new Date('1950-01-01T00:00:00Z'); + var jan_1_2050 = new Date('2050-01-01T00:00:00Z'); + var date = attr.value; + if(typeof date === 'string') { + // try to parse date + var timestamp = Date.parse(date); + if(!isNaN(timestamp)) { + date = new Date(timestamp); + } else if(date.length === 13) { + // YYMMDDHHMMSSZ (13 chars for UTCTime) + date = asn1.utcTimeToDate(date); + } else { + // assume generalized time + date = asn1.generalizedTimeToDate(date); + } + } + + if(date >= jan_1_1950 && date < jan_1_2050) { + value = asn1.create( + asn1.Class.UNIVERSAL, asn1.Type.UTCTIME, false, + asn1.dateToUtcTime(date)); + } else { + value = asn1.create( + asn1.Class.UNIVERSAL, asn1.Type.GENERALIZEDTIME, false, + asn1.dateToGeneralizedTime(date)); + } + } + + // TODO: expose as common API call + // create a RelativeDistinguishedName set + // each value in the set is an AttributeTypeAndValue first + // containing the type (an OID) and second the value + return asn1.create(asn1.Class.UNIVERSAL, asn1.Type.SEQUENCE, true, [ + // AttributeType + asn1.create(asn1.Class.UNIVERSAL, asn1.Type.OID, false, + asn1.oidToDer(attr.type).getBytes()), + asn1.create(asn1.Class.UNIVERSAL, asn1.Type.SET, true, [ + // AttributeValue + value + ]) + ]); +} + +/** + * Map messages encrypted content to ASN.1 objects. + * + * @param ec The encryptedContent object of the message. + * + * @return ASN.1 representation of the encryptedContent object (SEQUENCE). + */ +function _encryptedContentToAsn1(ec) { + return [ + // ContentType, always Data for the moment + asn1.create(asn1.Class.UNIVERSAL, asn1.Type.OID, false, + asn1.oidToDer(forge$2.pki.oids.data).getBytes()), + // ContentEncryptionAlgorithmIdentifier + asn1.create(asn1.Class.UNIVERSAL, asn1.Type.SEQUENCE, true, [ + // Algorithm + asn1.create(asn1.Class.UNIVERSAL, asn1.Type.OID, false, + asn1.oidToDer(ec.algorithm).getBytes()), + // Parameters (IV) + !ec.parameter ? + undefined : + asn1.create( + asn1.Class.UNIVERSAL, asn1.Type.OCTETSTRING, false, + ec.parameter.getBytes()) + ]), + // [0] EncryptedContent + asn1.create(asn1.Class.CONTEXT_SPECIFIC, 0, true, [ + asn1.create(asn1.Class.UNIVERSAL, asn1.Type.OCTETSTRING, false, + ec.content.getBytes()) + ]) + ]; +} + +/** + * Reads the "common part" of an PKCS#7 content block (in ASN.1 format) + * + * This function reads the "common part" of the PKCS#7 content blocks + * EncryptedData and EnvelopedData, i.e. version number and symmetrically + * encrypted content block. + * + * The result of the ASN.1 validate and capture process is returned + * to allow the caller to extract further data, e.g. the list of recipients + * in case of a EnvelopedData object. + * + * @param msg the PKCS#7 object to read the data to. + * @param obj the ASN.1 representation of the content block. + * @param validator the ASN.1 structure validator object to use. + * + * @return the value map captured by validator object. + */ +function _fromAsn1(msg, obj, validator) { + var capture = {}; + var errors = []; + if(!asn1.validate(obj, validator, capture, errors)) { + var error = new Error('Cannot read PKCS#7 message. ' + + 'ASN.1 object is not a supported PKCS#7 message.'); + error.errors = error; + throw error; + } + + // Check contentType, so far we only support (raw) Data. + var contentType = asn1.derToOid(capture.contentType); + if(contentType !== forge$2.pki.oids.data) { + throw new Error('Unsupported PKCS#7 message. ' + + 'Only wrapped ContentType Data supported.'); + } + + if(capture.encryptedContent) { + var content = ''; + if(forge$2.util.isArray(capture.encryptedContent)) { + for(var i = 0; i < capture.encryptedContent.length; ++i) { + if(capture.encryptedContent[i].type !== asn1.Type.OCTETSTRING) { + throw new Error('Malformed PKCS#7 message, expecting encrypted ' + + 'content constructed of only OCTET STRING objects.'); + } + content += capture.encryptedContent[i].value; + } + } else { + content = capture.encryptedContent; + } + msg.encryptedContent = { + algorithm: asn1.derToOid(capture.encAlgorithm), + parameter: forge$2.util.createBuffer(capture.encParameter.value), + content: forge$2.util.createBuffer(content) + }; + } + + if(capture.content) { + var content = ''; + if(forge$2.util.isArray(capture.content)) { + for(var i = 0; i < capture.content.length; ++i) { + if(capture.content[i].type !== asn1.Type.OCTETSTRING) { + throw new Error('Malformed PKCS#7 message, expecting ' + + 'content constructed of only OCTET STRING objects.'); + } + content += capture.content[i].value; + } + } else { + content = capture.content; + } + msg.content = forge$2.util.createBuffer(content); + } + + msg.version = capture.version.charCodeAt(0); + msg.rawCapture = capture; + + return capture; +} + +/** + * Decrypt the symmetrically encrypted content block of the PKCS#7 message. + * + * Decryption is skipped in case the PKCS#7 message object already has a + * (decrypted) content attribute. The algorithm, key and cipher parameters + * (probably the iv) are taken from the encryptedContent attribute of the + * message object. + * + * @param The PKCS#7 message object. + */ +function _decryptContent(msg) { + if(msg.encryptedContent.key === undefined) { + throw new Error('Symmetric key not available.'); + } + + if(msg.content === undefined) { + var ciph; + + switch(msg.encryptedContent.algorithm) { + case forge$2.pki.oids['aes128-CBC']: + case forge$2.pki.oids['aes192-CBC']: + case forge$2.pki.oids['aes256-CBC']: + ciph = forge$2.aes.createDecryptionCipher(msg.encryptedContent.key); + break; + + case forge$2.pki.oids['desCBC']: + case forge$2.pki.oids['des-EDE3-CBC']: + ciph = forge$2.des.createDecryptionCipher(msg.encryptedContent.key); + break; + + default: + throw new Error('Unsupported symmetric cipher, OID ' + + msg.encryptedContent.algorithm); + } + ciph.start(msg.encryptedContent.parameter); + ciph.update(msg.encryptedContent.content); + + if(!ciph.finish()) { + throw new Error('Symmetric decryption failed.'); + } + + msg.content = ciph.output; + } +} + +/** + * Functions to output keys in SSH-friendly formats. + * + * This is part of the Forge project which may be used under the terms of + * either the BSD License or the GNU General Public License (GPL) Version 2. + * + * See: https://github.com/digitalbazaar/forge/blob/cbebca3780658703d925b61b2caffb1d263a6c1d/LICENSE + * + * @author https://github.com/shellac + */ + +var forge$1 = forge$D; + + + + + + +var ssh = forge$1.ssh = forge$1.ssh || {}; + +/** + * Encodes (and optionally encrypts) a private RSA key as a Putty PPK file. + * + * @param privateKey the key. + * @param passphrase a passphrase to protect the key (falsy for no encryption). + * @param comment a comment to include in the key file. + * + * @return the PPK file as a string. + */ +ssh.privateKeyToPutty = function(privateKey, passphrase, comment) { + comment = comment || ''; + passphrase = passphrase || ''; + var algorithm = 'ssh-rsa'; + var encryptionAlgorithm = (passphrase === '') ? 'none' : 'aes256-cbc'; + + var ppk = 'PuTTY-User-Key-File-2: ' + algorithm + '\r\n'; + ppk += 'Encryption: ' + encryptionAlgorithm + '\r\n'; + ppk += 'Comment: ' + comment + '\r\n'; + + // public key into buffer for ppk + var pubbuffer = forge$1.util.createBuffer(); + _addStringToBuffer(pubbuffer, algorithm); + _addBigIntegerToBuffer(pubbuffer, privateKey.e); + _addBigIntegerToBuffer(pubbuffer, privateKey.n); + + // write public key + var pub = forge$1.util.encode64(pubbuffer.bytes(), 64); + var length = Math.floor(pub.length / 66) + 1; // 66 = 64 + \r\n + ppk += 'Public-Lines: ' + length + '\r\n'; + ppk += pub; + + // private key into a buffer + var privbuffer = forge$1.util.createBuffer(); + _addBigIntegerToBuffer(privbuffer, privateKey.d); + _addBigIntegerToBuffer(privbuffer, privateKey.p); + _addBigIntegerToBuffer(privbuffer, privateKey.q); + _addBigIntegerToBuffer(privbuffer, privateKey.qInv); + + // optionally encrypt the private key + var priv; + if(!passphrase) { + // use the unencrypted buffer + priv = forge$1.util.encode64(privbuffer.bytes(), 64); + } else { + // encrypt RSA key using passphrase + var encLen = privbuffer.length() + 16 - 1; + encLen -= encLen % 16; + + // pad private key with sha1-d data -- needs to be a multiple of 16 + var padding = _sha1(privbuffer.bytes()); + + padding.truncate(padding.length() - encLen + privbuffer.length()); + privbuffer.putBuffer(padding); + + var aeskey = forge$1.util.createBuffer(); + aeskey.putBuffer(_sha1('\x00\x00\x00\x00', passphrase)); + aeskey.putBuffer(_sha1('\x00\x00\x00\x01', passphrase)); + + // encrypt some bytes using CBC mode + // key is 40 bytes, so truncate *by* 8 bytes + var cipher = forge$1.aes.createEncryptionCipher(aeskey.truncate(8), 'CBC'); + cipher.start(forge$1.util.createBuffer().fillWithByte(0, 16)); + cipher.update(privbuffer.copy()); + cipher.finish(); + var encrypted = cipher.output; + + // Note: this appears to differ from Putty -- is forge wrong, or putty? + // due to padding we finish as an exact multiple of 16 + encrypted.truncate(16); // all padding + + priv = forge$1.util.encode64(encrypted.bytes(), 64); + } + + // output private key + length = Math.floor(priv.length / 66) + 1; // 64 + \r\n + ppk += '\r\nPrivate-Lines: ' + length + '\r\n'; + ppk += priv; + + // MAC + var mackey = _sha1('putty-private-key-file-mac-key', passphrase); + + var macbuffer = forge$1.util.createBuffer(); + _addStringToBuffer(macbuffer, algorithm); + _addStringToBuffer(macbuffer, encryptionAlgorithm); + _addStringToBuffer(macbuffer, comment); + macbuffer.putInt32(pubbuffer.length()); + macbuffer.putBuffer(pubbuffer); + macbuffer.putInt32(privbuffer.length()); + macbuffer.putBuffer(privbuffer); + + var hmac = forge$1.hmac.create(); + hmac.start('sha1', mackey); + hmac.update(macbuffer.bytes()); + + ppk += '\r\nPrivate-MAC: ' + hmac.digest().toHex() + '\r\n'; + + return ppk; +}; + +/** + * Encodes a public RSA key as an OpenSSH file. + * + * @param key the key. + * @param comment a comment. + * + * @return the public key in OpenSSH format. + */ +ssh.publicKeyToOpenSSH = function(key, comment) { + var type = 'ssh-rsa'; + comment = comment || ''; + + var buffer = forge$1.util.createBuffer(); + _addStringToBuffer(buffer, type); + _addBigIntegerToBuffer(buffer, key.e); + _addBigIntegerToBuffer(buffer, key.n); + + return type + ' ' + forge$1.util.encode64(buffer.bytes()) + ' ' + comment; +}; + +/** + * Encodes a private RSA key as an OpenSSH file. + * + * @param key the key. + * @param passphrase a passphrase to protect the key (falsy for no encryption). + * + * @return the public key in OpenSSH format. + */ +ssh.privateKeyToOpenSSH = function(privateKey, passphrase) { + if(!passphrase) { + return forge$1.pki.privateKeyToPem(privateKey); + } + // OpenSSH private key is just a legacy format, it seems + return forge$1.pki.encryptRsaPrivateKey(privateKey, passphrase, + {legacy: true, algorithm: 'aes128'}); +}; + +/** + * Gets the SSH fingerprint for the given public key. + * + * @param options the options to use. + * [md] the message digest object to use (defaults to forge.md.md5). + * [encoding] an alternative output encoding, such as 'hex' + * (defaults to none, outputs a byte buffer). + * [delimiter] the delimiter to use between bytes for 'hex' encoded + * output, eg: ':' (defaults to none). + * + * @return the fingerprint as a byte buffer or other encoding based on options. + */ +ssh.getPublicKeyFingerprint = function(key, options) { + options = options || {}; + var md = options.md || forge$1.md.md5.create(); + + var type = 'ssh-rsa'; + var buffer = forge$1.util.createBuffer(); + _addStringToBuffer(buffer, type); + _addBigIntegerToBuffer(buffer, key.e); + _addBigIntegerToBuffer(buffer, key.n); + + // hash public key bytes + md.start(); + md.update(buffer.getBytes()); + var digest = md.digest(); + if(options.encoding === 'hex') { + var hex = digest.toHex(); + if(options.delimiter) { + return hex.match(/.{2}/g).join(options.delimiter); + } + return hex; + } else if(options.encoding === 'binary') { + return digest.getBytes(); + } else if(options.encoding) { + throw new Error('Unknown encoding "' + options.encoding + '".'); + } + return digest; +}; + +/** + * Adds len(val) then val to a buffer. + * + * @param buffer the buffer to add to. + * @param val a big integer. + */ +function _addBigIntegerToBuffer(buffer, val) { + var hexVal = val.toString(16); + // ensure 2s complement +ve + if(hexVal[0] >= '8') { + hexVal = '00' + hexVal; + } + var bytes = forge$1.util.hexToBytes(hexVal); + buffer.putInt32(bytes.length); + buffer.putBytes(bytes); +} + +/** + * Adds len(val) then val to a buffer. + * + * @param buffer the buffer to add to. + * @param val a string. + */ +function _addStringToBuffer(buffer, val) { + buffer.putInt32(val.length); + buffer.putString(val); +} + +/** + * Hashes the arguments into one value using SHA-1. + * + * @return the sha1 hash of the provided arguments. + */ +function _sha1() { + var sha = forge$1.md.sha1.create(); + var num = arguments.length; + for (var i = 0; i < num; ++i) { + sha.update(arguments[i]); + } + return sha.digest(); +} + +/** + * Node.js module for Forge. + * + * @author Dave Longley + * + * Copyright 2011-2016 Digital Bazaar, Inc. + */ + +var lib = forge$D; + +const forge = /*@__PURE__*/getDefaultExportFromCjs(lib); + +let isDockerCached; +function isDocker() { + if (isDockerCached === void 0) { + isDockerCached = _hasDockerEnvironment() || _hasDockerCGroup(); + } + return isDockerCached; +} +function _hasDockerEnvironment() { + try { + statSync("/.dockerenv"); + return true; + } catch { + return false; + } +} +function _hasDockerCGroup() { + try { + return readFileSync("/proc/self/cgroup", "utf8").includes("docker"); + } catch { + return false; + } +} + +let isWSLCached; +function isWsl() { + if (isWSLCached === void 0) { + isWSLCached = _isWsl(); + } + return isWSLCached; +} +function _isWsl() { + if (process.platform !== "linux") { + return false; + } + if (os.release().toLowerCase().includes("microsoft")) { + if (isDocker()) { + return false; + } + return true; + } + try { + return readFileSync("/proc/version", "utf8").toLowerCase().includes("microsoft") ? !isDocker() : false; + } catch { + return false; + } +} +const defaultMountPoint = "/mnt/"; +let _wslMountpoint; +function getWslDrivesMountPoint() { + if (_wslMountpoint) { + return _wslMountpoint; + } + const configFilePath = "/etc/wsl.conf"; + let isConfigFileExists = false; + try { + accessSync(configFilePath, constants.F_OK); + isConfigFileExists = true; + } catch { + } + if (!isConfigFileExists) { + return defaultMountPoint; + } + const configContent = readFileSync(configFilePath, { encoding: "utf8" }); + const configMountPoint = /(?.*)/g.exec( + configContent + ); + if (!configMountPoint || !configMountPoint.groups) { + return defaultMountPoint; + } + _wslMountpoint = configMountPoint.groups.mountPoint.trim(); + _wslMountpoint = _wslMountpoint.endsWith("/") ? _wslMountpoint : `${_wslMountpoint}/`; + return _wslMountpoint; +} + +async function open(target, options = {}) { + let command; + const cliArguments = []; + const childProcessOptions = {}; + if (process.platform === "darwin") { + command = "open"; + if (options.wait) { + cliArguments.push("--wait-apps"); + } + if (options.background) { + cliArguments.push("--background"); + } + if (options.newInstance) { + cliArguments.push("--new"); + } + } else if (process.platform === "win32" || isWsl() && !isDocker()) { + command = isWsl() ? `${getWslDrivesMountPoint()}c/Windows/System32/WindowsPowerShell/v1.0/powershell.exe` : `${process.env.SYSTEMROOT}\\System32\\WindowsPowerShell\\v1.0\\powershell`; + cliArguments.push( + "-NoProfile", + "-NonInteractive", + "\u2013ExecutionPolicy", + "Bypass", + "-EncodedCommand" + ); + if (!isWsl()) { + childProcessOptions.windowsVerbatimArguments = true; + } + const encodedArguments = ["Start"]; + if (options.wait) { + encodedArguments.push("-Wait"); + } + encodedArguments.push(target); + target = Buffer.from(encodedArguments.join(" "), "utf16le").toString( + "base64" + ); + } else { + command = "xdg-open"; + const useSystemXdgOpen = process.versions.electron || process.platform === "android"; + if (!useSystemXdgOpen) { + command = join(os.tmpdir(), "xdg-open"); + if (!fs.existsSync(command)) { + try { + fs.writeFileSync( + join(os.tmpdir(), "xdg-open"), + await import('./xdg-open.mjs').then((r) => r.xdgOpenScript()), + "utf8" + ); + fs.chmodSync( + command, + 493 + /* rwx r-x r-x */ + ); + } catch { + command = "xdg-open"; + } + } + } + if (!options.wait) { + childProcessOptions.stdio = "ignore"; + childProcessOptions.detached = true; + } + } + cliArguments.push(target); + const subprocess = childProcess.spawn( + command, + cliArguments, + childProcessOptions + ); + if (options.wait) { + return new Promise((resolve, reject) => { + subprocess.once("error", reject); + subprocess.once("close", (exitCode) => { + if (options.allowNonzeroExitCode && exitCode > 0) { + reject(new Error(`Exited with code ${exitCode}`)); + return; + } + resolve(subprocess); + }); + }); + } + subprocess.unref(); + return subprocess; +} + +function getNetworkInterfaces(includeIPV6) { + const addrs = /* @__PURE__ */ new Set(); + for (const details of Object.values(networkInterfaces())) { + if (details) { + for (const d of details) { + if (!d.internal && !(d.mac === "00:00:00:00:00:00") && !d.address.startsWith("fe80::") && !(!includeIPV6 && (d.family === "IPv6" || +d.family === 6))) { + addrs.add(formatAddress(d)); + } + } + } + } + return [...addrs].sort(); +} +function formatAddress(addr) { + return addr.family === "IPv6" || addr.family === 6 ? `[${addr.address}]` : addr.address; +} +function formatURL(url) { + return colors.cyan( + colors.underline( + decodeURI(url).replace(/:(\d+)\//g, `:${colors.bold("$1")}/`) + ) + ); +} +const _localHosts = /* @__PURE__ */ new Set(["127.0.0.1", "localhost", "::1"]); +function isLocalhost(hostname) { + return hostname === void 0 ? false : _localHosts.has(hostname); +} +const _anyHosts = /* @__PURE__ */ new Set(["", "0.0.0.0", "::"]); +function isAnyhost(hostname) { + return hostname === void 0 ? false : _anyHosts.has(hostname); +} +function generateURL(hostname, listhenOptions, baseURL) { + const proto = listhenOptions.https ? "https://" : "http://"; + let port = listhenOptions.port || ""; + if (port === 80 && proto === "http://" || port === 443 && proto === "https://") { + port = ""; + } + if (hostname[0] !== "[" && hostname.includes(":")) { + hostname = `[${hostname}]`; + } + return proto + (hostname || "localhost") + ":" + port + (baseURL || listhenOptions.baseURL || ""); +} +function getDefaultHost(preferPublic) { + if (isDocker() || isWsl()) { + return ""; + } + return preferPublic ? "" : "localhost"; +} +function getPublicURL(listhenOptions, baseURL) { + if (listhenOptions.publicURL) { + return listhenOptions.publicURL; + } + if (d === "stackblitz") { + const stackblitzURL = detectStackblitzURL(listhenOptions._entry); + if (stackblitzURL) { + return stackblitzURL; + } + } + if (listhenOptions.hostname && !isLocalhost(listhenOptions.hostname) && !isAnyhost(listhenOptions.hostname)) { + return generateURL(listhenOptions.hostname, listhenOptions, baseURL); + } +} +function detectStackblitzURL(entry) { + try { + const cwd = process.env.PWD || ""; + if (cwd.startsWith("/home/projects")) { + const projectId = cwd.split("/")[3]; + const relativeEntry = entry && relative(process.cwd(), entry).replace(/^\.\//, ""); + const query = relativeEntry ? `?file=${relativeEntry}` : ""; + return `https://stackblitz.com/edit/${projectId}${query}`; + } + if (cwd.startsWith("/home")) { + const githubRepo = cwd.split("/").slice(2).join("/"); + return `https://stackblitz.com/edit/~/github.com/${githubRepo}`; + } + } catch (error) { + console.error(error); + } +} +const HOSTNAME_RE = /^(?!-)[\d.:A-Za-z-]{1,63}(? options && options.includeBoundaries + ? `(?:(?<=\\s|^)(?=${word})|(?<=${word})(?=\\s|$))` + : ''; + +const v4 = '(?:25[0-5]|2[0-4]\\d|1\\d\\d|[1-9]\\d|\\d)(?:\\.(?:25[0-5]|2[0-4]\\d|1\\d\\d|[1-9]\\d|\\d)){3}'; + +const v6segment = '[a-fA-F\\d]{1,4}'; + +const v6 = ` +(?: +(?:${v6segment}:){7}(?:${v6segment}|:)| // 1:2:3:4:5:6:7:: 1:2:3:4:5:6:7:8 +(?:${v6segment}:){6}(?:${v4}|:${v6segment}|:)| // 1:2:3:4:5:6:: 1:2:3:4:5:6::8 1:2:3:4:5:6::8 1:2:3:4:5:6::1.2.3.4 +(?:${v6segment}:){5}(?::${v4}|(?::${v6segment}){1,2}|:)| // 1:2:3:4:5:: 1:2:3:4:5::7:8 1:2:3:4:5::8 1:2:3:4:5::7:1.2.3.4 +(?:${v6segment}:){4}(?:(?::${v6segment}){0,1}:${v4}|(?::${v6segment}){1,3}|:)| // 1:2:3:4:: 1:2:3:4::6:7:8 1:2:3:4::8 1:2:3:4::6:7:1.2.3.4 +(?:${v6segment}:){3}(?:(?::${v6segment}){0,2}:${v4}|(?::${v6segment}){1,4}|:)| // 1:2:3:: 1:2:3::5:6:7:8 1:2:3::8 1:2:3::5:6:7:1.2.3.4 +(?:${v6segment}:){2}(?:(?::${v6segment}){0,3}:${v4}|(?::${v6segment}){1,5}|:)| // 1:2:: 1:2::4:5:6:7:8 1:2::8 1:2::4:5:6:7:1.2.3.4 +(?:${v6segment}:){1}(?:(?::${v6segment}){0,4}:${v4}|(?::${v6segment}){1,6}|:)| // 1:: 1::3:4:5:6:7:8 1::8 1::3:4:5:6:7:1.2.3.4 +(?::(?:(?::${v6segment}){0,5}:${v4}|(?::${v6segment}){1,7}|:)) // ::2:3:4:5:6:7:8 ::2:3:4:5:6:7:8 ::8 ::1.2.3.4 +)(?:%[0-9a-zA-Z]{1,})? // %eth0 %1 +`.replace(/\s*\/\/.*$/gm, '').replace(/\n/g, '').trim(); + +// Pre-compile only the exact regexes because adding a global flag make regexes stateful +const v46Exact = new RegExp(`(?:^${v4}$)|(?:^${v6}$)`); +const v4exact = new RegExp(`^${v4}$`); +const v6exact = new RegExp(`^${v6}$`); + +const ipRegex = options => options && options.exact + ? v46Exact + : new RegExp(`(?:${boundry(options)}${v4}${boundry(options)})|(?:${boundry(options)}${v6}${boundry(options)})`, 'g'); + +ipRegex.v4 = options => options && options.exact ? v4exact : new RegExp(`${boundry(options)}${v4}${boundry(options)}`, 'g'); +ipRegex.v6 = options => options && options.exact ? v6exact : new RegExp(`${boundry(options)}${v6}${boundry(options)}`, 'g'); + +async function resolveCertificate(options) { + let https; + if (typeof options === "object" && options.key && options.cert) { + https = await resolveCert(options); + if (options.passphrase) { + https.passphrase = options.passphrase; + } + } else if (typeof options === "object" && options.pfx) { + const pfx = await resolvePfx(options); + if (!pfx.safeContents || pfx.safeContents.length < 2 || pfx.safeContents[0].safeBags.length === 0 || pfx.safeContents[1].safeBags.length === 0) { + throw new Error("keystore not containing a cert AND a key"); + } + const _cert = pfx.safeContents[0].safeBags[0].cert; + const _key = pfx.safeContents[1].safeBags[0].key; + https = { + key: forge.pki.privateKeyToPem(_key), + cert: forge.pki.certificateToPem(_cert) + }; + } else { + const { cert } = await generateCertificates(options); + https = cert; + } + return https; +} +async function generateCertificates(options) { + const defaults = { + commonName: "localhost", + countryCode: "US", + state: "Michigan", + locality: "Berkley", + organization: "Testing Corp", + organizationalUnit: "IT department", + domains: ["localhost", "127.0.0.1", "::1"], + validityDays: 1, + bits: 2048 + }; + const caOptions = defu(options, defaults); + caOptions.passphrase = options.signingKeyPassphrase; + const ca = await generateCACert(caOptions); + const domains = Array.isArray(options.domains) ? options.domains : ["localhost", "127.0.0.1", "::1"]; + const certOptions = defu(options, defaults); + const cert = await generateTLSCert({ + ...certOptions, + signingKeyCert: ca.cert, + signingKey: ca.key, + domains + }); + return { ca, cert }; +} +async function resolveCert(options) { + if (options && options.key && options.cert) { + const isInline = (s = "") => s.startsWith("--"); + const r = (s) => isInline(s) ? s : promises.readFile(s, "utf8"); + return { + key: await r(options.key), + cert: await r(options.cert) + }; + } + throw new Error("Certificate or Private Key not present"); +} +async function resolvePfx(options) { + if (options && options.pfx) { + const pfx = await promises.readFile(options.pfx, "binary"); + const p12Asn1 = forge.asn1.fromDer(pfx); + if (options.passphrase) { + return forge.pkcs12.pkcs12FromAsn1(p12Asn1, options.passphrase); + } + return forge.pkcs12.pkcs12FromAsn1(p12Asn1, ""); + } + throw new Error("Error resolving the pfx store"); +} +function createAttributes(options) { + return [ + options.commonName && { name: "commonName", value: options.commonName }, + options.countryCode && { name: "countryName", value: options.countryCode }, + options.state && { name: "stateOrProvinceName", value: options.state }, + options.locality && { name: "localityName", value: options.locality }, + options.organization && { + name: "organizationName", + value: options.organization + }, + options.organizationalUnit && { + name: "organizationalUnitName", + value: options.organizationalUnit + }, + options.emailAddress && { + name: "emailAddress", + value: options.emailAddress + } + ].filter(Boolean); +} +function createCertificateInfo(options) { + if (!options.domains || options.domains && options.domains.length === 0) { + options.domains = ["localhost.local"]; + } + options.commonName = options.commonName || options.domains[0]; + const attributes = createAttributes(options); + const extensions = [ + { name: "basicConstraints", cA: false, critical: true }, + { + name: "keyUsage", + digitalSignature: true, + keyEncipherment: true, + critical: true + }, + { name: "extKeyUsage", serverAuth: true, clientAuth: true }, + { + name: "subjectAltName", + altNames: options.domains.map((domain) => { + const types = { domain: 2, ip: 7 }; + const isIp = ipRegex({ exact: true }).test(domain); + if (isIp) { + return { type: types.ip, ip: domain }; + } + return { type: types.domain, value: domain }; + }) + } + ]; + return { attributes, extensions }; +} +function createCaInfo(options) { + const attributes = createAttributes(options); + const extensions = [ + { name: "basicConstraints", cA: true, critical: true }, + { name: "keyUsage", keyCertSign: true, critical: true } + ]; + return { attributes, extensions }; +} +async function generateTLSCert(options) { + const { attributes, extensions } = createCertificateInfo(options); + const ca = forge.pki.certificateFromPem(options.signingKeyCert); + return await generateCert({ + bits: options.bits, + subject: attributes, + issuer: ca.subject.attributes, + extensions, + validityDays: options.validityDays || 1, + signingKey: options.signingKey, + signingKeyPassphrase: options.signingKeyPassphrase, + passphrase: options.passphrase + }); +} +async function generateCACert(options = {}) { + const { attributes, extensions } = createCaInfo(options); + return await generateCert({ + ...options, + bits: options.bits || 2048, + subject: attributes, + issuer: attributes, + extensions, + validityDays: options.validityDays || 1 + }); +} +function signCertificate(options, cert) { + if (options.signingKey) { + if (isValidPassphrase(options.signingKeyPassphrase)) { + const encryptedPrivateKey = forge.pki.encryptedPrivateKeyFromPem( + options.signingKey + ); + const decryptedPrivateKey = forge.pki.decryptPrivateKeyInfo( + encryptedPrivateKey, + options.signingKeyPassphrase + ); + cert.sign( + forge.pki.privateKeyFromAsn1(decryptedPrivateKey), + forge.md.sha256.create() + ); + } else { + cert.sign( + forge.pki.privateKeyFromPem(options.signingKey), + forge.md.sha256.create() + ); + } + } else { + cert.sign(cert.privateKey, forge.md.sha256.create()); + } +} +function createCertificateFromKeyPair(keyPair, options) { + const serial = Math.floor(Math.random() * 95e3 + 5e4).toString(); + const cert = forge.pki.createCertificate(); + cert.publicKey = keyPair.publicKey; + cert.privateKey = keyPair.privateKey; + cert.serialNumber = Buffer.from(serial).toString("hex"); + cert.validity.notBefore = /* @__PURE__ */ new Date(); + cert.validity.notAfter = /* @__PURE__ */ new Date(); + cert.validity.notAfter.setDate( + cert.validity.notAfter.getDate() + options.validityDays + ); + cert.setSubject(options.subject); + cert.setIssuer(options.issuer); + cert.setExtensions(options.extensions); + return cert; +} +async function generateKeyPair(bits = 2048) { + const _generateKeyPair = promisify( + forge.pki.rsa.generateKeyPair.bind(forge.pki.rsa) + ); + return await _generateKeyPair({ + bits, + workers: os.availableParallelism ? os.availableParallelism() : os.cpus().length + }); +} +function isValidPassphrase(passphrase) { + return typeof passphrase === "string" && passphrase.length < 2e3; +} +async function generateCert(options) { + const keyPair = await generateKeyPair(options.bits); + const cert = createCertificateFromKeyPair(keyPair, options); + if (isValidPassphrase(options.passphrase)) { + const asn1PrivateKey = forge.pki.privateKeyToAsn1(keyPair.privateKey); + const privateKeyInfo = forge.pki.wrapRsaPrivateKey(asn1PrivateKey); + const encryptedPrivateKeyInfo = forge.pki.encryptPrivateKeyInfo( + privateKeyInfo, + options.passphrase, + { + algorithm: "aes256" + } + ); + signCertificate( + { + signingKey: options.signingKey, + signingKeyPassphrase: options.signingKeyPassphrase + }, + cert + ); + return { + key: forge.pki.encryptedPrivateKeyToPem(encryptedPrivateKeyInfo), + cert: forge.pki.certificateToPem(cert), + passphrase: options.passphrase + }; + } else { + signCertificate( + { + signingKey: options.signingKey, + signingKeyPassphrase: options.signingKeyPassphrase + }, + cert + ); + return { + key: forge.pki.privateKeyToPem(keyPair.privateKey), + cert: forge.pki.certificateToPem(cert) + }; + } +} + +async function listen(handle, _options = {}) { + const _isProd = _options.isProd ?? process.env.NODE_ENV === "production"; + const _isTest = _options.isTest ?? process.env.NODE_ENV === "test"; + const _hostname = _options.hostname ?? process.env.HOST; + const _public = _options.public ?? (isLocalhost(_hostname) ? false : void 0) ?? (isAnyhost(_hostname) ? true : void 0) ?? (process.argv.includes("--host") ? true : void 0) ?? _isProd; + const listhenOptions = defu(_options, { + name: "", + https: false, + port: process.env.PORT || 3e3, + hostname: _hostname ?? getDefaultHost(_public), + showURL: true, + baseURL: "/", + open: false, + clipboard: false, + isTest: _isTest, + isProd: _isProd, + public: _public, + autoClose: true + }); + listhenOptions.hostname = validateHostname( + listhenOptions.hostname, + listhenOptions.public + ); + const _localhost = isLocalhost(listhenOptions.hostname); + const _anyhost = isAnyhost(listhenOptions.hostname); + if (listhenOptions.public && _localhost) { + consola.warn( + `[listhen] Trying to listhen on private host ${JSON.stringify( + listhenOptions.hostname + )} with public option enabled.` + ); + listhenOptions.public = false; + } else if (!listhenOptions.public && _anyhost && !(isWsl() || isDocker())) { + consola.warn( + `[listhen] Trying to listhen on public host ${JSON.stringify( + listhenOptions.hostname + )} with public option disabled. Using "localhost".` + ); + listhenOptions.public = false; + listhenOptions.hostname = "localhost"; + } + if (listhenOptions.isTest) { + listhenOptions.showURL = false; + } + if (listhenOptions.isProd || listhenOptions.isTest) { + listhenOptions.open = false; + listhenOptions.clipboard = false; + } + const port = listhenOptions.port = await getPort({ + port: Number(listhenOptions.port), + verbose: !listhenOptions.isTest, + host: listhenOptions.hostname, + alternativePortRange: [3e3, 3100], + public: listhenOptions.public, + ...typeof listhenOptions.port === "object" && listhenOptions.port + }); + let server; + let https = false; + const httpsOptions = listhenOptions.https; + let _addr; + if (httpsOptions) { + https = await resolveCertificate(httpsOptions); + server = createServer$1(https, handle); + addShutdown(server); + await promisify(server.listen.bind(server))(port, listhenOptions.hostname); + _addr = server.address(); + listhenOptions.port = _addr.port; + } else { + server = createServer$2(handle); + addShutdown(server); + await promisify(server.listen.bind(server))(port, listhenOptions.hostname); + _addr = server.address(); + listhenOptions.port = _addr.port; + } + if (listhenOptions.ws) { + if (typeof listhenOptions.ws === "function") { + server.on("upgrade", listhenOptions.ws); + } else { + consola.warn( + "[listhen] Using experimental websocket API. Learn more: `https://crossws.unjs.io`" + ); + const nodeWSAdapter = await import('./node.mjs').then( + (r) => r.default || r + ); + const { handleUpgrade } = nodeWSAdapter({ + ...listhenOptions.ws + }); + server.on("upgrade", handleUpgrade); + } + } + const getURL = (host = listhenOptions.hostname, baseURL) => generateURL(host, listhenOptions, baseURL); + let tunnel; + if (listhenOptions.tunnel) { + const { startTunnel } = await import('./index5.mjs'); + tunnel = await startTunnel({ + url: getURL() + }); + } + let _closed = false; + const close = async () => { + if (_closed) { + return; + } + _closed = true; + await promisify(server.shutdown)().catch(() => { + }); + await tunnel?.close().catch(() => { + }); + }; + if (listhenOptions.clipboard) { + const clipboardy = await import('./index6.mjs').then((r) => r.default || r); + await clipboardy.write(getURL()).catch(() => { + listhenOptions.clipboard = false; + }); + } + const getURLs = async (getURLOptions = {}) => { + const urls = []; + const _addURL = (type, url) => { + if (!urls.some((u) => u.url === url)) { + urls.push({ + url, + type + }); + } + }; + const publicURL = getURLOptions.publicURL || getPublicURL(listhenOptions, getURLOptions.baseURL); + if (publicURL) { + _addURL("network", publicURL); + } + if (_localhost || _anyhost) { + _addURL("local", getURL(listhenOptions.hostname, getURLOptions.baseURL)); + } + if (tunnel) { + _addURL("tunnel", await tunnel.getURL()); + } + if (listhenOptions.public) { + const _ipv6Host = listhenOptions.hostname.includes(":"); + for (const addr of getNetworkInterfaces(_ipv6Host)) { + if (addr === publicURL) { + continue; + } + _addURL("network", getURL(addr, getURLOptions.baseURL)); + } + } + return urls; + }; + const showURL = async (showURLOptions = {}) => { + const lines = []; + const nameSuffix = showURLOptions.name || listhenOptions.name ? ` (${showURLOptions.name || listhenOptions.name})` : ""; + const urls = await getURLs(showURLOptions); + const firstLocalUrl = urls.find((u) => u.type === "local"); + const firstPublicUrl = urls.find((u) => u.type !== "local"); + const showQR = (showURLOptions.qr ?? listhenOptions.qr) !== false; + if (firstPublicUrl && showQR) { + const space = " ".repeat(14); + lines.push(" "); + lines.push( + ...renderUnicodeCompact(firstPublicUrl.url).split("\n").map((line) => space + line) + ); + lines.push(" "); + } + const typeMap = { + local: ["Local", "green"], + tunnel: ["Tunnel", "yellow"], + network: ["Network", "magenta"] + }; + for (const url of urls) { + const type = typeMap[url.type]; + const label = getColor(type[1])( + ` \u279C ${(type[0] + ":").padEnd(8, " ")}${nameSuffix} ` + ); + let suffix = ""; + if (url === firstLocalUrl && listhenOptions.clipboard) { + suffix += colors.gray(" [copied to clipboard]"); + } + if (url === firstPublicUrl && showQR) { + suffix += colors.gray(" [QR code]"); + } + lines.push(`${label} ${formatURL(url.url)}${suffix}`); + } + if (!firstPublicUrl) { + lines.push( + colors.gray(` \u279C Network: use ${colors.white("--host")} to expose`) + ); + } + console.log("\n" + lines.join("\n") + "\n"); + }; + if (listhenOptions.showURL) { + showURL(); + } + const _open = async () => { + await open(getURL()).catch(() => { + }); + }; + if (listhenOptions.open) { + await _open(); + } + if (listhenOptions.autoClose) { + process.setMaxListeners(0); + process.once("exit", () => close()); + process.once("SIGINT", () => process.exit(0)); + process.once("SIGTERM", () => process.exit(0)); + process.once("SIGHUP", () => process.exit(0)); + } + return { + url: getURL(), + https, + server, + address: _addr, + open: _open, + showURL, + getURLs, + close + }; +} + +export { listen }; diff --git a/.pnpm-store/v3/files/3d/b7fbd7d9a51d6dea86e1da79da7f14ee22c5af122c6b23d9929d8d6e9ddaf9211d225640de86ab8e83c960d07b9ba8127a1de24810c01bb65efbabbfc014c6 b/.pnpm-store/v3/files/3d/b7fbd7d9a51d6dea86e1da79da7f14ee22c5af122c6b23d9929d8d6e9ddaf9211d225640de86ab8e83c960d07b9ba8127a1de24810c01bb65efbabbfc014c6 new file mode 100644 index 0000000000000000000000000000000000000000..12e3954314d9d6ec074cabb40e4b6ccb9e8dd788 --- /dev/null +++ b/.pnpm-store/v3/files/3d/b7fbd7d9a51d6dea86e1da79da7f14ee22c5af122c6b23d9929d8d6e9ddaf9211d225640de86ab8e83c960d07b9ba8127a1de24810c01bb65efbabbfc014c6 @@ -0,0 +1,111 @@ +import { d as defineCommand, c as consola } from '../shared/nuxi.9edf0930.mjs'; +import 'node:util'; +import 'node:path'; +import 'node:process'; +import 'node:tty'; +import { l as loadKit } from '../shared/nuxi.dc1b30dc.mjs'; +import { a as clearBuildDir } from '../shared/nuxi.1ff5d6e2.mjs'; +import { o as overrideEnv } from '../shared/nuxi.2509f57e.mjs'; +import { s as showVersions } from '../shared/nuxi.c8477004.mjs'; +import { s as sharedArgs, l as legacyRootDirArgs, r as resolve, a as relative } from '../shared/nuxi.610c92ff.mjs'; +import 'node:url'; +import '../shared/nuxi.1902c37d.mjs'; +import 'node:module'; +import 'node:fs'; +import '../shared/nuxi.53f5921c.mjs'; +import 'node:assert'; +import 'node:v8'; +import 'node:perf_hooks'; +import '../shared/nuxi.eaa29140.mjs'; +import './satisfies.mjs'; +import '../shared/nuxi.2155838d.mjs'; +import '../shared/nuxi.cc8dd4a9.mjs'; +import '../shared/nuxi.73800aa7.mjs'; +import 'crypto'; +import 'fs'; +import 'module'; +import 'path'; +import 'perf_hooks'; +import 'os'; +import 'vm'; +import 'url'; +import 'assert'; +import 'process'; +import 'v8'; +import 'util'; +import 'tty'; +import '../shared/nuxi.d3241ca4.mjs'; +import '../shared/nuxi.5aaa4630.mjs'; + +const buildCommand = defineCommand({ + meta: { + name: "build", + description: "Build Nuxt for production deployment" + }, + args: { + ...sharedArgs, + prerender: { + type: "boolean", + description: "Build Nuxt and prerender static routes" + }, + preset: { + type: "string", + description: "Nitro server preset" + }, + dotenv: { + type: "string", + description: "Path to .env file" + }, + ...legacyRootDirArgs + }, + async run(ctx) { + overrideEnv("production"); + const cwd = resolve(ctx.args.cwd || ctx.args.rootDir || "."); + showVersions(cwd); + const kit = await loadKit(cwd); + const nitroPreset = ctx.args.prerender ? "static" : ctx.args.preset; + if (nitroPreset) { + consola.info(`Using Nitro server preset: \`${nitroPreset}\``); + } + const nuxt = await kit.loadNuxt({ + cwd, + dotenv: { + cwd, + fileName: ctx.args.dotenv + }, + overrides: { + logLevel: ctx.args.logLevel, + // TODO: remove in 3.8 + _generate: ctx.args.prerender, + ...ctx.args.prerender ? { nitro: { static: true } } : { nitro: { preset: nitroPreset } }, + ...ctx.data?.overrides + } + }); + let nitro; + try { + nitro = kit.useNitro?.(); + } catch { + } + await clearBuildDir(nuxt.options.buildDir); + await kit.writeTypes(nuxt); + nuxt.hook("build:error", (err) => { + consola.error("Nuxt Build Error:", err); + process.exit(1); + }); + await kit.buildNuxt(nuxt); + if (ctx.args.prerender) { + if (!nuxt.options.ssr) { + consola.warn( + "HTML content not prerendered because `ssr: false` was set. You can read more in `https://nuxt.com/docs/getting-started/deployment#static-hosting`." + ); + } + const dir = nitro?.options.output.publicDir; + const publicDir = dir ? relative(process.cwd(), dir) : ".output/public"; + consola.success( + `You can now deploy \`${publicDir}\` to any static hosting!` + ); + } + } +}); + +export { buildCommand as default }; diff --git a/.pnpm-store/v3/files/4b/b0a55a58f0ff2ae7dc7ba0e9bfa03a5995b979d1ac38389e0dca4e17bc5efa9be144c5c9808385bbe90e001177e3d5272086e6f09c8ea7808851179fff4dcf b/.pnpm-store/v3/files/4b/b0a55a58f0ff2ae7dc7ba0e9bfa03a5995b979d1ac38389e0dca4e17bc5efa9be144c5c9808385bbe90e001177e3d5272086e6f09c8ea7808851179fff4dcf new file mode 100644 index 0000000000000000000000000000000000000000..bb0a1d8954cf8185e913e19eeaf9d2dc9c4500be --- /dev/null +++ b/.pnpm-store/v3/files/4b/b0a55a58f0ff2ae7dc7ba0e9bfa03a5995b979d1ac38389e0dca4e17bc5efa9be144c5c9808385bbe90e001177e3d5272086e6f09c8ea7808851179fff4dcf @@ -0,0 +1,11 @@ +const overrideEnv = (targetEnv) => { + const currentEnv = process.env.NODE_ENV; + if (currentEnv && currentEnv !== targetEnv) { + console.warn( + `Changing \`NODE_ENV\` from \`${currentEnv}\` to \`${targetEnv}\`, to avoid unintended behavior.` + ); + } + process.env.NODE_ENV = targetEnv; +}; + +export { overrideEnv as o }; diff --git a/.pnpm-store/v3/files/51/5444e545d62ea7d0ba8944d63b3a530262133943fb51aacd3f9df2e2d38891dd73d6ee7ae0ecf400c495623110e494e9e4a9d60dee72e145e447e4ce40e1c8 b/.pnpm-store/v3/files/51/5444e545d62ea7d0ba8944d63b3a530262133943fb51aacd3f9df2e2d38891dd73d6ee7ae0ecf400c495623110e494e9e4a9d60dee72e145e447e4ce40e1c8 new file mode 100644 index 0000000000000000000000000000000000000000..05e1f6183d618170c19b8810ab5757cbc8470ffa --- /dev/null +++ b/.pnpm-store/v3/files/51/5444e545d62ea7d0ba8944d63b3a530262133943fb51aacd3f9df2e2d38891dd73d6ee7ae0ecf400c495623110e494e9e4a9d60dee72e145e447e4ce40e1c8 @@ -0,0 +1,74 @@ +import { execa } from './index3.mjs'; +import { d as defineCommand, c as consola } from '../shared/nuxi.9edf0930.mjs'; +import 'node:util'; +import 'node:path'; +import 'node:process'; +import 'node:tty'; +import { t as tryResolveModule } from '../shared/nuxi.1902c37d.mjs'; +import { s as sharedArgs, l as legacyRootDirArgs, r as resolve } from '../shared/nuxi.610c92ff.mjs'; +import 'node:buffer'; +import 'node:child_process'; +import '../shared/nuxi.2155838d.mjs'; +import 'child_process'; +import 'path'; +import 'fs'; +import 'node:url'; +import 'node:os'; +import 'node:fs'; +import 'node:timers/promises'; +import 'stream'; +import 'node:module'; +import '../shared/nuxi.53f5921c.mjs'; +import 'node:assert'; +import 'node:v8'; + +const MODULE_BUILDER_PKG = "@nuxt/module-builder"; +const buildModule = defineCommand({ + meta: { + name: "build-module", + description: `Helper command for using ${MODULE_BUILDER_PKG}` + }, + args: { + ...sharedArgs, + ...legacyRootDirArgs, + stub: { + type: "boolean", + description: "Stub dist instead of actually building it for development" + }, + sourcemap: { + type: "boolean", + description: "Generate sourcemaps" + }, + prepare: { + type: "boolean", + description: "Prepare module for local development" + } + }, + async run(ctx) { + const cwd = resolve(ctx.args.cwd || ctx.args.rootDir || "."); + const hasLocal = await tryResolveModule( + `${MODULE_BUILDER_PKG}/package.json`, + cwd + ); + const execArgs = Object.entries({ + "--stub": ctx.args.stub, + "--sourcemap": ctx.args.sourcemap, + "--prepare": ctx.args.prepare + }).filter(([, value]) => value).map(([key]) => key); + let cmd = "nuxt-module-build"; + if (!hasLocal) { + consola.warn( + `Cannot find locally installed version of \`${MODULE_BUILDER_PKG}\` (>=0.2.0). Falling back to \`npx ${MODULE_BUILDER_PKG}\`` + ); + cmd = "npx"; + execArgs.unshift(MODULE_BUILDER_PKG); + } + await execa(cmd, execArgs, { + cwd, + preferLocal: true, + stdio: "inherit" + }); + } +}); + +export { buildModule as default }; diff --git a/.pnpm-store/v3/files/5f/18bb5fb155a80f7e4a82b0538a894e8586b6a0e0cdb5a5630a4c0b51701578a13b9ec1e715c02d76afcac30c87c138bb0aa41902630a291af525cc192ce3ca b/.pnpm-store/v3/files/5f/18bb5fb155a80f7e4a82b0538a894e8586b6a0e0cdb5a5630a4c0b51701578a13b9ec1e715c02d76afcac30c87c138bb0aa41902630a291af525cc192ce3ca new file mode 100644 index 0000000000000000000000000000000000000000..5cba810ec73a79c29706de846746655fd3f0879c --- /dev/null +++ b/.pnpm-store/v3/files/5f/18bb5fb155a80f7e4a82b0538a894e8586b6a0e0cdb5a5630a4c0b51701578a13b9ec1e715c02d76afcac30c87c138bb0aa41902630a291af525cc192ce3ca @@ -0,0 +1,21 @@ +The MIT License (MIT) + +Copyright (c) Nuxt Team + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. diff --git a/.pnpm-store/v3/files/6c/a67d19868ce8638ae0aaa9e4c9cfb6d89bae6f92cdf40f64ad03612309e401c10b6bf645e0c96e86224733d3bc6e05f6c77e1d36179eb5553bce5440176176 b/.pnpm-store/v3/files/6c/a67d19868ce8638ae0aaa9e4c9cfb6d89bae6f92cdf40f64ad03612309e401c10b6bf645e0c96e86224733d3bc6e05f6c77e1d36179eb5553bce5440176176 new file mode 100644 index 0000000000000000000000000000000000000000..666679ce05a3d32ff3d8da069b2bf2386ec1fc40 --- /dev/null +++ b/.pnpm-store/v3/files/6c/a67d19868ce8638ae0aaa9e4c9cfb6d89bae6f92cdf40f64ad03612309e401c10b6bf645e0c96e86224733d3bc6e05f6c77e1d36179eb5553bce5440176176 @@ -0,0 +1,10 @@ +declare const main: any; + +declare const runMain: () => Promise; +declare function runCommand(name: string, argv?: string[], data?: { + overrides?: Record; +}): Promise<{ + result: unknown; +}>; + +export { main, runCommand, runMain }; diff --git a/.pnpm-store/v3/files/73/2d794726dfb64b23b283a438d1a7003c65b70cfdc5d7e582c38e4f6bdb7f22fd27d8507308516db0ecec751ef57b5c5fb44898463960b8346bb91f21af56de b/.pnpm-store/v3/files/73/2d794726dfb64b23b283a438d1a7003c65b70cfdc5d7e582c38e4f6bdb7f22fd27d8507308516db0ecec751ef57b5c5fb44898463960b8346bb91f21af56de new file mode 100644 index 0000000000000000000000000000000000000000..107f12570d697d1a4273f48509bc846d443a291a --- /dev/null +++ b/.pnpm-store/v3/files/73/2d794726dfb64b23b283a438d1a7003c65b70cfdc5d7e582c38e4f6bdb7f22fd27d8507308516db0ecec751ef57b5c5fb44898463960b8346bb91f21af56de @@ -0,0 +1,319 @@ +import process from 'node:process'; +import os from 'node:os'; +import fs from 'node:fs'; +import { execa, execaSync } from './index3.mjs'; +import path from 'node:path'; +import { fileURLToPath } from 'node:url'; +import { promisify } from 'node:util'; +import childProcess from 'node:child_process'; +import 'node:buffer'; +import '../shared/nuxi.2155838d.mjs'; +import 'child_process'; +import 'path'; +import 'fs'; +import 'node:timers/promises'; +import 'stream'; + +let isDockerCached; + +function hasDockerEnv() { + try { + fs.statSync('/.dockerenv'); + return true; + } catch { + return false; + } +} + +function hasDockerCGroup() { + try { + return fs.readFileSync('/proc/self/cgroup', 'utf8').includes('docker'); + } catch { + return false; + } +} + +function isDocker() { + // TODO: Use `??=` when targeting Node.js 16. + if (isDockerCached === undefined) { + isDockerCached = hasDockerEnv() || hasDockerCGroup(); + } + + return isDockerCached; +} + +let cachedResult; + +// Podman detection +const hasContainerEnv = () => { + try { + fs.statSync('/run/.containerenv'); + return true; + } catch { + return false; + } +}; + +function isInsideContainer() { + // TODO: Use `??=` when targeting Node.js 16. + if (cachedResult === undefined) { + cachedResult = hasContainerEnv() || isDocker(); + } + + return cachedResult; +} + +const isWsl = () => { + if (process.platform !== 'linux') { + return false; + } + + if (os.release().toLowerCase().includes('microsoft')) { + if (isInsideContainer()) { + return false; + } + + return true; + } + + try { + return fs.readFileSync('/proc/version', 'utf8').toLowerCase().includes('microsoft') + ? !isInsideContainer() : false; + } catch { + return false; + } +}; + +const isWSL = process.env.__IS_WSL_TEST__ ? isWsl : isWsl(); + +const handler = error => { + if (error.code === 'ENOENT') { + throw new Error('Couldn\'t find the termux-api scripts. You can install them with: apt install termux-api'); + } + + throw error; +}; + +const clipboard$4 = { + async copy(options) { + try { + await execa('termux-clipboard-set', options); + } catch (error) { + handler(error); + } + }, + async paste(options) { + try { + const {stdout} = await execa('termux-clipboard-get', options); + return stdout; + } catch (error) { + handler(error); + } + }, + copySync(options) { + try { + execaSync('termux-clipboard-set', options); + } catch (error) { + handler(error); + } + }, + pasteSync(options) { + try { + return execaSync('termux-clipboard-get', options).stdout; + } catch (error) { + handler(error); + } + }, +}; + +const termux = clipboard$4; + +const __dirname$1 = path.dirname(fileURLToPath(import.meta.url)); + +const xsel = 'xsel'; +const xselFallback = path.join(__dirname$1, '../fallbacks/linux/xsel'); + +const copyArguments = ['--clipboard', '--input']; +const pasteArguments = ['--clipboard', '--output']; + +const makeError = (xselError, fallbackError) => { + let error; + if (xselError.code === 'ENOENT') { + error = new Error('Couldn\'t find the `xsel` binary and fallback didn\'t work. On Debian/Ubuntu you can install xsel with: sudo apt install xsel'); + } else { + error = new Error('Both xsel and fallback failed'); + error.xselError = xselError; + } + + error.fallbackError = fallbackError; + return error; +}; + +const xselWithFallback = async (argumentList, options) => { + try { + const {stdout} = await execa(xsel, argumentList, options); + return stdout; + } catch (xselError) { + try { + const {stdout} = await execa(xselFallback, argumentList, options); + return stdout; + } catch (fallbackError) { + throw makeError(xselError, fallbackError); + } + } +}; + +const xselWithFallbackSync = (argumentList, options) => { + try { + return execaSync(xsel, argumentList, options).stdout; + } catch (xselError) { + try { + return execaSync(xselFallback, argumentList, options).stdout; + } catch (fallbackError) { + throw makeError(xselError, fallbackError); + } + } +}; + +const clipboard$3 = { + async copy(options) { + await xselWithFallback(copyArguments, options); + }, + copySync(options) { + xselWithFallbackSync(copyArguments, options); + }, + paste: options => xselWithFallback(pasteArguments, options), + pasteSync: options => xselWithFallbackSync(pasteArguments, options), +}; + +const linux = clipboard$3; + +const env = { + LC_CTYPE: 'UTF-8', // eslint-disable-line unicorn/text-encoding-identifier-case +}; + +const clipboard$2 = { + copy: async options => execa('pbcopy', {...options, env}), + async paste(options) { + const {stdout} = await execa('pbpaste', {...options, env}); + return stdout; + }, + copySync: options => execaSync('pbcopy', {...options, env}), + pasteSync: options => execaSync('pbpaste', {...options, env}).stdout, +}; + +const macos = clipboard$2; + +promisify(childProcess.execFile); + +function systemArchitectureSync() { + const {arch, platform, env} = process; + + // Detect Node.js x64 binary running under Rosetta 2 on a ARM64 Mac. + if (platform === 'darwin' && arch === 'x64') { + const stdout = childProcess.execFileSync('sysctl', ['-inq', 'sysctl.proc_translated'], {encoding: 'utf8'}); + return stdout.trim() === '1' ? 'arm64' : 'x64'; + } + + if (arch === 'arm64' || arch === 'x64') { + return arch; + } + + if (platform === 'win32' && Object.hasOwn(env, 'PROCESSOR_ARCHITEW6432')) { + return 'x64'; + } + + if (platform === 'linux') { + const stdout = childProcess.execFileSync('getconf', ['LONG_BIT'], {encoding: 'utf8'}); + if (stdout.trim() === '64') { + return 'x64'; + } + } + + return arch; +} + +const archtectures64bit = new Set([ + 'arm64', + 'x64', + 'ppc64', + 'riscv64', +]); + +function is64bitSync() { + return archtectures64bit.has(systemArchitectureSync()); +} + +const __dirname = path.dirname(fileURLToPath(import.meta.url)); + +const binarySuffix = is64bitSync() ? 'x86_64' : 'i686'; + +// Binaries from: https://github.com/sindresorhus/win-clipboard +const windowBinaryPath = path.join(__dirname, `../fallbacks/windows/clipboard_${binarySuffix}.exe`); + +const clipboard$1 = { + copy: async options => execa(windowBinaryPath, ['--copy'], options), + async paste(options) { + const {stdout} = await execa(windowBinaryPath, ['--paste'], options); + return stdout; + }, + copySync: options => execaSync(windowBinaryPath, ['--copy'], options), + pasteSync: options => execaSync(windowBinaryPath, ['--paste'], options).stdout, +}; + +const windows = clipboard$1; + +const platformLib = (() => { + switch (process.platform) { + case 'darwin': { + return macos; + } + + case 'win32': { + return windows; + } + + case 'android': { + if (process.env.PREFIX !== '/data/data/com.termux/files/usr') { + throw new Error('You need to install Termux for this module to work on Android: https://termux.com'); + } + + return termux; + } + + default: { + // `process.platform === 'linux'` for WSL. + if (isWSL) { + return windows; + } + + return linux; + } + } +})(); + +const clipboard = {}; + +clipboard.write = async text => { + if (typeof text !== 'string') { + throw new TypeError(`Expected a string, got ${typeof text}`); + } + + await platformLib.copy({input: text}); +}; + +clipboard.read = async () => platformLib.paste({stripFinalNewline: false}); + +clipboard.writeSync = text => { + if (typeof text !== 'string') { + throw new TypeError(`Expected a string, got ${typeof text}`); + } + + platformLib.copySync({input: text}); +}; + +clipboard.readSync = () => platformLib.pasteSync({stripFinalNewline: false}); + +const clipboardy = clipboard; + +export { clipboardy as default }; diff --git a/.pnpm-store/v3/files/74/5579d31f220241999ae22d3b5672bdfd193e23f1f49c75b64bbd7746b1b2f10f4b3390839b0199c1a205be44fc15d9400755b2defbba4feec3640bbfaed3d0 b/.pnpm-store/v3/files/74/5579d31f220241999ae22d3b5672bdfd193e23f1f49c75b64bbd7746b1b2f10f4b3390839b0199c1a205be44fc15d9400755b2defbba4feec3640bbfaed3d0 new file mode 100644 index 0000000000000000000000000000000000000000..6a9282e3ece056699ef0707d233d67a48b308ca4 --- /dev/null +++ b/.pnpm-store/v3/files/74/5579d31f220241999ae22d3b5672bdfd193e23f1f49c75b64bbd7746b1b2f10f4b3390839b0199c1a205be44fc15d9400755b2defbba4feec3640bbfaed3d0 @@ -0,0 +1,210 @@ +import { existsSync, promises } from 'node:fs'; +import { d as defineCommand, c as consola } from '../shared/nuxi.9edf0930.mjs'; +import 'node:util'; +import 'node:path'; +import 'node:process'; +import 'node:tty'; +import { l as loadKit } from '../shared/nuxi.dc1b30dc.mjs'; +import { u as upperFirst } from '../shared/nuxi.349af404.mjs'; +import { s as sharedArgs, r as resolve, e as extname, d as dirname } from '../shared/nuxi.610c92ff.mjs'; +import 'node:url'; +import '../shared/nuxi.1902c37d.mjs'; +import 'node:module'; +import '../shared/nuxi.53f5921c.mjs'; +import 'node:assert'; +import 'node:v8'; +import 'node:perf_hooks'; +import '../shared/nuxi.eaa29140.mjs'; +import './satisfies.mjs'; +import '../shared/nuxi.2155838d.mjs'; +import '../shared/nuxi.cc8dd4a9.mjs'; +import '../shared/nuxi.73800aa7.mjs'; +import 'crypto'; +import 'fs'; +import 'module'; +import 'path'; +import 'perf_hooks'; +import 'os'; +import 'vm'; +import 'url'; +import 'assert'; +import 'process'; +import 'v8'; +import 'util'; +import 'tty'; + +const httpMethods = [ + "connect", + "delete", + "get", + "head", + "options", + "post", + "put", + "trace", + "patch" +]; +const api = ({ name, args }) => ({ + path: `server/api/${name}${applySuffix(args, httpMethods, "method")}.ts`, + contents: ` +export default defineEventHandler((event) => { + return 'Hello ${name}' +}) +` +}); +const plugin = ({ name, args }) => ({ + path: `plugins/${name}${applySuffix(args, ["client", "server"], "mode")}.ts`, + contents: ` +export default defineNuxtPlugin((nuxtApp) => {}) + ` +}); +const component = ({ name, args }) => ({ + path: `components/${name}${applySuffix( + args, + ["client", "server"], + "mode" + )}.vue`, + contents: ` +