은승우

all add

Showing 1000 changed files with 4289 additions and 223 deletions

Too many changes to show.

To preserve performance only 1000 of 1000+ files are displayed.

1 +var express = require('express');
2 +var app = express();
3 +var client_id = 'bIYcswH22VlQqT8OkkLm';
4 +var client_secret = 'qLaERoks0u';
5 +var query = "한국어";
6 +app.get('/detectLangs', function (req, res) {
7 + var api_url = 'https://openapi.naver.com/v1/papago/detectLangs';
8 + var request = require('request');
9 + var options = {
10 + url: api_url,
11 + form: {'query': query},
12 + headers: {'X-Naver-Client-Id':client_id, 'X-Naver-Client-Secret': client_secret}
13 + };
14 + request.post(options, function (error, response, body) {
15 + if (!error && response.statusCode == 200) {
16 + res.writeHead(200, {'Content-Type': 'text/json;charset=utf-8'});
17 + res.end(body);
18 + } else {
19 + res.status(response.statusCode).end();
20 + console.log('error = ' + response.statusCode);
21 + }
22 + });
23 + });
24 + app.listen(3000, function () {
25 + console.log('http://127.0.0.1:3000/detectLangs app listening on port 3000!');
26 + });
...\ No newline at end of file ...\ No newline at end of file
...@@ -5,7 +5,7 @@ var request = require('request'); ...@@ -5,7 +5,7 @@ var request = require('request');
5 var https=require('https'); 5 var https=require('https');
6 var http=require('http'); 6 var http=require('http');
7 7
8 -/* 8 +
9 var fs = require("fs"); 9 var fs = require("fs");
10 10
11 var httpsOptions = { 11 var httpsOptions = {
...@@ -15,7 +15,6 @@ var httpsOptions = { ...@@ -15,7 +15,6 @@ var httpsOptions = {
15 15
16 http.createServer(app).listen(80); 16 http.createServer(app).listen(80);
17 https.createServer(httpsOptions, app).listen(443); 17 https.createServer(httpsOptions, app).listen(443);
18 -*/
19 /* if ssl expired 18 /* if ssl expired
20 var greenlock= require('greenlock-express'); 19 var greenlock= require('greenlock-express');
21 const lex = greenlock .create({ 20 const lex = greenlock .create({
...@@ -97,6 +96,7 @@ function handleEvent(event) { ...@@ -97,6 +96,7 @@ function handleEvent(event) {
97 'Ocp-Apim-Subscription-Key': subscriptionKey 96 'Ocp-Apim-Subscription-Key': subscriptionKey
98 }, 97 },
99 body: fs.readFileSync(event.message.image) 98 body: fs.readFileSync(event.message.image)
99 + console.log(body);
100 }; 100 };
101 request.post(options, function (error, response, body) { 101 request.post(options, function (error, response, body) {
102 var data=JSON.stringify(body); 102 var data=JSON.stringify(body);
......
1 +var express = require('express');
2 +var app = express();
3 +var client_id = 'bIYcswH22VlQqT8OkkLm';
4 +var client_secret = 'qLaERoks0u';
5 +var query = "힘쌔고 강한 아침!";
6 +app.get('/translate', function (req, res) {
7 + var api_url = 'https://openapi.naver.com/v1/papago/n2mt';
8 + var request = require('request');
9 + var options = {
10 + url: api_url,
11 + form: {'source':'ko', 'target':'en', 'text':query},
12 + headers: {'X-Naver-Client-Id':client_id, 'X-Naver-Client-Secret': client_secret}
13 + };
14 + request.post(options, function (error, response, body) {
15 + if (!error && response.statusCode == 200) {
16 + res.writeHead(200, {'Content-Type': 'text/json;charset=utf-8'});
17 + res.end(body);
18 + } else {
19 + res.status(response.statusCode).end();
20 + console.log('error = ' + response.statusCode);
21 + }
22 + });
23 + });
24 + app.listen(3000, function () {
25 + console.log('http://127.0.0.1:3000/translate app listening on port 3000!');
26 + });
...\ No newline at end of file ...\ No newline at end of file
1 +#!/bin/sh
2 +basedir=$(dirname "$(echo "$0" | sed -e 's,\\,/,g')")
3 +
4 +case `uname` in
5 + *CYGWIN*) basedir=`cygpath -w "$basedir"`;;
6 +esac
7 +
8 +if [ -x "$basedir/node" ]; then
9 + "$basedir/node" "$basedir/../cert-info/bin/cert-info.js" "$@"
10 + ret=$?
11 +else
12 + node "$basedir/../cert-info/bin/cert-info.js" "$@"
13 + ret=$?
14 +fi
15 +exit $ret
1 +@IF EXIST "%~dp0\node.exe" (
2 + "%~dp0\node.exe" "%~dp0\..\cert-info\bin\cert-info.js" %*
3 +) ELSE (
4 + @SETLOCAL
5 + @SET PATHEXT=%PATHEXT:;.JS;=;%
6 + node "%~dp0\..\cert-info\bin\cert-info.js" %*
7 +)
...\ No newline at end of file ...\ No newline at end of file
1 +#!/bin/sh
2 +basedir=$(dirname "$(echo "$0" | sed -e 's,\\,/,g')")
3 +
4 +case `uname` in
5 + *CYGWIN*) basedir=`cygpath -w "$basedir"`;;
6 +esac
7 +
8 +if [ -x "$basedir/node" ]; then
9 + "$basedir/node" "$basedir/../eckles/bin/eckles.js" "$@"
10 + ret=$?
11 +else
12 + node "$basedir/../eckles/bin/eckles.js" "$@"
13 + ret=$?
14 +fi
15 +exit $ret
1 +@IF EXIST "%~dp0\node.exe" (
2 + "%~dp0\node.exe" "%~dp0\..\eckles\bin\eckles.js" %*
3 +) ELSE (
4 + @SETLOCAL
5 + @SET PATHEXT=%PATHEXT:;.JS;=;%
6 + node "%~dp0\..\eckles\bin\eckles.js" %*
7 +)
...\ No newline at end of file ...\ No newline at end of file
1 +#!/bin/sh
2 +basedir=$(dirname "$(echo "$0" | sed -e 's,\\,/,g')")
3 +
4 +case `uname` in
5 + *CYGWIN*) basedir=`cygpath -w "$basedir"`;;
6 +esac
7 +
8 +if [ -x "$basedir/node" ]; then
9 + "$basedir/node" "$basedir/../@root/greenlock/bin/greenlock.js" "$@"
10 + ret=$?
11 +else
12 + node "$basedir/../@root/greenlock/bin/greenlock.js" "$@"
13 + ret=$?
14 +fi
15 +exit $ret
1 +@IF EXIST "%~dp0\node.exe" (
2 + "%~dp0\node.exe" "%~dp0\..\@root\greenlock\bin\greenlock.js" %*
3 +) ELSE (
4 + @SETLOCAL
5 + @SET PATHEXT=%PATHEXT:;.JS;=;%
6 + node "%~dp0\..\@root\greenlock\bin\greenlock.js" %*
7 +)
...\ No newline at end of file ...\ No newline at end of file
1 +#!/bin/sh
2 +basedir=$(dirname "$(echo "$0" | sed -e 's,\\,/,g')")
3 +
4 +case `uname` in
5 + *CYGWIN*) basedir=`cygpath -w "$basedir"`;;
6 +esac
7 +
8 +if [ -x "$basedir/node" ]; then
9 + "$basedir/node" "$basedir/../keypairs/bin/keypairs.js" "$@"
10 + ret=$?
11 +else
12 + node "$basedir/../keypairs/bin/keypairs.js" "$@"
13 + ret=$?
14 +fi
15 +exit $ret
1 +@IF EXIST "%~dp0\node.exe" (
2 + "%~dp0\node.exe" "%~dp0\..\keypairs\bin\keypairs.js" %*
3 +) ELSE (
4 + @SETLOCAL
5 + @SET PATHEXT=%PATHEXT:;.JS;=;%
6 + node "%~dp0\..\keypairs\bin\keypairs.js" %*
7 +)
...\ No newline at end of file ...\ No newline at end of file
1 +#!/bin/sh
2 +basedir=$(dirname "$(echo "$0" | sed -e 's,\\,/,g')")
3 +
4 +case `uname` in
5 + *CYGWIN*) basedir=`cygpath -w "$basedir"`;;
6 +esac
7 +
8 +if [ -x "$basedir/node" ]; then
9 + "$basedir/node" "$basedir/../rasha/bin/rasha.js" "$@"
10 + ret=$?
11 +else
12 + node "$basedir/../rasha/bin/rasha.js" "$@"
13 + ret=$?
14 +fi
15 +exit $ret
1 +@IF EXIST "%~dp0\node.exe" (
2 + "%~dp0\node.exe" "%~dp0\..\rasha\bin\rasha.js" %*
3 +) ELSE (
4 + @SETLOCAL
5 + @SET PATHEXT=%PATHEXT:;.JS;=;%
6 + node "%~dp0\..\rasha\bin\rasha.js" %*
7 +)
...\ No newline at end of file ...\ No newline at end of file
1 +#!/bin/sh
2 +basedir=$(dirname "$(echo "$0" | sed -e 's,\\,/,g')")
3 +
4 +case `uname` in
5 + *CYGWIN*) basedir=`cygpath -w "$basedir"`;;
6 +esac
7 +
8 +if [ -x "$basedir/node" ]; then
9 + "$basedir/node" "$basedir/../rsa-compat/bin/rsa-keygen.js" "$@"
10 + ret=$?
11 +else
12 + node "$basedir/../rsa-compat/bin/rsa-keygen.js" "$@"
13 + ret=$?
14 +fi
15 +exit $ret
1 +@IF EXIST "%~dp0\node.exe" (
2 + "%~dp0\node.exe" "%~dp0\..\rsa-compat\bin\rsa-keygen.js" %*
3 +) ELSE (
4 + @SETLOCAL
5 + @SET PATHEXT=%PATHEXT:;.JS;=;%
6 + node "%~dp0\..\rsa-compat\bin\rsa-keygen.js" %*
7 +)
...\ No newline at end of file ...\ No newline at end of file
1 +#!/bin/sh
2 +basedir=$(dirname "$(echo "$0" | sed -e 's,\\,/,g')")
3 +
4 +case `uname` in
5 + *CYGWIN*) basedir=`cygpath -w "$basedir"`;;
6 +esac
7 +
8 +if [ -x "$basedir/node" ]; then
9 + "$basedir/node" "$basedir/../sshpk/bin/sshpk-conv" "$@"
10 + ret=$?
11 +else
12 + node "$basedir/../sshpk/bin/sshpk-conv" "$@"
13 + ret=$?
14 +fi
15 +exit $ret
1 +@IF EXIST "%~dp0\node.exe" (
2 + "%~dp0\node.exe" "%~dp0\..\sshpk\bin\sshpk-conv" %*
3 +) ELSE (
4 + @SETLOCAL
5 + @SET PATHEXT=%PATHEXT:;.JS;=;%
6 + node "%~dp0\..\sshpk\bin\sshpk-conv" %*
7 +)
...\ No newline at end of file ...\ No newline at end of file
1 +#!/bin/sh
2 +basedir=$(dirname "$(echo "$0" | sed -e 's,\\,/,g')")
3 +
4 +case `uname` in
5 + *CYGWIN*) basedir=`cygpath -w "$basedir"`;;
6 +esac
7 +
8 +if [ -x "$basedir/node" ]; then
9 + "$basedir/node" "$basedir/../sshpk/bin/sshpk-sign" "$@"
10 + ret=$?
11 +else
12 + node "$basedir/../sshpk/bin/sshpk-sign" "$@"
13 + ret=$?
14 +fi
15 +exit $ret
1 +@IF EXIST "%~dp0\node.exe" (
2 + "%~dp0\node.exe" "%~dp0\..\sshpk\bin\sshpk-sign" %*
3 +) ELSE (
4 + @SETLOCAL
5 + @SET PATHEXT=%PATHEXT:;.JS;=;%
6 + node "%~dp0\..\sshpk\bin\sshpk-sign" %*
7 +)
...\ No newline at end of file ...\ No newline at end of file
1 +#!/bin/sh
2 +basedir=$(dirname "$(echo "$0" | sed -e 's,\\,/,g')")
3 +
4 +case `uname` in
5 + *CYGWIN*) basedir=`cygpath -w "$basedir"`;;
6 +esac
7 +
8 +if [ -x "$basedir/node" ]; then
9 + "$basedir/node" "$basedir/../sshpk/bin/sshpk-verify" "$@"
10 + ret=$?
11 +else
12 + node "$basedir/../sshpk/bin/sshpk-verify" "$@"
13 + ret=$?
14 +fi
15 +exit $ret
1 +@IF EXIST "%~dp0\node.exe" (
2 + "%~dp0\node.exe" "%~dp0\..\sshpk\bin\sshpk-verify" %*
3 +) ELSE (
4 + @SETLOCAL
5 + @SET PATHEXT=%PATHEXT:;.JS;=;%
6 + node "%~dp0\..\sshpk\bin\sshpk-verify" %*
7 +)
...\ No newline at end of file ...\ No newline at end of file
1 +#!/bin/sh
2 +basedir=$(dirname "$(echo "$0" | sed -e 's,\\,/,g')")
3 +
4 +case `uname` in
5 + *CYGWIN*) basedir=`cygpath -w "$basedir"`;;
6 +esac
7 +
8 +if [ -x "$basedir/node" ]; then
9 + "$basedir/node" "$basedir/../uuid/bin/uuid" "$@"
10 + ret=$?
11 +else
12 + node "$basedir/../uuid/bin/uuid" "$@"
13 + ret=$?
14 +fi
15 +exit $ret
1 +@IF EXIST "%~dp0\node.exe" (
2 + "%~dp0\node.exe" "%~dp0\..\uuid\bin\uuid" %*
3 +) ELSE (
4 + @SETLOCAL
5 + @SET PATHEXT=%PATHEXT:;.JS;=;%
6 + node "%~dp0\..\uuid\bin\uuid" %*
7 +)
...\ No newline at end of file ...\ No newline at end of file
This diff is collapsed. Click to expand it.
1 +# [Greenlock Manager](https://git.rootprojects.org/root/greenlock-manager.js)
2 +
3 +Manages SSL Certificate issue and renewal for [Greenlock](https://git.rootprojects.org/root/greenlock-manager.js).
4 +
5 +Saves global and per-site config to a local File Sytem (current), with optional encrypted Cloud backup (coming soon).
6 +
7 +```bash
8 +npm install --save greenlock@3
9 +npm install --save greenlock-manager@3
10 +```
11 +
12 +# Greenlock Manager CLI & API
13 +
14 +All manager plugins have the **same API**.
15 +
16 +The manager-specific implementation is overlaid by Greenlock with error handling and common utilities,
17 +and then exposed as documented here.
18 +
19 +**Note**: Most people do not need to (and should not) not use the JavaScript API.
20 +Instead, use the CLI (current) or Web API (coming soon).
21 +
22 +## Initialize the Manager
23 +
24 +```bash
25 +npx greenlock init --manager cloud --manager-token 'xxxx' --manager-config-file './greenlock.json'
26 +```
27 +
28 +Note: You **should not** initialize greenlock directly as
29 +this may make it incompatible with the CLI and Web GUI.
30 +
31 +Instead use the file generated by the CLI `init` (shown above).
32 +
33 +```js
34 +Greenlock.create({
35 + manager: "@greenlock/manager",
36 + cloud: true,
37 + token: "xxxx",
38 + configFile: "./greenlock.json",
39 + packageRoot: __dirname
40 +});
41 +```
42 +
43 +## Set Subscriber and other global Defaults
44 +
45 +```bash
46 +npx greenlock defaults --subscriber-email jon@example.com --agree-to-terms true
47 +```
48 +
49 +```js
50 +greenlock.manager.defaults({
51 + subscriberEmail: "jon@example.com",
52 + agreeToTerms: true
53 +});
54 +```
55 +
56 +# Site Management
57 +
58 +By "site" we mean a primary domain and, optionally, secondary domains, to be listed on an ssl certificate,
59 +along with any configuration that is necessary for getting and renewing those certificates.
60 +
61 +## Add a sites - domains and SSL certificates
62 +
63 +```bash
64 +npx greenlock add --subject example.com --altnames 'example.com,www.example.com'
65 +```
66 +
67 +```js
68 +greenlock.sites.add({
69 + subject: "example.com",
70 + altnames: ["example.com", "www.example.com"]
71 +});
72 +```
73 +
74 +## View site config
75 +
76 +```bash
77 +npx greenlock config --subject example.com
78 +```
79 +
80 +```js
81 +greenlock.sites.get({
82 + servername: "www.example.com",
83 + wildname: "*.example.com"
84 +});
85 +```
86 +
87 +## Update site config
88 +
89 +```bash
90 +npx greenlock update --subject example.com --challenge-dns-01 acme-dns-01-ovh --challenge-dns-01-token xxxx
91 +```
92 +
93 +```js
94 +greenlock.sites.update({
95 + subject: "www.example.com",
96 + challenges: {
97 + "dns-01": {
98 + module: "acme-dns-01-ovh",
99 + token: "xxxx"
100 + }
101 + }
102 +});
103 +```
104 +
105 +## Remove a site
106 +
107 +To stop automatic renewal of SSL certificates for a particular site.
108 +You to restart renewal you must use `add()`.
109 +
110 +```bash
111 +npx greenlock remove --subject example.com
112 +```
113 +
114 +```js
115 +greenlock.sites.remove({
116 + subject: "example.com"
117 +});
118 +```
1 +"use strict";
2 +
3 +var MFS = require("greenlock-manager-fs");
4 +// TODO @greenlock/manager-cloud
5 +
6 +var Manager = module.exports;
7 +Manager.create = function(opts) {
8 + var mfs = MFS.create(opts);
9 + var manager = {};
10 +
11 + //
12 + // REQUIRED (basic issuance)
13 + //
14 + if (mfs.get) {
15 + manager.get = async function({ servername, wildname }) {
16 + // (optional) `wildcard` may or may not exist
17 + // if *you* support wildcard domains, *you* should handle them
18 + return mfs.get({ servername, wildname });
19 + };
20 + } else {
21 + // (optional)
22 + // because the current version doesn't have get()
23 + manager.get = createGetFromFind();
24 + }
25 +
26 + //
27 + // REQUIRED (basic issuance)
28 + //
29 + manager.set = async function(opts) {
30 + return mfs.set(opts);
31 + };
32 +
33 + //
34 + // Optional (Fully Automatic Renewal)
35 + //
36 + manager.find = async function(opts) {
37 + // { subject, servernames, altnames, renewBefore }
38 + return mfs.find(opts);
39 + };
40 +
41 + //
42 + // Optional (Special Remove Functionality)
43 + // The default behavior is to set `deletedAt`
44 + //
45 + //manager.remove = async function(opts) {
46 + // return mfs.remove(opts);
47 + //};
48 +
49 + //
50 + // Optional (special settings save)
51 + // Implemented here because this module IS the fallback
52 + //
53 + manager.defaults = async function(opts) {
54 + return mfs.defaults(opts);
55 + };
56 +
57 + //
58 + // Optional (for common deps and/or async initialization)
59 + //
60 + manager.init = async function(deps) {
61 + return mfs.init(deps);
62 + };
63 +
64 + return manager;
65 +
66 + //
67 + // IGNORE
68 + // Backwards compat for the first versions of greenlock-manager-fs
69 + //
70 + function createGetFromFind() {
71 + return async function({ servername, wildname }) {
72 + var servernames = [servername];
73 + if (wildname) {
74 + servernames.push(wildname);
75 + }
76 + return mfs
77 + .find({
78 + servernames: servernames,
79 + // because the original manager used altnames here
80 + altnames: servernames
81 + })
82 + .then(function(sites) {
83 + return sites[0] || null;
84 + });
85 + };
86 + }
87 +};
1 +{
2 + "_from": "@greenlock/manager@^3.0.0",
3 + "_id": "@greenlock/manager@3.0.0",
4 + "_inBundle": false,
5 + "_integrity": "sha512-ijgJrFdzJPmzrDk8aKXYoYR8LNfG3hXd9/s54ZY7IgxTulyPQ/qOPgl7sWgCxxLhZBzSY1xI6eC/6Y5TQ01agg==",
6 + "_location": "/@greenlock/manager",
7 + "_phantomChildren": {},
8 + "_requested": {
9 + "type": "range",
10 + "registry": true,
11 + "raw": "@greenlock/manager@^3.0.0",
12 + "name": "@greenlock/manager",
13 + "escapedName": "@greenlock%2fmanager",
14 + "scope": "@greenlock",
15 + "rawSpec": "^3.0.0",
16 + "saveSpec": null,
17 + "fetchSpec": "^3.0.0"
18 + },
19 + "_requiredBy": [
20 + "/@root/greenlock"
21 + ],
22 + "_resolved": "https://registry.npmjs.org/@greenlock/manager/-/manager-3.0.0.tgz",
23 + "_shasum": "dfc8155d101fd9c28b1fd5b777ba34ab7180ed57",
24 + "_spec": "@greenlock/manager@^3.0.0",
25 + "_where": "C:\\Users\\USER\\Documents\\Desktop\\옵소팀플\\LINEBOT\\node_modules\\@root\\greenlock",
26 + "author": {
27 + "name": "AJ ONeal",
28 + "email": "coolaj86@gmail.com",
29 + "url": "https://coolaj86.com/"
30 + },
31 + "bundleDependencies": false,
32 + "dependencies": {
33 + "greenlock-manager-fs": "^3.0.5"
34 + },
35 + "deprecated": false,
36 + "description": "FileSytem-based Manager with optional encrypted Cloud backup for Greenlock SSL",
37 + "devDependencies": {
38 + "greenlock-manager-test": "^3.1.1"
39 + },
40 + "files": [
41 + "*.js",
42 + "lib"
43 + ],
44 + "keywords": [
45 + "greenlock",
46 + "manager",
47 + "cloud",
48 + "fs",
49 + "ssl",
50 + "file",
51 + "system"
52 + ],
53 + "license": "MPL-2.0",
54 + "main": "manager.js",
55 + "name": "@greenlock/manager",
56 + "repository": {
57 + "type": "git",
58 + "url": "https://git.rootprojects.org/root/greenlock-manager.js.git"
59 + },
60 + "scripts": {
61 + "test": "node tests"
62 + },
63 + "version": "3.0.0"
64 +}
1 +## 6.8.3 (05 Nov 2019)
2 +
3 +### Bug fix
4 +
5 +* Add exception handler in middleware (#153)
6 +
7 +### Feature
8 +
9 +* Flex Message Update 1 (#173)
10 +* Support friend statistics API (#161)
11 +
12 +### Misc
13 +
14 +* Update dependencies (#174)
15 +
16 +## 6.8.2 (08 Aug 2019)
17 +
18 +### Bug fix
19 +
20 +* Fix LINEThings Scenario Execution Event Types (#158)
21 +
22 +## 6.8.1 (29 Jul 2019)
23 +
24 +### Bug fix
25 +
26 +* Fix a type wrong in Template Message (#163)
27 +
28 +### Feature
29 +* Get `X-LINE-Request-Id` by using `responseData['x-line-request-id']` (#151 #157)
30 +
31 +## 6.8.0 (25 Jun 2019)
32 +
33 +### Feature
34 +
35 +* Add new parameter in push/reply/multicast/broadcast API to catch up the newest bot API (#147)
36 +* Add new APIs in bot API (#147)
37 + - Get the target limit for additional messages
38 + - Get number of messages sent this month
39 + - Get number of sent broadcast messages
40 + - Send broadcast message
41 +
42 +### Breaking changes
43 +* Deprecate Node 6 and start to support Node 12 (#139)
44 +* Remove polyfills for Node 6 (#149)
45 +
46 +### Type
47 +
48 +* Add LINE Things Event (#150)
49 +
50 +### Misc
51 +* Update axios and other dependencies by running `npm audit fix` to fix vulnerabilities. (#148 #154)
52 +
53 +## 6.7.0 (18 Apr 2019)
54 +
55 +### Feature
56 +
57 +* Add alt URL field to URI action (#135)
58 +* Implement (un)linkRichMenuToMultipleUsers (#135)
59 +
60 +### Type
61 +
62 +* Fix typo in a type (#124)
63 +
64 +
65 +## 6.6.0 (4 Mar 2019)
66 +
67 +### Feature
68 +
69 +* Add DeviceLinkEvent / DeviceUnlinkEvent (#123)
70 +
71 +### Type
72 +
73 +* Fix FlexSpacer to have optional 'size' property (#122)
74 +
75 +### Misc
76 +
77 +* Run `npm audit fix` to fix minor dependency vulnerability.
78 +
79 +
80 +## 6.5.0 (16 Feb 2019)
81 +
82 +### Feature
83 +
84 +* Add APIs to get number of sent messages (#116)
85 +* Add account link event (#117)
86 +
87 +### Misc
88 +
89 +* Fix a typo in doc (#119)
90 +
91 +
1 ## 6.4.0 (19 Nov 2018) 92 ## 6.4.0 (19 Nov 2018)
2 93
3 ### Feature 94 ### Feature
......
1 -# line-bot-sdk-nodejs 1 +# LINE Messaging API SDK for nodejs
2 2
3 [![Travis CI](https://travis-ci.org/line/line-bot-sdk-nodejs.svg?branch=master)](https://travis-ci.org/line/line-bot-sdk-nodejs) 3 [![Travis CI](https://travis-ci.org/line/line-bot-sdk-nodejs.svg?branch=master)](https://travis-ci.org/line/line-bot-sdk-nodejs)
4 [![npmjs](https://badge.fury.io/js/%40line%2Fbot-sdk.svg)](https://www.npmjs.com/package/@line/bot-sdk) 4 [![npmjs](https://badge.fury.io/js/%40line%2Fbot-sdk.svg)](https://www.npmjs.com/package/@line/bot-sdk)
5 5
6 -Node.js SDK for LINE Messaging API
7 6
8 -## Getting Started 7 +## Introduction
8 +The LINE Messaging API SDK for nodejs makes it easy to develop bots using LINE Messaging API, and you can create a sample bot within minutes.
9 9
10 -### Install 10 +## Documentation
11 +
12 +See the official API documentation for more information
13 +
14 +- English: https://developers.line.biz/en/docs/messaging-api/overview/
15 +- Japanese: https://developers.line.biz/ja/docs/messaging-api/overview/
16 +
17 +line-bot-sdk-nodejs documentation: https://line.github.io/line-bot-sdk-nodejs/#getting-started
18 +
19 +## Requirements
20 +
21 +* **Node.js** 8 or higher
22 +
23 +## Installation
11 24
12 Using [npm](https://www.npmjs.com/): 25 Using [npm](https://www.npmjs.com/):
13 26
...@@ -15,30 +28,37 @@ Using [npm](https://www.npmjs.com/): ...@@ -15,30 +28,37 @@ Using [npm](https://www.npmjs.com/):
15 $ npm install @line/bot-sdk --save 28 $ npm install @line/bot-sdk --save
16 ``` 29 ```
17 30
18 -### Documentation 31 +## Help and media
19 - 32 +FAQ: https://developers.line.biz/en/faq/
20 -For guide, API reference, and other information, please refer to
21 -the [documentation](https://line.github.io/line-bot-sdk-nodejs/).
22 33
23 -### LINE Messaging API References 34 +Community Q&A: https://www.line-community.me/questions
24 35
25 -Here are links to official references for LINE Messaging API. It is recommended 36 +News: https://developers.line.biz/en/news/
26 -reading them beforehand.
27 37
28 -* LINE API Reference [EN](https://developers.line.me/en/docs/messaging-api/reference/) [JA](https://developers.line.me/ja/docs/messaging-api/reference/) 38 +Twitter: @LINE_DEV
29 -* LINE Developers - Messaging API
30 - * [Overview](https://developers.line.me/messaging-api/overview)
31 - * [Getting started](https://developers.line.me/messaging-api/getting-started)
32 - * [Joining groups and rooms](https://developers.line.me/messaging-api/joining-groups-and-rooms)
33 39
34 -## Requirements 40 +## Versioning
41 +This project respects semantic versioning
35 42
36 -* **Node.js** 6 or higher 43 +See http://semver.org/
37 44
38 ## Contributing 45 ## Contributing
39 46
40 Please check [CONTRIBUTING](CONTRIBUTING.md) before making a contribution. 47 Please check [CONTRIBUTING](CONTRIBUTING.md) before making a contribution.
41 48
42 ## License 49 ## License
43 - 50 +```
44 -[Apache License Version 2.0](LICENSE) 51 +Copyright (C) 2016 LINE Corp.
52 +
53 +Licensed under the Apache License, Version 2.0 (the "License");
54 +you may not use this file except in compliance with the License.
55 +You may obtain a copy of the License at
56 +
57 + http://www.apache.org/licenses/LICENSE-2.0
58 +
59 +Unless required by applicable law or agreed to in writing, software
60 +distributed under the License is distributed on an "AS IS" BASIS,
61 +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
62 +See the License for the specific language governing permissions and
63 +limitations under the License.
64 +```
......
...@@ -5,9 +5,11 @@ export default class Client { ...@@ -5,9 +5,11 @@ export default class Client {
5 config: Types.ClientConfig; 5 config: Types.ClientConfig;
6 private http; 6 private http;
7 constructor(config: Types.ClientConfig); 7 constructor(config: Types.ClientConfig);
8 - pushMessage(to: string, messages: Types.Message | Types.Message[]): Promise<any>; 8 + private parseHTTPResponse;
9 - replyMessage(replyToken: string, messages: Types.Message | Types.Message[]): Promise<any>; 9 + pushMessage(to: string, messages: Types.Message | Types.Message[], notificationDisabled?: boolean): Promise<Types.MessageAPIResponseBase>;
10 - multicast(to: string[], messages: Types.Message | Types.Message[]): Promise<any>; 10 + replyMessage(replyToken: string, messages: Types.Message | Types.Message[], notificationDisabled?: boolean): Promise<Types.MessageAPIResponseBase>;
11 + multicast(to: string[], messages: Types.Message | Types.Message[], notificationDisabled?: boolean): Promise<Types.MessageAPIResponseBase>;
12 + broadcast(messages: Types.Message | Types.Message[], notificationDisabled?: boolean): Promise<Types.MessageAPIResponseBase>;
11 getProfile(userId: string): Promise<Types.Profile>; 13 getProfile(userId: string): Promise<Types.Profile>;
12 private getChatMemberProfile; 14 private getChatMemberProfile;
13 getGroupMemberProfile(groupId: string, userId: string): Promise<Types.Profile>; 15 getGroupMemberProfile(groupId: string, userId: string): Promise<Types.Profile>;
...@@ -25,6 +27,8 @@ export default class Client { ...@@ -25,6 +27,8 @@ export default class Client {
25 getRichMenuIdOfUser(userId: string): Promise<string>; 27 getRichMenuIdOfUser(userId: string): Promise<string>;
26 linkRichMenuToUser(userId: string, richMenuId: string): Promise<any>; 28 linkRichMenuToUser(userId: string, richMenuId: string): Promise<any>;
27 unlinkRichMenuFromUser(userId: string): Promise<any>; 29 unlinkRichMenuFromUser(userId: string): Promise<any>;
30 + linkRichMenuToMultipleUsers(richMenuId: string, userIds: string[]): Promise<any>;
31 + unlinkRichMenusFromMultipleUsers(userIds: string[]): Promise<any>;
28 getRichMenuImage(richMenuId: string): Promise<Readable>; 32 getRichMenuImage(richMenuId: string): Promise<Readable>;
29 setRichMenuImage(richMenuId: string, data: Buffer | Readable, contentType?: string): Promise<any>; 33 setRichMenuImage(richMenuId: string, data: Buffer | Readable, contentType?: string): Promise<any>;
30 getRichMenuList(): Promise<Array<Types.RichMenuResponse>>; 34 getRichMenuList(): Promise<Array<Types.RichMenuResponse>>;
...@@ -32,4 +36,23 @@ export default class Client { ...@@ -32,4 +36,23 @@ export default class Client {
32 getDefaultRichMenuId(): Promise<string>; 36 getDefaultRichMenuId(): Promise<string>;
33 deleteDefaultRichMenu(): Promise<{}>; 37 deleteDefaultRichMenu(): Promise<{}>;
34 getLinkToken(userId: string): Promise<string>; 38 getLinkToken(userId: string): Promise<string>;
39 + getNumberOfSentReplyMessages(date: string): Promise<Types.NumberOfMessagesSentResponse>;
40 + getNumberOfSentPushMessages(date: string): Promise<Types.NumberOfMessagesSentResponse>;
41 + getNumberOfSentMulticastMessages(date: string): Promise<Types.NumberOfMessagesSentResponse>;
42 + getTargetLimitForAdditionalMessages(): Promise<Types.TargetLimitForAdditionalMessages>;
43 + getNumberOfMessagesSentThisMonth(): Promise<Types.NumberOfMessagesSentThisMonth>;
44 + getNumberOfSentBroadcastMessages(date: string): Promise<Types.NumberOfMessagesSentResponse>;
45 + getNumberOfMessageDeliveries(date: string): Promise<Types.NumberOfMessageDeliveriesResponse>;
46 + getNumberOfFollowers(date: string): Promise<Types.NumberOfFollowersResponse>;
47 + getFriendDemographics(): Promise<Types.FriendDemoGraphics>;
48 +}
49 +export declare class OAuth {
50 + private http;
51 + constructor();
52 + issueAccessToken(client_id: string, client_secret: string): Promise<{
53 + access_token: string;
54 + expires_in: number;
55 + token_type: "Bearer";
56 + }>;
57 + revokeAccessToken(access_token: string): Promise<{}>;
35 } 58 }
......
This diff is collapsed. Click to expand it.
1 /// <reference types="node" /> 1 /// <reference types="node" />
2 +import { AxiosResponse } from "axios";
2 import { Readable } from "stream"; 3 import { Readable } from "stream";
4 +declare type httpClientConfig = {
5 + baseURL?: string;
6 + defaultHeaders?: any;
7 + responseParser?: <T>(res: AxiosResponse) => T;
8 +};
3 export default class HTTPClient { 9 export default class HTTPClient {
4 private instance; 10 private instance;
5 - constructor(baseURL?: string, defaultHeaders?: any); 11 + private config;
12 + constructor(config?: httpClientConfig);
6 get<T>(url: string, params?: any): Promise<T>; 13 get<T>(url: string, params?: any): Promise<T>;
7 getStream(url: string, params?: any): Promise<Readable>; 14 getStream(url: string, params?: any): Promise<Readable>;
8 - post<T>(url: string, data?: any): Promise<T>; 15 + post<T>(url: string, body?: any): Promise<T>;
16 + postForm<T>(url: string, body?: any): Promise<T>;
9 postBinary<T>(url: string, data: Buffer | Readable, contentType?: string): Promise<T>; 17 postBinary<T>(url: string, data: Buffer | Readable, contentType?: string): Promise<T>;
10 delete<T>(url: string, params?: any): Promise<T>; 18 delete<T>(url: string, params?: any): Promise<T>;
11 private wrapError; 19 private wrapError;
12 } 20 }
21 +export {};
......
...@@ -4,9 +4,12 @@ const axios_1 = require("axios"); ...@@ -4,9 +4,12 @@ const axios_1 = require("axios");
4 const stream_1 = require("stream"); 4 const stream_1 = require("stream");
5 const exceptions_1 = require("./exceptions"); 5 const exceptions_1 = require("./exceptions");
6 const fileType = require("file-type"); 6 const fileType = require("file-type");
7 +const qs = require("querystring");
7 const pkg = require("../package.json"); 8 const pkg = require("../package.json");
8 class HTTPClient { 9 class HTTPClient {
9 - constructor(baseURL, defaultHeaders) { 10 + constructor(config = {}) {
11 + this.config = config;
12 + const { baseURL, defaultHeaders } = config;
10 this.instance = axios_1.default.create({ 13 this.instance = axios_1.default.create({
11 baseURL, 14 baseURL,
12 headers: Object.assign({}, defaultHeaders, { 15 headers: Object.assign({}, defaultHeaders, {
...@@ -15,27 +18,40 @@ class HTTPClient { ...@@ -15,27 +18,40 @@ class HTTPClient {
15 }); 18 });
16 this.instance.interceptors.response.use(res => res, err => Promise.reject(this.wrapError(err))); 19 this.instance.interceptors.response.use(res => res, err => Promise.reject(this.wrapError(err)));
17 } 20 }
18 - get(url, params) { 21 + async get(url, params) {
19 - return this.instance.get(url, { params }).then(res => res.data); 22 + const res = await this.instance.get(url, { params });
23 + return res.data;
20 } 24 }
21 - getStream(url, params) { 25 + async getStream(url, params) {
22 - return this.instance 26 + const res = await this.instance.get(url, {
23 - .get(url, { params, responseType: "stream" }) 27 + params,
24 - .then(res => res.data); 28 + responseType: "stream",
29 + });
30 + return res.data;
25 } 31 }
26 - post(url, data) { 32 + async post(url, body) {
27 - return this.instance 33 + const res = await this.instance.post(url, body, {
28 - .post(url, data, { headers: { "Content-Type": "application/json" } }) 34 + headers: { "Content-Type": "application/json" },
29 - .then(res => res.data); 35 + });
36 + const { responseParser } = this.config;
37 + if (responseParser)
38 + return responseParser(res);
39 + else
40 + return res.data;
30 } 41 }
31 - postBinary(url, data, contentType) { 42 + async postForm(url, body) {
32 - let getBuffer; 43 + const res = await this.instance.post(url, qs.stringify(body), {
33 - if (Buffer.isBuffer(data)) { 44 + headers: { "Content-Type": "application/x-www-form-urlencoded" },
34 - getBuffer = Promise.resolve(data); 45 + });
35 - } 46 + return res.data;
36 - else { 47 + }
37 - getBuffer = new Promise((resolve, reject) => { 48 + async postBinary(url, data, contentType) {
38 - if (data instanceof stream_1.Readable) { 49 + const buffer = await (async () => {
50 + if (Buffer.isBuffer(data)) {
51 + return data;
52 + }
53 + else if (data instanceof stream_1.Readable) {
54 + return new Promise((resolve, reject) => {
39 const buffers = []; 55 const buffers = [];
40 let size = 0; 56 let size = 0;
41 data.on("data", (chunk) => { 57 data.on("data", (chunk) => {
...@@ -44,25 +60,23 @@ class HTTPClient { ...@@ -44,25 +60,23 @@ class HTTPClient {
44 }); 60 });
45 data.on("end", () => resolve(Buffer.concat(buffers, size))); 61 data.on("end", () => resolve(Buffer.concat(buffers, size)));
46 data.on("error", reject); 62 data.on("error", reject);
47 - } 63 + });
48 - else { 64 + }
49 - reject(new Error("invalid data type for postBinary")); 65 + else {
50 - } 66 + throw new Error("invalid data type for postBinary");
51 - }); 67 + }
52 - } 68 + })();
53 - return getBuffer.then(data => { 69 + const res = await this.instance.post(url, buffer, {
54 - return this.instance 70 + headers: {
55 - .post(url, data, { 71 + "Content-Type": contentType || fileType(buffer).mime,
56 - headers: { 72 + "Content-Length": buffer.length,
57 - "Content-Type": contentType || fileType(data).mime, 73 + },
58 - "Content-Length": data.length,
59 - },
60 - })
61 - .then(res => res.data);
62 }); 74 });
75 + return res.data;
63 } 76 }
64 - delete(url, params) { 77 + async delete(url, params) {
65 - return this.instance.delete(url, { params }).then(res => res.data); 78 + const res = await this.instance.delete(url, { params });
79 + return res.data;
66 } 80 }
67 wrapError(err) { 81 wrapError(err) {
68 if (err.response) { 82 if (err.response) {
......
1 -import Client from "./client"; 1 +import Client, { OAuth } from "./client";
2 import middleware from "./middleware"; 2 import middleware from "./middleware";
3 import validateSignature from "./validate-signature"; 3 import validateSignature from "./validate-signature";
4 -export { Client, middleware, validateSignature }; 4 +export { Client, middleware, validateSignature, OAuth };
5 export * from "./exceptions"; 5 export * from "./exceptions";
6 export * from "./types"; 6 export * from "./types";
......
...@@ -5,9 +5,11 @@ function __export(m) { ...@@ -5,9 +5,11 @@ function __export(m) {
5 Object.defineProperty(exports, "__esModule", { value: true }); 5 Object.defineProperty(exports, "__esModule", { value: true });
6 const client_1 = require("./client"); 6 const client_1 = require("./client");
7 exports.Client = client_1.default; 7 exports.Client = client_1.default;
8 +exports.OAuth = client_1.OAuth;
8 const middleware_1 = require("./middleware"); 9 const middleware_1 = require("./middleware");
9 exports.middleware = middleware_1.default; 10 exports.middleware = middleware_1.default;
10 const validate_signature_1 = require("./validate-signature"); 11 const validate_signature_1 = require("./validate-signature");
11 exports.validateSignature = validate_signature_1.default; 12 exports.validateSignature = validate_signature_1.default;
12 // re-export exceptions and types 13 // re-export exceptions and types
13 __export(require("./exceptions")); 14 __export(require("./exceptions"));
15 +__export(require("./types"));
......
...@@ -6,5 +6,5 @@ export declare type Request = http.IncomingMessage & { ...@@ -6,5 +6,5 @@ export declare type Request = http.IncomingMessage & {
6 }; 6 };
7 export declare type Response = http.ServerResponse; 7 export declare type Response = http.ServerResponse;
8 export declare type NextCallback = (err?: Error) => void; 8 export declare type NextCallback = (err?: Error) => void;
9 -export declare type Middleware = (req: Request, res: Response, next: NextCallback) => void; 9 +export declare type Middleware = (req: Request, res: Response, next: NextCallback) => void | Promise<void>;
10 export default function middleware(config: Types.MiddlewareConfig): Middleware; 10 export default function middleware(config: Types.MiddlewareConfig): Middleware;
......
...@@ -11,7 +11,7 @@ function middleware(config) { ...@@ -11,7 +11,7 @@ function middleware(config) {
11 throw new Error("no channel secret"); 11 throw new Error("no channel secret");
12 } 12 }
13 const secret = config.channelSecret; 13 const secret = config.channelSecret;
14 - return (req, res, next) => { 14 + const _middleware = async (req, res, next) => {
15 // header names are lower-cased 15 // header names are lower-cased
16 // https://nodejs.org/api/http.html#http_message_headers 16 // https://nodejs.org/api/http.html#http_message_headers
17 const signature = req.headers["x-line-signature"]; 17 const signature = req.headers["x-line-signature"];
...@@ -19,34 +19,34 @@ function middleware(config) { ...@@ -19,34 +19,34 @@ function middleware(config) {
19 next(new exceptions_1.SignatureValidationFailed("no signature")); 19 next(new exceptions_1.SignatureValidationFailed("no signature"));
20 return; 20 return;
21 } 21 }
22 - let getBody; 22 + const body = await (async () => {
23 - if (isValidBody(req.rawBody)) { 23 + if (isValidBody(req.rawBody)) {
24 - // rawBody is provided in Google Cloud Functions and others 24 + // rawBody is provided in Google Cloud Functions and others
25 - getBody = Promise.resolve(req.rawBody); 25 + return req.rawBody;
26 - }
27 - else if (isValidBody(req.body)) {
28 - getBody = Promise.resolve(req.body);
29 - }
30 - else {
31 - // body may not be parsed yet, parse it to a buffer
32 - getBody = new Promise(resolve => {
33 - body_parser_1.raw({ type: "*/*" })(req, res, () => resolve(req.body));
34 - });
35 - }
36 - getBody.then(body => {
37 - if (!validate_signature_1.default(body, secret, signature)) {
38 - next(new exceptions_1.SignatureValidationFailed("signature validation failed", signature));
39 - return;
40 } 26 }
41 - const strBody = Buffer.isBuffer(body) ? body.toString() : body; 27 + else if (isValidBody(req.body)) {
42 - try { 28 + return req.body;
43 - req.body = JSON.parse(strBody);
44 - next();
45 } 29 }
46 - catch (err) { 30 + else {
47 - next(new exceptions_1.JSONParseError(err.message, strBody)); 31 + // body may not be parsed yet, parse it to a buffer
32 + return new Promise((resolve, reject) => body_parser_1.raw({ type: "*/*" })(req, res, (error) => error ? reject(error) : resolve(req.body)));
48 } 33 }
49 - }); 34 + })();
35 + if (!validate_signature_1.default(body, secret, signature)) {
36 + next(new exceptions_1.SignatureValidationFailed("signature validation failed", signature));
37 + return;
38 + }
39 + const strBody = Buffer.isBuffer(body) ? body.toString() : body;
40 + try {
41 + req.body = JSON.parse(strBody);
42 + next();
43 + }
44 + catch (err) {
45 + next(new exceptions_1.JSONParseError(err.message, strBody));
46 + }
47 + };
48 + return (req, res, next) => {
49 + _middleware(req, res, next).catch(next);
50 }; 50 };
51 } 51 }
52 exports.default = middleware; 52 exports.default = middleware;
......
This diff is collapsed. Click to expand it.
1 "use strict"; 1 "use strict";
2 Object.defineProperty(exports, "__esModule", { value: true }); 2 Object.defineProperty(exports, "__esModule", { value: true });
3 +exports.LINE_REQUEST_ID_HTTP_HEADER_NAME = "x-line-request-id";
......
...@@ -2,35 +2,13 @@ ...@@ -2,35 +2,13 @@
2 Object.defineProperty(exports, "__esModule", { value: true }); 2 Object.defineProperty(exports, "__esModule", { value: true });
3 const crypto_1 = require("crypto"); 3 const crypto_1 = require("crypto");
4 function s2b(str, encoding) { 4 function s2b(str, encoding) {
5 - if (Buffer.from) { 5 + return Buffer.from(str, encoding);
6 - try {
7 - return Buffer.from(str, encoding);
8 - }
9 - catch (err) {
10 - if (err.name === "TypeError") {
11 - return new Buffer(str, encoding);
12 - }
13 - throw err;
14 - }
15 - }
16 - else {
17 - return new Buffer(str, encoding);
18 - }
19 } 6 }
20 function safeCompare(a, b) { 7 function safeCompare(a, b) {
21 if (a.length !== b.length) { 8 if (a.length !== b.length) {
22 return false; 9 return false;
23 } 10 }
24 - if (crypto_1.timingSafeEqual) { 11 + return crypto_1.timingSafeEqual(a, b);
25 - return crypto_1.timingSafeEqual(a, b);
26 - }
27 - else {
28 - let result = 0;
29 - for (let i = 0; i < a.length; i++) {
30 - result |= a[i] ^ b[i];
31 - }
32 - return result === 0;
33 - }
34 } 12 }
35 function validateSignature(body, channelSecret, signature) { 13 function validateSignature(body, channelSecret, signature) {
36 return safeCompare(crypto_1.createHmac("SHA256", channelSecret) 14 return safeCompare(crypto_1.createHmac("SHA256", channelSecret)
......
This diff is collapsed. Click to expand it.
1 -import axios, { AxiosInstance, AxiosError } from "axios"; 1 +import axios, { AxiosInstance, AxiosError, AxiosResponse } from "axios";
2 import { Readable } from "stream"; 2 import { Readable } from "stream";
3 import { HTTPError, ReadError, RequestError } from "./exceptions"; 3 import { HTTPError, ReadError, RequestError } from "./exceptions";
4 import * as fileType from "file-type"; 4 import * as fileType from "file-type";
5 +import * as qs from "querystring";
5 6
6 const pkg = require("../package.json"); 7 const pkg = require("../package.json");
7 8
9 +type httpClientConfig = {
10 + baseURL?: string;
11 + defaultHeaders?: any;
12 + responseParser?: <T>(res: AxiosResponse) => T;
13 +};
14 +
8 export default class HTTPClient { 15 export default class HTTPClient {
9 private instance: AxiosInstance; 16 private instance: AxiosInstance;
17 + private config: httpClientConfig;
10 18
11 - constructor(baseURL?: string, defaultHeaders?: any) { 19 + constructor(config: httpClientConfig = {}) {
20 + this.config = config;
21 + const { baseURL, defaultHeaders } = config;
12 this.instance = axios.create({ 22 this.instance = axios.create({
13 baseURL, 23 baseURL,
14 headers: Object.assign({}, defaultHeaders, { 24 headers: Object.assign({}, defaultHeaders, {
...@@ -22,34 +32,47 @@ export default class HTTPClient { ...@@ -22,34 +32,47 @@ export default class HTTPClient {
22 ); 32 );
23 } 33 }
24 34
25 - public get<T>(url: string, params?: any): Promise<T> { 35 + public async get<T>(url: string, params?: any): Promise<T> {
26 - return this.instance.get(url, { params }).then(res => res.data); 36 + const res = await this.instance.get(url, { params });
37 + return res.data;
27 } 38 }
28 39
29 - public getStream(url: string, params?: any): Promise<Readable> { 40 + public async getStream(url: string, params?: any): Promise<Readable> {
30 - return this.instance 41 + const res = await this.instance.get(url, {
31 - .get(url, { params, responseType: "stream" }) 42 + params,
32 - .then(res => res.data as Readable); 43 + responseType: "stream",
44 + });
45 + return res.data as Readable;
33 } 46 }
34 47
35 - public post<T>(url: string, data?: any): Promise<T> { 48 + public async post<T>(url: string, body?: any): Promise<T> {
36 - return this.instance 49 + const res = await this.instance.post(url, body, {
37 - .post(url, data, { headers: { "Content-Type": "application/json" } }) 50 + headers: { "Content-Type": "application/json" },
38 - .then(res => res.data); 51 + });
52 +
53 + const { responseParser } = this.config;
54 + if (responseParser) return responseParser<T>(res);
55 + else return res.data;
39 } 56 }
40 57
41 - public postBinary<T>( 58 + public async postForm<T>(url: string, body?: any): Promise<T> {
59 + const res = await this.instance.post(url, qs.stringify(body), {
60 + headers: { "Content-Type": "application/x-www-form-urlencoded" },
61 + });
62 +
63 + return res.data;
64 + }
65 +
66 + public async postBinary<T>(
42 url: string, 67 url: string,
43 data: Buffer | Readable, 68 data: Buffer | Readable,
44 contentType?: string, 69 contentType?: string,
45 ): Promise<T> { 70 ): Promise<T> {
46 - let getBuffer: Promise<Buffer>; 71 + const buffer = await (async (): Promise<Buffer> => {
47 - 72 + if (Buffer.isBuffer(data)) {
48 - if (Buffer.isBuffer(data)) { 73 + return data;
49 - getBuffer = Promise.resolve(data); 74 + } else if (data instanceof Readable) {
50 - } else { 75 + return new Promise<Buffer>((resolve, reject) => {
51 - getBuffer = new Promise((resolve, reject) => {
52 - if (data instanceof Readable) {
53 const buffers: Buffer[] = []; 76 const buffers: Buffer[] = [];
54 let size = 0; 77 let size = 0;
55 data.on("data", (chunk: Buffer) => { 78 data.on("data", (chunk: Buffer) => {
...@@ -58,26 +81,25 @@ export default class HTTPClient { ...@@ -58,26 +81,25 @@ export default class HTTPClient {
58 }); 81 });
59 data.on("end", () => resolve(Buffer.concat(buffers, size))); 82 data.on("end", () => resolve(Buffer.concat(buffers, size)));
60 data.on("error", reject); 83 data.on("error", reject);
61 - } else { 84 + });
62 - reject(new Error("invalid data type for postBinary")); 85 + } else {
63 - } 86 + throw new Error("invalid data type for postBinary");
64 - }); 87 + }
65 - } 88 + })();
66 89
67 - return getBuffer.then(data => { 90 + const res = await this.instance.post(url, buffer, {
68 - return this.instance 91 + headers: {
69 - .post(url, data, { 92 + "Content-Type": contentType || fileType(buffer).mime,
70 - headers: { 93 + "Content-Length": buffer.length,
71 - "Content-Type": contentType || fileType(data).mime, 94 + },
72 - "Content-Length": data.length,
73 - },
74 - })
75 - .then(res => res.data);
76 }); 95 });
96 +
97 + return res.data;
77 } 98 }
78 99
79 - public delete<T>(url: string, params?: any): Promise<T> { 100 + public async delete<T>(url: string, params?: any): Promise<T> {
80 - return this.instance.delete(url, { params }).then(res => res.data); 101 + const res = await this.instance.delete(url, { params });
102 + return res.data;
81 } 103 }
82 104
83 private wrapError(err: AxiosError): Error { 105 private wrapError(err: AxiosError): Error {
......
1 -import Client from "./client"; 1 +import Client, { OAuth } from "./client";
2 import middleware from "./middleware"; 2 import middleware from "./middleware";
3 import validateSignature from "./validate-signature"; 3 import validateSignature from "./validate-signature";
4 4
5 -export { Client, middleware, validateSignature }; 5 +export { Client, middleware, validateSignature, OAuth };
6 6
7 // re-export exceptions and types 7 // re-export exceptions and types
8 export * from "./exceptions"; 8 export * from "./exceptions";
......
...@@ -12,7 +12,7 @@ export type Middleware = ( ...@@ -12,7 +12,7 @@ export type Middleware = (
12 req: Request, 12 req: Request,
13 res: Response, 13 res: Response,
14 next: NextCallback, 14 next: NextCallback,
15 -) => void; 15 +) => void | Promise<void>;
16 16
17 function isValidBody(body?: any): body is string | Buffer { 17 function isValidBody(body?: any): body is string | Buffer {
18 return (body && typeof body === "string") || Buffer.isBuffer(body); 18 return (body && typeof body === "string") || Buffer.isBuffer(body);
...@@ -25,7 +25,7 @@ export default function middleware(config: Types.MiddlewareConfig): Middleware { ...@@ -25,7 +25,7 @@ export default function middleware(config: Types.MiddlewareConfig): Middleware {
25 25
26 const secret = config.channelSecret; 26 const secret = config.channelSecret;
27 27
28 - return (req, res, next) => { 28 + const _middleware: Middleware = async (req, res, next) => {
29 // header names are lower-cased 29 // header names are lower-cased
30 // https://nodejs.org/api/http.html#http_message_headers 30 // https://nodejs.org/api/http.html#http_message_headers
31 const signature = req.headers["x-line-signature"] as string; 31 const signature = req.headers["x-line-signature"] as string;
...@@ -35,38 +35,39 @@ export default function middleware(config: Types.MiddlewareConfig): Middleware { ...@@ -35,38 +35,39 @@ export default function middleware(config: Types.MiddlewareConfig): Middleware {
35 return; 35 return;
36 } 36 }
37 37
38 - let getBody: Promise<string | Buffer>; 38 + const body = await (async (): Promise<string | Buffer> => {
39 - if (isValidBody((req as any).rawBody)) { 39 + if (isValidBody((req as any).rawBody)) {
40 - // rawBody is provided in Google Cloud Functions and others 40 + // rawBody is provided in Google Cloud Functions and others
41 - getBody = Promise.resolve((req as any).rawBody); 41 + return (req as any).rawBody;
42 - } else if (isValidBody(req.body)) { 42 + } else if (isValidBody(req.body)) {
43 - getBody = Promise.resolve(req.body); 43 + return req.body;
44 - } else { 44 + } else {
45 - // body may not be parsed yet, parse it to a buffer 45 + // body may not be parsed yet, parse it to a buffer
46 - getBody = new Promise(resolve => { 46 + return new Promise<Buffer>((resolve, reject) =>
47 - raw({ type: "*/*" })(req as any, res as any, () => resolve(req.body)); 47 + raw({ type: "*/*" })(req as any, res as any, (error: Error) =>
48 - }); 48 + error ? reject(error) : resolve(req.body),
49 - }
50 -
51 - getBody.then(body => {
52 - if (!validateSignature(body, secret, signature)) {
53 - next(
54 - new SignatureValidationFailed(
55 - "signature validation failed",
56 - signature,
57 ), 49 ),
58 ); 50 );
59 - return;
60 } 51 }
52 + })();
53 +
54 + if (!validateSignature(body, secret, signature)) {
55 + next(
56 + new SignatureValidationFailed("signature validation failed", signature),
57 + );
58 + return;
59 + }
61 60
62 - const strBody = Buffer.isBuffer(body) ? body.toString() : body; 61 + const strBody = Buffer.isBuffer(body) ? body.toString() : body;
63 62
64 - try { 63 + try {
65 - req.body = JSON.parse(strBody); 64 + req.body = JSON.parse(strBody);
66 - next(); 65 + next();
67 - } catch (err) { 66 + } catch (err) {
68 - next(new JSONParseError(err.message, strBody)); 67 + next(new JSONParseError(err.message, strBody));
69 - } 68 + }
70 - }); 69 + };
70 + return (req, res, next): void => {
71 + (<Promise<void>>_middleware(req, res, next)).catch(next);
71 }; 72 };
72 } 73 }
......
This diff is collapsed. Click to expand it.
1 import { createHmac, timingSafeEqual } from "crypto"; 1 import { createHmac, timingSafeEqual } from "crypto";
2 2
3 function s2b(str: string, encoding: string): Buffer { 3 function s2b(str: string, encoding: string): Buffer {
4 - if (Buffer.from) { 4 + return Buffer.from(str, encoding);
5 - try {
6 - return Buffer.from(str, encoding);
7 - } catch (err) {
8 - if (err.name === "TypeError") {
9 - return new Buffer(str, encoding);
10 - }
11 - throw err;
12 - }
13 - } else {
14 - return new Buffer(str, encoding);
15 - }
16 } 5 }
17 6
18 function safeCompare(a: Buffer, b: Buffer): boolean { 7 function safeCompare(a: Buffer, b: Buffer): boolean {
19 if (a.length !== b.length) { 8 if (a.length !== b.length) {
20 return false; 9 return false;
21 } 10 }
22 - 11 + return timingSafeEqual(a, b);
23 - if (timingSafeEqual) {
24 - return timingSafeEqual(a, b);
25 - } else {
26 - let result = 0;
27 - for (let i = 0; i < a.length; i++) {
28 - result |= a[i] ^ b[i];
29 - }
30 - return result === 0;
31 - }
32 } 12 }
33 13
34 export default function validateSignature( 14 export default function validateSignature(
......
1 { 1 {
2 - "_from": "@line/bot-sdk", 2 + "_from": "@line/bot-sdk@^6.4.0",
3 - "_id": "@line/bot-sdk@6.4.0", 3 + "_id": "@line/bot-sdk@6.8.3",
4 "_inBundle": false, 4 "_inBundle": false,
5 - "_integrity": "sha512-N0FkrqFxTTleOpD6y7DTK8qbMYHr9Q8qZfrAmSYEFAGedM1HLJdbNNkStj5GT+svx+w+/ePF/n7nAEts0aJwkA==", 5 + "_integrity": "sha512-nj2T4CQxw0W/juAlpj0kMTDScOh5QUK6xMCR2dZp+pN8B0vj/c+5uX3TyGB4ijz/NIsehgfKujPgzw7LhtYtJw==",
6 "_location": "/@line/bot-sdk", 6 "_location": "/@line/bot-sdk",
7 "_phantomChildren": {}, 7 "_phantomChildren": {},
8 "_requested": { 8 "_requested": {
9 - "type": "tag", 9 + "type": "range",
10 "registry": true, 10 "registry": true,
11 - "raw": "@line/bot-sdk", 11 + "raw": "@line/bot-sdk@^6.4.0",
12 "name": "@line/bot-sdk", 12 "name": "@line/bot-sdk",
13 "escapedName": "@line%2fbot-sdk", 13 "escapedName": "@line%2fbot-sdk",
14 "scope": "@line", 14 "scope": "@line",
15 - "rawSpec": "", 15 + "rawSpec": "^6.4.0",
16 "saveSpec": null, 16 "saveSpec": null,
17 - "fetchSpec": "latest" 17 + "fetchSpec": "^6.4.0"
18 }, 18 },
19 "_requiredBy": [ 19 "_requiredBy": [
20 "#USER", 20 "#USER",
21 "/" 21 "/"
22 ], 22 ],
23 - "_resolved": "https://registry.npmjs.org/@line/bot-sdk/-/bot-sdk-6.4.0.tgz", 23 + "_resolved": "https://registry.npmjs.org/@line/bot-sdk/-/bot-sdk-6.8.3.tgz",
24 - "_shasum": "18aa7659da26d3a8487614c74ad9ccb80ec4ca59", 24 + "_shasum": "0a886461e8c16a8c89091fd5338f6071335636a6",
25 - "_spec": "@line/bot-sdk", 25 + "_spec": "@line/bot-sdk@^6.4.0",
26 - "_where": "C:\\Users\\KSI\\Desktop\\3-2\\OSS\\LineBot", 26 + "_where": "C:\\Users\\USER\\Documents\\Desktop\\옵소팀플\\LINEBOT",
27 "bugs": { 27 "bugs": {
28 "url": "https://github.com/line/line-bot-sdk-nodejs/issues" 28 "url": "https://github.com/line/line-bot-sdk-nodejs/issues"
29 }, 29 },
...@@ -32,7 +32,7 @@ ...@@ -32,7 +32,7 @@
32 "@types/body-parser": "^1.16.8", 32 "@types/body-parser": "^1.16.8",
33 "@types/file-type": "^5.2.1", 33 "@types/file-type": "^5.2.1",
34 "@types/node": "^7.0.31", 34 "@types/node": "^7.0.31",
35 - "axios": "^0.16.2", 35 + "axios": "^0.19.0",
36 "body-parser": "^1.18.2", 36 "body-parser": "^1.18.2",
37 "file-type": "^7.2.0" 37 "file-type": "^7.2.0"
38 }, 38 },
...@@ -40,19 +40,21 @@ ...@@ -40,19 +40,21 @@
40 "description": "Node.js SDK for LINE Messaging API", 40 "description": "Node.js SDK for LINE Messaging API",
41 "devDependencies": { 41 "devDependencies": {
42 "@types/express": "^4.0.35", 42 "@types/express": "^4.0.35",
43 + "@types/finalhandler": "^1.1.0",
43 "@types/mocha": "^2.2.41", 44 "@types/mocha": "^2.2.41",
44 "del-cli": "^1.1.0", 45 "del-cli": "^1.1.0",
45 "express": "^4.16.3", 46 "express": "^4.16.3",
47 + "finalhandler": "^1.1.2",
46 "husky": "^0.14.3", 48 "husky": "^0.14.3",
47 "mocha": "^5.2.0", 49 "mocha": "^5.2.0",
48 - "nyc": "^12.0.2", 50 + "nyc": "^14.1.1",
49 "prettier": "^1.15.2", 51 "prettier": "^1.15.2",
50 - "ts-node": "^3.3.0", 52 + "ts-node": "^8.3.0",
51 "typescript": "^3.1.6", 53 "typescript": "^3.1.6",
52 - "vuepress": "^0.14.2" 54 + "vuepress": "^0.14.10"
53 }, 55 },
54 "engines": { 56 "engines": {
55 - "node": ">=6" 57 + "node": ">=8"
56 }, 58 },
57 "files": [ 59 "files": [
58 "dist", 60 "dist",
...@@ -102,5 +104,5 @@ ...@@ -102,5 +104,5 @@
102 "test": "API_BASE_URL=http://localhost:1234/ TEST_PORT=1234 TS_NODE_CACHE=0 nyc mocha" 104 "test": "API_BASE_URL=http://localhost:1234/ TEST_PORT=1234 TS_NODE_CACHE=0 nyc mocha"
103 }, 105 },
104 "types": "dist/index.d.ts", 106 "types": "dist/index.d.ts",
105 - "version": "6.4.0" 107 + "version": "6.8.3"
106 } 108 }
......
1 +# Changelog
2 +
3 +- v3 (Oct 2019)
4 + - Add POST-as-GET for Let's Encrypt v2 release 2 (ACME / RFC 8555)
5 + - Jump to v3 for parity with Greenlock
6 + - Merge browser and node.js versions in one
7 + - Drop all backwards-compat complexity
8 + - Move to zero-external deps, using @root packages only
9 +- v1.8
10 + - more transitional prepwork for new v2 API
11 + - support newer (simpler) dns-01 and http-01 libraries
12 +- v1.5
13 + - perform full test challenge first (even before nonce)
14 +- v1.3
15 + - Use node RSA keygen by default
16 + - No non-optional external deps!
17 +- v1.2
18 + - fix some API out-of-specness
19 + - doc some magic numbers (status)
20 + - updated deps
21 +- v1.1.0
22 + - reduce dependencies (use lightweight @coolaj86/request instead of request)
23 +- v1.0.5 - cleanup logging
24 +- v1.0.4 - v6- compat use `promisify` from node's util or bluebird
25 +- v1.0.3 - documentation cleanup
26 +- v1.0.2
27 + - use `options.contact` to provide raw contact array
28 + - made `options.email` optional
29 + - file cleanup
30 +- v1.0.1
31 + - Compat API is ready for use
32 + - Eliminate debug logging
33 +- Apr 10, 2018 - tested backwards-compatibility using greenlock.js
34 +- Apr 5, 2018 - export http and dns challenge tests
35 +- Apr 5, 2018 - test http and dns challenges (success and failure)
36 +- Apr 5, 2018 - test subdomains and its wildcard
37 +- Apr 5, 2018 - test two subdomains
38 +- Apr 5, 2018 - test wildcard
39 +- Apr 5, 2018 - completely match api for acme v1 (le-acme-core.js)
40 +- Mar 21, 2018 - _mostly_ matches le-acme-core.js API
41 +- Mar 21, 2018 - can now accept values (not hard coded)
42 +- Mar 20, 2018 - SUCCESS - got a test certificate (hard-coded)
43 +- Mar 20, 2018 - download certificate
44 +- Mar 20, 2018 - poll for status
45 +- Mar 20, 2018 - finalize order (submit csr)
46 +- Mar 20, 2018 - generate domain keypair
47 +- Mar 20, 2018 - respond to challenges
48 +- Mar 16, 2018 - get challenges
49 +- Mar 16, 2018 - new order
50 +- Mar 15, 2018 - create account
51 +- Mar 15, 2018 - generate account keypair
52 +- Mar 15, 2018 - get nonce
53 +- Mar 15, 2018 - get directory
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
1 +'use strict';
2 +
3 +var A = module.exports;
4 +var U = require('./utils.js');
5 +
6 +var Keypairs = require('@root/keypairs');
7 +var Enc = require('@root/encoding/bytes');
8 +var agreers = {};
9 +
10 +A._getAccountKid = function(me, options) {
11 + // It's just fine if there's no account, we'll go get the key id we need via the existing key
12 + var kid =
13 + options.kid ||
14 + (options.account && (options.account.key && options.account.key.kid));
15 +
16 + if (kid) {
17 + return Promise.resolve(kid);
18 + }
19 +
20 + //return Promise.reject(new Error("must include KeyID"));
21 + // This is an idempotent request. It'll return the same account for the same public key.
22 + return A._registerAccount(me, options).then(function(account) {
23 + return account.key.kid;
24 + });
25 +};
26 +
27 +// ACME RFC Section 7.3 Account Creation
28 +/*
29 + {
30 + "protected": base64url({
31 + "alg": "ES256",
32 + "jwk": {...},
33 + "nonce": "6S8IqOGY7eL2lsGoTZYifg",
34 + "url": "https://example.com/acme/new-account"
35 + }),
36 + "payload": base64url({
37 + "termsOfServiceAgreed": true,
38 + "onlyReturnExisting": false,
39 + "contact": [
40 + "mailto:cert-admin@example.com",
41 + "mailto:admin@example.com"
42 + ]
43 + }),
44 + "signature": "RZPOnYoPs1PhjszF...-nh6X1qtOFPB519I"
45 + }
46 +*/
47 +A._registerAccount = function(me, options) {
48 + //#console.debug('[ACME.js] accounts.create');
49 +
50 + function agree(agreed) {
51 + var err;
52 + if (!agreed) {
53 + err = new Error("must agree to '" + me._tos + "'");
54 + err.code = 'E_AGREE_TOS';
55 + throw err;
56 + }
57 + return true;
58 + }
59 +
60 + function getAccount() {
61 + return U._importKeypair(options.accountKey).then(function(pair) {
62 + var contact;
63 + if (options.contact) {
64 + contact = options.contact.slice(0);
65 + } else if (options.subscriberEmail) {
66 + contact = ['mailto:' + options.subscriberEmail];
67 + }
68 +
69 + var accountRequest = {
70 + termsOfServiceAgreed: true,
71 + onlyReturnExisting: false,
72 + contact: contact
73 + };
74 +
75 + var pub = pair.public;
76 + return attachExtAcc(pub, accountRequest).then(function(accReq) {
77 + var payload = JSON.stringify(accReq);
78 + return U._jwsRequest(me, {
79 + accountKey: options.accountKey,
80 + url: me._directoryUrls.newAccount,
81 + protected: { kid: false, jwk: pair.public },
82 + payload: Enc.strToBuf(payload)
83 + }).then(function(resp) {
84 + var account = resp.body;
85 +
86 + if (resp.statusCode < 200 || resp.statusCode >= 300) {
87 + if ('string' !== typeof account) {
88 + account = JSON.stringify(account);
89 + }
90 + throw new Error(
91 + 'account error: ' +
92 + resp.statusCode +
93 + ' ' +
94 + account +
95 + '\n' +
96 + payload
97 + );
98 + }
99 +
100 + // the account id url is the "kid"
101 + var kid = resp.headers.location;
102 + if (!account) {
103 + account = { _emptyResponse: true };
104 + }
105 + if (!account.key) {
106 + account.key = {};
107 + }
108 + account.key.kid = kid;
109 + return account;
110 + });
111 + });
112 + });
113 + }
114 +
115 + // for external accounts (probably useless, but spec'd)
116 + function attachExtAcc(pubkey, accountRequest) {
117 + if (!options.externalAccount) {
118 + return Promise.resolve(accountRequest);
119 + }
120 +
121 + return Keypairs.signJws({
122 + // TODO is HMAC the standard, or is this arbitrary?
123 + secret: options.externalAccount.secret,
124 + protected: {
125 + alg: options.externalAccount.alg || 'HS256',
126 + kid: options.externalAccount.id,
127 + url: me._directoryUrls.newAccount
128 + },
129 + payload: Enc.strToBuf(JSON.stringify(pubkey))
130 + }).then(function(jws) {
131 + accountRequest.externalAccountBinding = jws;
132 + return accountRequest;
133 + });
134 + }
135 +
136 + return Promise.resolve()
137 + .then(function() {
138 + //#console.debug('[ACME.js] agreeToTerms');
139 + var agreeToTerms = options.agreeToTerms;
140 + if (!agreeToTerms) {
141 + agreeToTerms = function(terms) {
142 + if (agreers[options.subscriberEmail]) {
143 + return true;
144 + }
145 + agreers[options.subscriberEmail] = true;
146 + console.info();
147 + console.info(
148 + 'By using this software you (' +
149 + options.subscriberEmail +
150 + ') are agreeing to the following:'
151 + );
152 + console.info(
153 + 'ACME Subscriber Agreement:',
154 + terms.acmeSubscriberTermsUrl
155 + );
156 + console.info(
157 + 'Greenlock/ACME.js Terms of Use:',
158 + terms.acmeJsTermsUrl
159 + );
160 + console.info();
161 + return true;
162 + };
163 + } else if (true === agreeToTerms) {
164 + agreeToTerms = function(terms) {
165 + return terms && true;
166 + };
167 + }
168 + return agreeToTerms({
169 + acmeSubscriberTermsUrl: me._tos,
170 + acmeJsTermsUrl: 'https://rootprojects.org/legal/#terms'
171 + });
172 + })
173 + .then(agree)
174 + .then(getAccount);
175 +};
This diff is collapsed. Click to expand it.
1 +#!/usr/bin/env node
2 +(async function() {
3 + 'use strict';
4 +
5 + var UglifyJS = require('uglify-js');
6 + var path = require('path');
7 + var fs = require('fs');
8 + var promisify = require('util').promisify;
9 + var readFile = promisify(fs.readFile);
10 + var writeFile = promisify(fs.writeFile);
11 + var gzip = promisify(require('zlib').gzip);
12 +
13 + // The order is specific, and it matters
14 + var files = await Promise.all(
15 + [
16 + '../lib/encoding.js',
17 + '../lib/asn1-packer.js',
18 + '../lib/x509.js',
19 + '../lib/ecdsa.js',
20 + '../lib/rsa.js',
21 + '../lib/keypairs.js',
22 + '../lib/asn1-parser.js',
23 + '../lib/csr.js',
24 + '../lib/acme.js'
25 + ].map(async function(file) {
26 + return (await readFile(path.join(__dirname, file), 'utf8')).trim();
27 + })
28 + );
29 +
30 + var header =
31 + [
32 + '// Copyright 2015-2019 AJ ONeal. All rights reserved',
33 + '/* This Source Code Form is subject to the terms of the Mozilla Public',
34 + ' * License, v. 2.0. If a copy of the MPL was not distributed with this',
35 + ' * file, You can obtain one at http://mozilla.org/MPL/2.0/. */'
36 + ].join('\n') + '\n';
37 +
38 + var file = header + files.join('\n') + '\n';
39 + await writeFile(path.join(__dirname, '../dist', 'acme.js'), file);
40 + await writeFile(
41 + path.join(__dirname, '../dist', 'acme.js.gz'),
42 + await gzip(file)
43 + );
44 +
45 + // TODO source maps?
46 + var result = UglifyJS.minify(file, {
47 + compress: true,
48 + // mangling doesn't save significant
49 + mangle: false
50 + });
51 + if (result.error) {
52 + throw result.error;
53 + }
54 + file = header + result.code;
55 + await writeFile(path.join(__dirname, '../dist', 'acme.min.js'), file);
56 + await writeFile(
57 + path.join(__dirname, '../dist', 'acme.min.js.gz'),
58 + await gzip(file)
59 + );
60 +})();
1 +'use strict';
2 +
3 +var E = module.exports;
4 +
5 +E.NO_SUITABLE_CHALLENGE = function(domain, challenges, presenters) {
6 + // Bail with a descriptive message if no usable challenge could be selected
7 + // For example, wildcards require dns-01 and, if we don't have that, we have to bail
8 + var enabled = presenters.join(', ') || 'none';
9 + var suitable =
10 + challenges
11 + .map(function(r) {
12 + return r.type;
13 + })
14 + .join(', ') || 'none';
15 + return new Error(
16 + "None of the challenge types that you've enabled ( " +
17 + enabled +
18 + ' )' +
19 + " are suitable for validating the domain you've selected (" +
20 + domain +
21 + ').' +
22 + ' You must enable one of ( ' +
23 + suitable +
24 + ' ).'
25 + );
26 +};
27 +E.UNHANDLED_ORDER_STATUS = function(options, domains, resp) {
28 + return new Error(
29 + "Didn't finalize order: Unhandled status '" +
30 + resp.body.status +
31 + "'." +
32 + ' This is not one of the known statuses...\n' +
33 + "Requested: '" +
34 + options.domains.join(', ') +
35 + "'\n" +
36 + "Validated: '" +
37 + domains.join(', ') +
38 + "'\n" +
39 + JSON.stringify(resp.body, null, 2) +
40 + '\n\n' +
41 + 'Please open an issue at https://git.rootprojects.org/root/acme.js'
42 + );
43 +};
44 +E.DOUBLE_READY_ORDER = function(options, domains, resp) {
45 + return new Error(
46 + "Did not finalize order: status 'ready'." +
47 + " Hmmm... this state shouldn't be possible here. That was the last state." +
48 + " This one should at least be 'processing'.\n" +
49 + "Requested: '" +
50 + options.domains.join(', ') +
51 + "'\n" +
52 + "Validated: '" +
53 + domains.join(', ') +
54 + "'\n" +
55 + JSON.stringify(resp.body, null, 2) +
56 + '\n\n' +
57 + 'Please open an issue at https://git.rootprojects.org/root/acme.js'
58 + );
59 +};
60 +E.ORDER_INVALID = function(options, domains, resp) {
61 + return new Error(
62 + "Did not finalize order: status 'invalid'." +
63 + ' Best guess: One or more of the domain challenges could not be verified' +
64 + ' (or the order was canceled).\n' +
65 + "Requested: '" +
66 + options.domains.join(', ') +
67 + "'\n" +
68 + "Validated: '" +
69 + domains.join(', ') +
70 + "'\n" +
71 + JSON.stringify(resp.body, null, 2)
72 + );
73 +};
74 +E.NO_AUTHORIZATIONS = function(options, resp) {
75 + return new Error(
76 + "[acme-v2.js] authorizations were not fetched for '" +
77 + options.domains.join() +
78 + "':\n" +
79 + JSON.stringify(resp.body)
80 + );
81 +};
1 +'use strict';
2 +
3 +var native = module.exports;
4 +
5 +native._canCheck = function(me) {
6 + me._canCheck = {};
7 + return me
8 + .request({ url: me._baseUrl + '/api/_acme_api_/' })
9 + .then(function(resp) {
10 + if (resp.body.success) {
11 + me._canCheck['http-01'] = true;
12 + me._canCheck['dns-01'] = true;
13 + }
14 + })
15 + .catch(function() {
16 + // ignore
17 + });
18 +};
19 +
20 +native._dns01 = function(me, ch) {
21 + return me
22 + .request({
23 + url: me._baseUrl + '/api/dns/' + ch.dnsHost + '?type=TXT'
24 + })
25 + .then(function(resp) {
26 + var err;
27 + if (!resp.body || !Array.isArray(resp.body.answer)) {
28 + err = new Error('failed to get DNS response');
29 + console.error(err);
30 + throw err;
31 + }
32 + if (!resp.body.answer.length) {
33 + err = new Error('failed to get DNS answer record in response');
34 + console.error(err);
35 + throw err;
36 + }
37 + return {
38 + answer: resp.body.answer.map(function(ans) {
39 + return { data: ans.data, ttl: ans.ttl };
40 + })
41 + };
42 + });
43 +};
44 +
45 +native._http01 = function(me, ch) {
46 + var url = encodeURIComponent(ch.challengeUrl);
47 + return me
48 + .request({
49 + url: me._baseUrl + '/api/http?url=' + url
50 + })
51 + .then(function(resp) {
52 + return resp.body;
53 + });
54 +};
1 +'use strict';
2 +
3 +var UserAgent = module.exports;
4 +UserAgent.get = function() {
5 + return false;
6 +};
1 +'use strict';
2 +
3 +var http = module.exports;
4 +
5 +http.request = function(opts) {
6 + opts.cors = true;
7 + return window.fetch(opts.url, opts).then(function(resp) {
8 + var headers = {};
9 + var result = {
10 + statusCode: resp.status,
11 + headers: headers,
12 + toJSON: function() {
13 + return this;
14 + }
15 + };
16 + Array.from(resp.headers.entries()).forEach(function(h) {
17 + headers[h[0]] = h[1];
18 + });
19 + if (!headers['content-type']) {
20 + return result;
21 + }
22 + if (/json/.test(headers['content-type'])) {
23 + return resp.json().then(function(json) {
24 + result.body = json;
25 + return result;
26 + });
27 + }
28 + return resp.text().then(function(txt) {
29 + result.body = txt;
30 + return result;
31 + });
32 + });
33 +};
1 +'use strict';
2 +
3 +var sha2 = module.exports;
4 +
5 +var encoder = new TextEncoder();
6 +sha2.sum = function(alg, str) {
7 + var data = str;
8 + if ('string' === typeof data) {
9 + data = encoder.encode(str);
10 + }
11 + var sha = 'SHA-' + String(alg).replace(/^sha-?/i, '');
12 + return window.crypto.subtle.digest(sha, data);
13 +};
1 +'use strict';
2 +
3 +var native = module.exports;
4 +var promisify = require('util').promisify;
5 +var resolveTxt = promisify(require('dns').resolveTxt);
6 +var crypto = require('crypto');
7 +
8 +native._canCheck = function(me) {
9 + me._canCheck = {};
10 + me._canCheck['http-01'] = true;
11 + me._canCheck['dns-01'] = true;
12 + return Promise.resolve();
13 +};
14 +
15 +native._dns01 = function(me, ch) {
16 + // TODO use digd.js
17 + return resolveTxt(ch.dnsHost).then(function(records) {
18 + return {
19 + answer: records.map(function(rr) {
20 + return {
21 + data: rr
22 + };
23 + })
24 + };
25 + });
26 +};
27 +
28 +native._http01 = function(me, ch) {
29 + return new me.request({
30 + url: ch.challengeUrl
31 + }).then(function(resp) {
32 + return resp.body;
33 + });
34 +};
35 +
36 +// the hashcash here is for browser parity only
37 +// basically we ask the client to find a needle in a haystack
38 +// (very similar to CloudFlare's api protection)
39 +native._hashcash = function(ch) {
40 + if (!ch || !ch.nonce) {
41 + ch = { nonce: 'xxx' };
42 + }
43 + return Promise.resolve()
44 + .then(function() {
45 + // only get easy answers
46 + var len = ch.needle.length;
47 + var start = ch.start || 0;
48 + var end = ch.end || Math.ceil(len / 2);
49 + var window = parseInt(end - start, 10) || 0;
50 +
51 + var maxLen = 6;
52 + var maxTries = Math.pow(2, maxLen * 8);
53 + if (
54 + len > maxLen ||
55 + window < Math.ceil(len / 2) ||
56 + ch.needle.toLowerCase() !== ch.needle ||
57 + ch.alg !== 'SHA-256'
58 + ) {
59 + // bail unless the server is issuing very easy challenges
60 + throw new Error('possible and easy answers only, please');
61 + }
62 +
63 + var haystack;
64 + var i;
65 + var answer;
66 + var needle = Buffer.from(ch.needle, 'hex');
67 + for (i = 0; i < maxTries; i += 1) {
68 + answer = i.toString(16);
69 + if (answer.length % 2) {
70 + answer = '0' + answer;
71 + }
72 + haystack = crypto
73 + .createHash('sha256')
74 + .update(Buffer.from(ch.nonce + answer, 'hex'))
75 + .digest()
76 + .slice(ch.start, ch.end);
77 + if (-1 !== haystack.indexOf(needle)) {
78 + return ch.nonce + ':' + answer;
79 + }
80 + }
81 + return ch.nonce + ':xxx';
82 + })
83 + .catch(function() {
84 + //console.log('[debug]', err);
85 + // ignore any error
86 + return ch.nonce + ':xxx';
87 + });
88 +};
1 +'use strict';
2 +
3 +var os = require('os');
4 +var ver = require('../../package.json').version;
5 +
6 +var UserAgent = module.exports;
7 +UserAgent.get = function(me) {
8 + // ACME clients MUST have an RFC7231-compliant User-Agent
9 + // ex: Greenlock/v3 ACME.js/v3 node/v12.0.0 darwin/17.7.0 Darwin/x64
10 + //
11 + // See https://tools.ietf.org/html/rfc8555#section-6.1
12 + // And https://tools.ietf.org/html/rfc7231#section-5.5.3
13 + // And https://community.letsencrypt.org/t/user-agent-flag-explained/3843/2
14 +
15 + var ua =
16 + 'ACME.js/' +
17 + ver +
18 + ' ' +
19 + process.release.name +
20 + '/' +
21 + process.version +
22 + ' ' +
23 + os.platform() +
24 + '/' +
25 + os.release() +
26 + ' ' +
27 + os.type() +
28 + '/' +
29 + process.arch;
30 +
31 + var pkg = me.packageAgent;
32 + if (pkg) {
33 + ua = pkg + ' ' + ua;
34 + }
35 +
36 + return ua;
37 +};
1 +'use strict';
2 +
3 +var http = module.exports;
4 +var promisify = require('util').promisify;
5 +var request = promisify(require('@root/request'));
6 +
7 +http.request = function(opts) {
8 + return request(opts);
9 +};
1 +/* global Promise */
2 +'use strict';
3 +
4 +var sha2 = module.exports;
5 +var crypto = require('crypto');
6 +
7 +sha2.sum = function(alg, str) {
8 + return Promise.resolve().then(function() {
9 + var sha = 'sha' + String(alg).replace(/^sha-?/i, '');
10 + // utf8 is the default for strings
11 + var buf = Buffer.from(str);
12 + return crypto
13 + .createHash(sha)
14 + .update(buf)
15 + .digest();
16 + });
17 +};
1 +'use strict';
2 +
3 +var M = module.exports;
4 +var native = require('./lib/native.js');
5 +
6 +// Keep track of active maintainers so that we know who to inform if
7 +// something breaks or has a serious bug or flaw.
8 +
9 +var oldCollegeTries = {};
10 +M.init = function(me) {
11 + if (oldCollegeTries[me.maintainerEmail]) {
12 + return;
13 + }
14 +
15 + var tz = '';
16 + try {
17 + // Use timezone to stagger messages to maintainers
18 + tz = Intl.DateTimeFormat().resolvedOptions().timeZone;
19 + } catch (e) {
20 + // ignore node versions with no or incomplete Intl
21 + }
22 +
23 + // Use locale to know what language to use
24 + var env = process.env;
25 + var locale = env.LC_ALL || env.LC_MESSAGES || env.LANG || env.LANGUAGE;
26 +
27 + try {
28 + M._init(me, tz, locale);
29 + } catch (e) {
30 + //console.log(e);
31 + // ignore
32 + }
33 +};
34 +
35 +M._init = function(me, tz, locale) {
36 + // prevent a stampede from misconfigured clients in an eternal loop
37 + setTimeout(function() {
38 + me.request({
39 + method: 'GET',
40 + url: 'https://api.rootprojects.org/api/nonce',
41 + json: true
42 + })
43 + .then(function(resp) {
44 + // in the browser this will work until solved, but in
45 + // node this will bail unless the challenge is trivial
46 + return native._hashcash(resp.body || {});
47 + })
48 + .then(function(hashcash) {
49 + var req = {
50 + headers: {
51 + 'x-root-nonce-v1': hashcash
52 + },
53 + method: 'POST',
54 + url:
55 + 'https://api.rootprojects.org/api/projects/ACME.js/dependents',
56 + json: {
57 + maintainer: me.maintainerEmail,
58 + package: me.packageAgent,
59 + tz: tz,
60 + locale: locale
61 + }
62 + };
63 + return me
64 + .request(req)
65 + .catch(function(err) {
66 + if (me.debug) {
67 + console.error(
68 + 'error adding maintainer to support notices:'
69 + );
70 + console.error(err);
71 + }
72 + })
73 + .then(function(/*resp*/) {
74 + oldCollegeTries[me.maintainerEmail] = true;
75 + //console.log(resp);
76 + });
77 + });
78 + }, me.__timeout || 3000);
79 +};
80 +
81 +if (require.main === module) {
82 + var ACME = require('./');
83 + var acme = ACME.create({
84 + maintainerEmail: 'aj+acme-test@rootprojects.org',
85 + packageAgent: 'test/v0',
86 + __timeout: 100
87 + });
88 + M.init(acme);
89 +}
1 +{
2 + "_from": "@root/acme@^3.0.8",
3 + "_id": "@root/acme@3.0.8",
4 + "_inBundle": false,
5 + "_integrity": "sha512-VmBvLvWdCDkolkanI9Dzm1ouSWPaAa2eCCwcDZcVQbWoNiUIOqbbd57fcMA/gZxLyuJPStD2WXFuEuSMPDxcww==",
6 + "_location": "/@root/acme",
7 + "_phantomChildren": {},
8 + "_requested": {
9 + "type": "range",
10 + "registry": true,
11 + "raw": "@root/acme@^3.0.8",
12 + "name": "@root/acme",
13 + "escapedName": "@root%2facme",
14 + "scope": "@root",
15 + "rawSpec": "^3.0.8",
16 + "saveSpec": null,
17 + "fetchSpec": "^3.0.8"
18 + },
19 + "_requiredBy": [
20 + "/@root/greenlock"
21 + ],
22 + "_resolved": "https://registry.npmjs.org/@root/acme/-/acme-3.0.8.tgz",
23 + "_shasum": "7ab1501b7e9e7aa25c59f4833862fd078d8f39c4",
24 + "_spec": "@root/acme@^3.0.8",
25 + "_where": "C:\\Users\\USER\\Documents\\Desktop\\옵소팀플\\LINEBOT\\node_modules\\@root\\greenlock",
26 + "author": {
27 + "name": "AJ ONeal",
28 + "email": "coolaj86@gmail.com",
29 + "url": "https://coolaj86.com/"
30 + },
31 + "browser": {
32 + "./lib/native.js": "./lib/browser.js",
33 + "./lib/node/sha2.js": "./lib/browser/sha2.js",
34 + "./lib/node/http.js": "./lib/browser/http.js",
35 + "./lib/node/client-user-agent.js": "./lib/browser/client-user-agent.js"
36 + },
37 + "bundleDependencies": false,
38 + "dependencies": {
39 + "@root/encoding": "^1.0.1",
40 + "@root/keypairs": "^0.9.0",
41 + "@root/pem": "^1.0.4",
42 + "@root/request": "^1.3.11",
43 + "@root/x509": "^0.7.2"
44 + },
45 + "deprecated": false,
46 + "description": "Free SSL certificates for Node.js and Browsers. Issued via Let's Encrypt",
47 + "devDependencies": {
48 + "@root/csr": "^0.8.1",
49 + "dig.js": "^1.3.9",
50 + "dns-suite": "^1.2.13",
51 + "dotenv": "^8.1.0",
52 + "punycode": "^1.4.1"
53 + },
54 + "files": [
55 + "*.js",
56 + "lib",
57 + "bin",
58 + "scripts",
59 + "dist"
60 + ],
61 + "homepage": "https://rootprojects.org/acme/",
62 + "keywords": [
63 + "ACME",
64 + "Let's Encrypt",
65 + "EC",
66 + "RSA",
67 + "CSR",
68 + "browser",
69 + "greenlock",
70 + "VanillaJS",
71 + "ZeroSSL"
72 + ],
73 + "license": "MPL-2.0",
74 + "main": "acme.js",
75 + "name": "@root/acme",
76 + "repository": {
77 + "type": "git",
78 + "url": "https://git.rootprojects.org/root/acme.js.git"
79 + },
80 + "scripts": {
81 + "build": "node_xxx bin/bundle.js",
82 + "lint": "jshint lib bin",
83 + "postinstall": "node scripts/postinstall",
84 + "start": "node server.js",
85 + "test": "node server.js"
86 + },
87 + "trulyOptionalDependencies": {
88 + "eslint": "^6.5.1",
89 + "webpack": "^4.41.0",
90 + "webpack-cli": "^3.3.9"
91 + },
92 + "version": "3.0.8"
93 +}
1 +#!/usr/bin/env node
2 +'use strict';
3 +
4 +// TODO put postinstall message
1 +'use strict';
2 +
3 +var U = module.exports;
4 +
5 +var Keypairs = require('@root/keypairs');
6 +var UserAgent = require('./lib/node/client-user-agent.js');
7 +
8 +// Handle nonce, signing, and request altogether
9 +U._jwsRequest = function(me, bigopts) {
10 + return U._getNonce(me).then(function(nonce) {
11 + bigopts.protected.nonce = nonce;
12 + bigopts.protected.url = bigopts.url;
13 + // protected.alg: added by Keypairs.signJws
14 + if (!bigopts.protected.jwk) {
15 + // protected.kid must be overwritten due to ACME's interpretation of the spec
16 + if (!('kid' in bigopts.protected)) {
17 + bigopts.protected.kid = bigopts.kid;
18 + }
19 + }
20 +
21 + // this will shasum the thumbprint the 2nd time
22 + return Keypairs.signJws({
23 + jwk: bigopts.accountKey,
24 + protected: bigopts.protected,
25 + payload: bigopts.payload
26 + })
27 + .then(function(jws) {
28 + //#console.debug('[ACME.js] url: ' + bigopts.url + ':');
29 + //#console.debug(jws);
30 + return U._request(me, { url: bigopts.url, json: jws });
31 + })
32 + .catch(function(e) {
33 + if (/badNonce$/.test(e.urn)) {
34 + // retry badNonces
35 + var retryable = bigopts._retries >= 2;
36 + if (!retryable) {
37 + bigopts._retries = (bigopts._retries || 0) + 1;
38 + return U._jwsRequest(me, bigopts);
39 + }
40 + }
41 + throw e;
42 + });
43 + });
44 +};
45 +
46 +U._getNonce = function(me) {
47 + var nonce;
48 + while (true) {
49 + nonce = me._nonces.shift();
50 + if (!nonce) {
51 + break;
52 + }
53 + if (Date.now() - nonce.createdAt > 15 * 60 * 1000) {
54 + nonce = null;
55 + } else {
56 + break;
57 + }
58 + }
59 + if (nonce) {
60 + return Promise.resolve(nonce.nonce);
61 + }
62 +
63 + // HEAD-as-HEAD ok
64 + return U._request(me, {
65 + method: 'HEAD',
66 + url: me._directoryUrls.newNonce
67 + }).then(function(resp) {
68 + return resp.headers['replay-nonce'];
69 + });
70 +};
71 +
72 +// Handle some ACME-specific defaults
73 +U._request = function(me, opts) {
74 + // no-op on browser
75 + var ua = UserAgent.get(me, opts);
76 +
77 + // Note: the required User-Agent string will be set in node, but not browsers
78 + if (!opts.headers) {
79 + opts.headers = {};
80 + }
81 +
82 + if (ua && !opts.headers['User-Agent']) {
83 + opts.headers['User-Agent'] = ua;
84 + }
85 + if (opts.json) {
86 + opts.headers.Accept = 'application/json';
87 + if (true !== opts.json) {
88 + opts.body = JSON.stringify(opts.json);
89 + }
90 + if (/*opts.jose ||*/ opts.json.protected) {
91 + opts.headers['Content-Type'] = 'application/jose+json';
92 + }
93 + }
94 + if (!opts.method) {
95 + opts.method = 'GET';
96 + if (opts.body) {
97 + opts.method = 'POST';
98 + }
99 + }
100 +
101 + //console.log('\n[debug] REQUEST');
102 + //console.log(opts);
103 + return me.__request(opts).then(function(resp) {
104 + if (resp.toJSON) {
105 + resp = resp.toJSON();
106 + }
107 + if (resp.headers['replay-nonce']) {
108 + U._setNonce(me, resp.headers['replay-nonce']);
109 + }
110 + //console.log('[debug] RESPONSE:');
111 + //console.log(resp.headers);
112 + //console.log(resp.body);
113 +
114 + var e;
115 + var err;
116 + if (resp.body) {
117 + err = resp.body.error;
118 + e = new Error('');
119 + if (400 === resp.body.status) {
120 + err = { type: resp.body.type, detail: resp.body.detail };
121 + }
122 + if (err) {
123 + e.status = resp.body.status;
124 + e.code = 'E_ACME';
125 + if (e.status) {
126 + e.message = '[' + e.status + '] ';
127 + }
128 + e.detail = err.detail;
129 + e.message += err.detail || JSON.stringify(err);
130 + e.urn = err.type;
131 + e.uri = resp.body.url;
132 + e._rawError = err;
133 + e._rawBody = resp.body;
134 + throw e;
135 + }
136 + }
137 +
138 + return resp;
139 + });
140 +};
141 +
142 +U._setNonce = function(me, nonce) {
143 + me._nonces.unshift({ nonce: nonce, createdAt: Date.now() });
144 +};
145 +
146 +U._importKeypair = function(key) {
147 + var p;
148 + var pub;
149 +
150 + if (key && key.kty) {
151 + // nix the browser jwk extras
152 + key.key_ops = undefined;
153 + key.ext = undefined;
154 + pub = Keypairs.neuter({ jwk: key });
155 + p = Promise.resolve({
156 + private: key,
157 + public: pub
158 + });
159 + } else if ('string' === typeof key) {
160 + p = Keypairs.import({ pem: key });
161 + } else {
162 + throw new Error('no private key given');
163 + }
164 +
165 + return p.then(function(pair) {
166 + if (pair.public.kid) {
167 + pair = JSON.parse(JSON.stringify(pair));
168 + delete pair.public.kid;
169 + delete pair.private.kid;
170 + }
171 + return pair;
172 + });
173 +};
1 +'use strict';
2 +
3 +var path = require('path');
4 +
5 +module.exports = {
6 + entry: './examples/app.js',
7 + //entry: './acme.js',
8 + output: {
9 + path: path.resolve(__dirname, 'dist'),
10 + filename: 'app.js'
11 + //filename: 'acme.js',
12 + //library: '@root/acme',
13 + //libraryTarget: 'umd'
14 + //globalObject: "typeof self !== 'undefined' ? self : this"
15 + },
16 + resolve: {
17 + aliasFields: ['webpack', 'browser'],
18 + mainFields: ['browser', 'main']
19 + }
20 +};
This diff is collapsed. Click to expand it.
1 +# @root/asn1
2 +
3 +Built by [The Root Company](https://therootcompany.com)
4 +for [Greenlock](https://greenlock.domains)
5 +and [ACME.js](https://git.rootprojects.org/root/acme.js)
6 +
7 +Lightweight, Zero-Dependency ASN.1 encoder and decoder for Node.js and Browsers,
8 +in less than 300 lines of vanilla JavaScript
9 +
10 +| 1.6k gzipped
11 +| 4.2k minified
12 +| 8.4k pretty
13 +|
14 +
15 +- [x] Zero External Dependencies
16 +- [x] Universal Support
17 + - [x] Node.js
18 + - [x] Browsers
19 +- [x] Vanilla JS
20 +
21 +This ASN.1 codec is built for simplicity. It encodes into DER format
22 +and decodes into a simple, classless Array of Arrays and values.
23 +
24 +Most people don't actually want to work with ANS.1 directly,
25 +but rather intend to work with pre-defined x509 schemas.
26 +
27 +If you're **most people**, you're actually looking for one or more of these:
28 +
29 +- [pem.js](https://git.rootprojects.org/root/pem.js)
30 +- [x509.js](https://git.rootprojects.org/root/x509.js)
31 +- [csr.js](https://git.rootprojects.org/root/csr.js)
32 +- [keypairs.js](https://git.rootprojects.org/root/keypairs.js)
33 +- [encoding.js](https://git.rootprojects.org/root/encoding.js)
34 +
35 +Want to [contribute](#contributions)?
36 +Need [commercial support](#commercial-support)?
37 +
38 +# Usage
39 +
40 +ASN.1 DER consists values which have
41 +
42 +- a type (2-bit class, 6-bit tag)
43 +- a coded length
44 +- zero or more values
45 +
46 +Common types include:
47 +
48 +```txt
49 +0x30 SEQUENCE
50 +0x02 INTEGER*
51 +0x03 BIT STRING**
52 +0x04 OCTET STRING
53 +0x05 NULL
54 +0x06 OBJECT IDENTIFIER
55 +0x0C UTF8String
56 +0x16 IA5String (ASCII)
57 +0x17 UTCTime
58 +0x31 SET
59 +0xA0 context-specific***
60 +0xA3 context-specific***
61 +```
62 +
63 +<small>\* INTEGERS are always BigInt-encoded (a leading '00' for positive numbers with a 1 in the most-significant-bit position)</small>
64 +
65 +<small>\*\*BIT STRINGS have a leading "bit mask" which, for all practical purposes, is actually _always_ '00'</small>
66 +
67 +<small>\*\*\* See <https://stackoverflow.com/a/15071901/151312></small>
68 +
69 +The core value in this library is that it:
70 +
71 +- correctly sums the byte length of children elements
72 +- correctly encodes BigInts
73 +
74 +## Parser Usage
75 +
76 +There are three options:
77 +
78 +- `der` (required) - the input bytes as a buffer
79 +- `json` (default) - returns hex strings for values, rather than buffers
80 +- `verbose` - returns a more human-friendly object that is useful for debugging
81 +
82 +```js
83 +ASN1.parse({ der: `<Buffer>`, json: true, verbose: true });
84 +```
85 +
86 +Default (hex) output:
87 +
88 +```js
89 +[
90 + '30',
91 + [
92 + ['02', '01'],
93 + ['04', '2c8996...'],
94 + ['a0', [['06', '2a8648...']]],
95 + ['a1', [['03', '04bdd8...']]]
96 + ]
97 +];
98 +```
99 +
100 +Verbose output:
101 +
102 +```js
103 +{ type: 48,
104 + lengthSize: 0,
105 + length: 119,
106 + children:
107 + [ { type: 2, lengthSize: 0, length: 1, value: <Buffer 01> },
108 + { type: 4,
109 + lengthSize: 0,
110 + length: 32,
111 + value:
112 + <Buffer 2c 89 96 ...>,
113 + children: [] },
114 + { type: 160, lengthSize: 0, length: 10, children: [Array] },
115 + { type: 161, lengthSize: 0, length: 68, children: [Array] } ] }
116 +```
117 +
118 +## Packer Usage
119 +
120 +You can use either of two syntaxes. One is much easier to read than the other.
121 +
122 +Ironically, hex strings are used in place of buffers for efficiency.
123 +
124 +```js
125 +ASN1.Any(hexType, hexBytes1, hexBytes2, ...);
126 +ASN1.UInt(hexBigInt);
127 +ASN1.BitStr(hexBitStream);
128 +```
129 +
130 +In practice, you'll be cascading the objects into a final hex string:
131 +
132 +```
133 +// result is a hex-encoded DER
134 +var der = hexToBuf(
135 + ASN1.Any('30' // Sequence
136 + , ASN1.UInt('01') // Integer (Version 1)
137 + , ASN1.Any('04', '07CAD7...') // Octet String
138 + , ASN1.Any('A0', '06082A...') // [0] Object ID (context-specific)
139 + , ASN1.Any('A1', // [1] (context-specific value)
140 + ASN1.BitStr('04BDD8...')
141 + )
142 + )
143 +);
144 +```
145 +
146 +Alternatively you can pack either the sparse array or verbose object, using hex strings or buffers:
147 +
148 +- `json` when set to true will return a hex-encoded DER rather than a DER buffer
149 +
150 +```js
151 +var buf = Uint8Array.from([0x01]);
152 +
153 +ASN1.pack(
154 + [
155 + '30',
156 + [
157 + ['02', buf],
158 + ['04', '07CAD7...'],
159 + ['A0', '06082A...'],
160 + ['A1', ['03', '04BDD8...']]
161 + ]
162 + ],
163 + { json: false }
164 +);
165 +```
166 +
167 +```js
168 +var buf = Uint8Array.from([0x01]);
169 +
170 +ASN1.pack(
171 + {
172 + type: 48,
173 + children: [
174 + { type: 2, value: '01' },
175 + { type: 4, value: '2c 89 96 ...', children: [] },
176 + { type: 160, children: [...] },
177 + { type: 161, children: [...] }
178 + ]
179 + },
180 + { json: false }
181 +);
182 +```
183 +
184 +# Install
185 +
186 +This package contains both node-specific and browser-specific code,
187 +and the `package.json#browser` field ensures that your package manager
188 +will automatically choose the correct code for your environment.
189 +
190 +## Node (and Webpack)
191 +
192 +```js
193 +npm install -g @root/asn1
194 +```
195 +
196 +```js
197 +var asn1 = require('@root/asn1');
198 +```
199 +
200 +```js
201 +// just the packer
202 +var asn1 = require('@root/asn1/packer');
203 +
204 +// just the parser
205 +var asn1 = require('@root/asn1/parser');
206 +```
207 +
208 +## Browsers (Vanilla JS)
209 +
210 +```html
211 +<script src="https://unpkg.com/@root/asn1/dist/asn1.all.js"></script>
212 +```
213 +
214 +```html
215 +<script src="https://unpkg.com/@root/asn1/dist/asn1.all.min.js"></script>
216 +```
217 +
218 +```js
219 +var ASN1 = window.ASN1;
220 +```
221 +
222 +# Examples
223 +
224 +## Decoding DER to JSON-ASN.1
225 +
226 +```js
227 +var PEM = require('@root/pem/packer');
228 +var Enc = require('@root/encoding');
229 +var ASN1 = require('@root/asn1/parser');
230 +```
231 +
232 +```js
233 +var pem = [
234 + '-----BEGIN EC PRIVATE KEY-----',
235 + 'MHcCAQEEICyJlsaqkx2z9yx0H6rHA0lM3/7jXjxqn/VOhExHDuR6oAoGCCqGSM49',
236 + 'AwEHoUQDQgAEvdjQ3T6VBX82LIKDzepYgRsz3HgRwp83yPuonu6vqoshSQRe0Aye',
237 + 'mmdXUDX2wTZsmFSjhY9uroRiBbGZrigbKA==',
238 + '-----END EC PRIVATE KEY-----'
239 +].join('\n');
240 +```
241 +
242 +```js
243 +var der = PEM.parseBlock(pem).bytes;
244 +var asn1 = ASN1.parse({ der: der, json: true, verbose: false });
245 +```
246 +
247 +```json
248 +[
249 + "30",
250 + [
251 + ["02", "01"],
252 + [
253 + "04",
254 + "2c8996c6aa931db3f72c741faac703494cdffee35e3c6a9ff54e844c470ee47a"
255 + ],
256 + ["a0", [["06", "2a8648ce3d030107"]]],
257 + [
258 + "a1",
259 + [
260 + [
261 + "03",
262 + "04bdd8d0dd3e95057f362c8283cdea58811b33dc7811c29f37c8fba89eeeafaa8b2149045ed00c9e9a67575035f6c1366c9854a3858f6eae846205b199ae281b28"
263 + ]
264 + ]
265 + ]
266 + ]
267 +]
268 +```
269 +
270 +```json
271 +{
272 + "type": 48,
273 + "lengthSize": 0,
274 + "length": 119,
275 + "children": [
276 + { "type": 2, "lengthSize": 0, "length": 1, "value": "01" },
277 + {
278 + "type": 4,
279 + "lengthSize": 0,
280 + "length": 32,
281 + "value": "2c8996c6aa931db3f72c741faac703494cdffee35e3c6a9ff54e844c470ee47a",
282 + "children": []
283 + },
284 + {
285 + "type": 160,
286 + "lengthSize": 0,
287 + "length": 10,
288 + "children": [
289 + {
290 + "type": 6,
291 + "lengthSize": 0,
292 + "length": 8,
293 + "value": "2a8648ce3d030107"
294 + }
295 + ]
296 + },
297 + {
298 + "type": 161,
299 + "lengthSize": 0,
300 + "length": 68,
301 + "children": [
302 + {
303 + "type": 3,
304 + "lengthSize": 0,
305 + "length": 66,
306 + "value": "04bdd8d0dd3e95057f362c8283cdea58811b33dc7811c29f37c8fba89eeeafaa8b2149045ed00c9e9a67575035f6c1366c9854a3858f6eae846205b199ae281b28",
307 + "children": []
308 + }
309 + ]
310 + }
311 + ]
312 +}
313 +```
314 +
315 +## Encoding ASN.1 to DER
316 +
317 +Here's an example of an SEC1-encoded EC P-256 Public/Private Keypair:
318 +
319 +```js
320 +var ASN1 = require('@root/asn1/packer');
321 +var Enc = require('@root/encoding');
322 +var PEM = require('@root/pem/packer');
323 +```
324 +
325 +```js
326 +// 1.2.840.10045.3.1.7
327 +// prime256v1 (ANSI X9.62 named elliptic curve)
328 +var OBJ_ID_EC_256 = '06 08 2A8648CE3D030107';
329 +```
330 +
331 +```js
332 +var jwk = {
333 + crv: 'P-256',
334 + d: 'LImWxqqTHbP3LHQfqscDSUzf_uNePGqf9U6ETEcO5Ho',
335 + kty: 'EC',
336 + x: 'vdjQ3T6VBX82LIKDzepYgRsz3HgRwp83yPuonu6vqos',
337 + y: 'IUkEXtAMnppnV1A19sE2bJhUo4WPbq6EYgWxma4oGyg',
338 + kid: 'MnfJYyS9W5gUjrJLdn8ePMzik8ZJz2qc-VZmKOs_oCw'
339 +};
340 +var d = Enc.base64ToHex(jwk.d);
341 +var x = Enc.base64ToHex(jwk.x);
342 +var y = Enc.base64ToHex(jwk.y);
343 +```
344 +
345 +```
346 +var der = Enc.hexToBuf(
347 + ASN1.Any('30' // Sequence
348 + , ASN1.UInt('01') // Integer (Version 1)
349 + , ASN1.Any('04', d) // Octet String
350 + , ASN1.Any('A0', OBJ_ID_EC_256) // [0] Object ID
351 + , ASN1.Any('A1', // [1] Embedded EC/ASN1 public key
352 + ASN1.BitStr('04' + x + y)
353 + )
354 + )
355 +);
356 +
357 +var pem = PEM.packBlock({
358 + type: 'EC PRIVATE KEY',
359 + bytes: der
360 +});
361 +```
362 +
363 +# Disabiguation
364 +
365 +`ASN1.Any(typ, hexVal, ...)`
366 +
367 +There was once an actual ASN.1 type with the literal name 'Any'.
368 +It was deprecated in 1994 and the `Any` in this API simply means "give any value"
369 +
370 +# Contributions
371 +
372 +Did this project save you some time? Maybe make your day? Even save the day?
373 +
374 +Please say "thanks" via Paypal or Patreon:
375 +
376 +- Paypal: [\$5](https://paypal.me/rootprojects/5) | [\$10](https://paypal.me/rootprojects/10) | Any amount: <paypal@therootcompany.com>
377 +- Patreon: <https://patreon.com/rootprojects>
378 +
379 +Where does your contribution go?
380 +
381 +[Root](https://therootcompany.com) is a collection of experts
382 +who trust each other and enjoy working together on deep-tech,
383 +Indie Web projects.
384 +
385 +Our goal is to operate as a sustainable community.
386 +
387 +Your contributions - both in code and _especially_ monetarily -
388 +help to not just this project, but also our broader work
389 +of [projects](https://rootprojects.org) that fuel the **Indie Web**.
390 +
391 +Also, we chat on [Keybase](https://keybase.io)
392 +in [#rootprojects](https://keybase.io/team/rootprojects)
393 +
394 +# Commercial Support
395 +
396 +Do you need...
397 +
398 +- more features?
399 +- bugfixes, on _your_ timeline?
400 +- custom code, built by experts?
401 +- commercial support and licensing?
402 +
403 +Contact <aj@therootcompany.com> for support options.
404 +
405 +# Legal
406 +
407 +Copyright [AJ ONeal](https://coolaj86.com),
408 +[Root](https://therootcompany.com) 2018-2019
409 +
410 +MPL-2.0 |
411 +[Terms of Use](https://therootcompany.com/legal/#terms) |
412 +[Privacy Policy](https://therootcompany.com/legal/#privacy)
This diff is collapsed. Click to expand it.
1 +(function(){"use strict";var Enc=window.Encoding={};Enc.bufToBase64=function(u8){var bin="";u8.forEach(function(i){bin+=String.fromCharCode(i)});return btoa(bin)};Enc.strToBase64=function(str){return btoa(Enc.strToBin(str))};function _base64ToBin(b64){return atob(Enc.urlBase64ToBase64(b64))}Enc._base64ToBin=_base64ToBin;Enc.base64ToBuf=function(b64){return Enc.binToBuf(_base64ToBin(b64))};Enc.base64ToStr=function(b64){return Enc.binToStr(_base64ToBin(b64))};Enc.urlBase64ToBase64=function(u64){var r=u64%4;if(2===r){u64+="=="}else if(3===r){u64+="="}return u64.replace(/-/g,"+").replace(/_/g,"/")};Enc.base64ToUrlBase64=function(b64){return b64.replace(/\+/g,"-").replace(/\//g,"_").replace(/=/g,"")};Enc.bufToUrlBase64=function(buf){return Enc.base64ToUrlBase64(Enc.bufToBase64(buf))};Enc.strToUrlBase64=function(str){return Enc.bufToUrlBase64(Enc.strToBuf(str))};Enc.bufToHex=function(u8){var hex=[];var i,h;var len=u8.byteLength||u8.length;for(i=0;i<len;i+=1){h=u8[i].toString(16);if(2!==h.length){h="0"+h}hex.push(h)}return hex.join("").toLowerCase()};Enc.numToHex=function(d){d=d.toString(16);if(d.length%2){return"0"+d}return d};Enc.strToHex=function(str){return Enc._binToHex(Enc.strToBin(str))};Enc._binToHex=function(bin){return bin.split("").map(function(ch){var h=ch.charCodeAt(0).toString(16);if(2!==h.length){h="0"+h}return h}).join("")};Enc.hexToBuf=function(hex){var arr=[];hex.match(/.{2}/g).forEach(function(h){arr.push(parseInt(h,16))});return"undefined"!==typeof Uint8Array?new Uint8Array(arr):arr};Enc.hexToStr=function(hex){return Enc.binToStr(_hexToBin(hex))};function _hexToBin(hex){return hex.replace(/([0-9A-F]{2})/gi,function(_,p1){return String.fromCharCode("0x"+p1)})}Enc._hexToBin=_hexToBin;Enc.bufToBin=function(buf){var bin="";buf.forEach(function(ch){bin+=String.fromCharCode(ch)});return bin};Enc.strToBin=function(str){var escstr=encodeURIComponent(str);var binstr=escstr.replace(/%([0-9A-F]{2})/g,function(_,p1){return String.fromCharCode("0x"+p1)});return binstr};Enc.binToBuf=function(bin){var arr=bin.split("").map(function(ch){return ch.charCodeAt(0)});return"undefined"!==typeof Uint8Array?new Uint8Array(arr):arr};Enc.strToBuf=function(str){return Enc.binToBuf(Enc.strToBin(str))};Enc.binToStr=function(binstr){var escstr=binstr.replace(/(.)/g,function(m,p){var code=p.charCodeAt(0).toString(16).toUpperCase();if(code.length<2){code="0"+code}return"%"+code});return decodeURIComponent(escstr)};Enc.bufToStr=function(buf){return Enc.binToStr(Enc.bufToBin(buf))};Enc.base64ToHex=function(b64){return Enc.bufToHex(Enc.base64ToBuf(b64))};Enc.hexToBase64=function(hex){return btoa(Enc._hexToBin(hex))}})();(function(){"use strict";var ASN1=window.ASN1={};var Enc=window.Encoding;ASN1.ELOOPN=102;ASN1.ELOOP="uASN1.js Error: iterated over "+ASN1.ELOOPN+"+ elements (probably a malformed file)";ASN1.EDEEPN=60;ASN1.EDEEP="uASN1.js Error: element nested "+ASN1.EDEEPN+"+ layers deep (probably a malformed file)";ASN1.CTYPES=[48,49,160,161];ASN1.VTYPES=[1,2,5,6,12,130];ASN1.parseVerbose=function parseAsn1Helper(buf,opts){if(!opts){opts={}}function parseAsn1(buf,depth,eager){if(depth.length>=ASN1.EDEEPN){throw new Error(ASN1.EDEEP)}var index=2;var asn1={type:buf[0],lengthSize:0,length:buf[1]};var child;var iters=0;var adjust=0;var adjustedLen;if(128&asn1.length){asn1.lengthSize=127&asn1.length;asn1.length=parseInt(Enc.bufToHex(buf.slice(index,index+asn1.lengthSize)),16);index+=asn1.lengthSize}if(0===buf[index]&&(2===asn1.type||3===asn1.type)){if(asn1.length>1){index+=1;adjust=-1}}adjustedLen=asn1.length+adjust;function parseChildren(eager){asn1.children=[];while(iters<ASN1.ELOOPN&&index<2+asn1.length+asn1.lengthSize){iters+=1;depth.length+=1;child=parseAsn1(buf.slice(index,index+adjustedLen),depth,eager);depth.length-=1;index+=2+child.lengthSize+child.length;if(index>2+asn1.lengthSize+asn1.length){if(!eager){console.error(JSON.stringify(asn1,ASN1._replacer,2))}throw new Error("Parse error: child value length ("+child.length+") is greater than remaining parent length ("+(asn1.length-index)+" = "+asn1.length+" - "+index+")")}asn1.children.push(child)}if(index!==2+asn1.lengthSize+asn1.length){throw new Error("premature end-of-file")}if(iters>=ASN1.ELOOPN){throw new Error(ASN1.ELOOP)}delete asn1.value;return asn1}if(-1!==ASN1.CTYPES.indexOf(asn1.type)){return parseChildren(eager)}asn1.value=buf.slice(index,index+adjustedLen);if(opts.json){asn1.value=Enc.bufToHex(asn1.value)}if(-1!==ASN1.VTYPES.indexOf(asn1.type)){return asn1}try{return parseChildren(true)}catch(e){asn1.children.length=0;return asn1}}var asn1=parseAsn1(buf,[]);var len=buf.byteLength||buf.length;if(len!==2+asn1.lengthSize+asn1.length){throw new Error("Length of buffer does not match length of ASN.1 sequence.")}return asn1};ASN1._toArray=function toArray(next,opts){var typ=opts.json?Enc.numToHex(next.type):next.type;var val=next.value;if(val){if("string"!==typeof val&&opts.json){val=Enc.bufToHex(val)}return[typ,val]}return[typ,next.children.map(function(child){return toArray(child,opts)})]};ASN1.parse=function(opts){var opts2={json:false!==opts.json};var verbose=ASN1.parseVerbose(opts.der,opts2);if(opts.verbose){return verbose}return ASN1._toArray(verbose,opts2)};ASN1._replacer=function(k,v){if("type"===k){return"0x"+Enc.numToHex(v)}if(v&&"value"===k){return"0x"+Enc.bufToHex(v.data||v)}return v};function Any(){var args=Array.prototype.slice.call(arguments);var typ=args.shift();var str=args.join("").replace(/\s+/g,"").toLowerCase();var len=str.length/2;var lenlen=0;var hex=typ;if("number"===typeof hex){hex=Enc.numToHex(hex)}if(len!==Math.round(len)){throw new Error("invalid hex")}if(len>127){lenlen+=1;while(len>255){lenlen+=1;len=len>>8}}if(lenlen){hex+=Enc.numToHex(128+lenlen)}return hex+Enc.numToHex(str.length/2)+str}ASN1.Any=Any;ASN1.UInt=function UINT(){var str=Array.prototype.slice.call(arguments).join("");var first=parseInt(str.slice(0,2),16);if(128&first){str="00"+str}return Any("02",str)};ASN1.BitStr=function BITSTR(){var str=Array.prototype.slice.call(arguments).join("");return Any("03","00"+str)};ASN1._toArray=function toArray(next,opts){var typ=opts.json?Enc.numToHex(next.type):next.type;var val=next.value;if(val){if("string"!==typeof val&&opts.json){val=Enc.bufToHex(val)}return[typ,val]}return[typ,next.children.map(function(child){return toArray(child,opts)})]};ASN1._pack=function(arr){var typ=arr[0];if("number"===typeof arr[0]){typ=Enc.numToHex(arr[0])}var str="";if(Array.isArray(arr[1])){arr[1].forEach(function(a){str+=ASN1._pack(a)})}else if("string"===typeof arr[1]){str=arr[1]}else if(arr[1].byteLength){str=Enc.bufToHex(arr[1])}else{throw new Error("unexpected array")}if("03"===typ){return ASN1.BitStr(str)}else if("02"===typ){return ASN1.UInt(str)}else{return Any(typ,str)}};ASN1.pack=function(asn1,opts){if(!opts){opts={}}if(!Array.isArray(asn1)){asn1=ASN1._toArray(asn1,{json:true})}var result=ASN1._pack(asn1);if(opts.json){return result}return Enc.hexToBuf(result)}})();
1 +;(function () {
2 +'use strict';
3 +var ASN1 = window.ASN1 = {};
4 +var Enc = window.Encoding;
5 +// Copyright 2018 AJ ONeal. All rights reserved
6 +/* This Source Code Form is subject to the terms of the Mozilla Public
7 + * License, v. 2.0. If a copy of the MPL was not distributed with this
8 + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
9 +
10 +
11 +//
12 +// Parser
13 +//
14 +
15 +// Although I've only seen 9 max in https certificates themselves,
16 +// but each domain list could have up to 100
17 +ASN1.ELOOPN = 102;
18 +ASN1.ELOOP =
19 + 'uASN1.js Error: iterated over ' +
20 + ASN1.ELOOPN +
21 + '+ elements (probably a malformed file)';
22 +// I've seen https certificates go 29 deep
23 +ASN1.EDEEPN = 60;
24 +ASN1.EDEEP =
25 + 'uASN1.js Error: element nested ' +
26 + ASN1.EDEEPN +
27 + '+ layers deep (probably a malformed file)';
28 +// Container Types are Sequence 0x30, Container Array? (0xA0, 0xA1)
29 +// Value Types are Boolean 0x01, Integer 0x02, Null 0x05, Object ID 0x06, String 0x0C, 0x16, 0x13, 0x1e Value Array? (0x82)
30 +// Bit String (0x03) and Octet String (0x04) may be values or containers
31 +// Sometimes Bit String is used as a container (RSA Pub Spki)
32 +ASN1.CTYPES = [0x30, 0x31, 0xa0, 0xa1];
33 +ASN1.VTYPES = [0x01, 0x02, 0x05, 0x06, 0x0c, 0x82];
34 +ASN1.parseVerbose = function parseAsn1Helper(buf, opts) {
35 + if (!opts) {
36 + opts = {};
37 + }
38 + //var ws = ' ';
39 + function parseAsn1(buf, depth, eager) {
40 + if (depth.length >= ASN1.EDEEPN) {
41 + throw new Error(ASN1.EDEEP);
42 + }
43 +
44 + var index = 2; // we know, at minimum, data starts after type (0) and lengthSize (1)
45 + var asn1 = { type: buf[0], lengthSize: 0, length: buf[1] };
46 + var child;
47 + var iters = 0;
48 + var adjust = 0;
49 + var adjustedLen;
50 +
51 + // Determine how many bytes the length uses, and what it is
52 + if (0x80 & asn1.length) {
53 + asn1.lengthSize = 0x7f & asn1.length;
54 + // I think that buf->hex->int solves the problem of Endianness... not sure
55 + asn1.length = parseInt(
56 + Enc.bufToHex(buf.slice(index, index + asn1.lengthSize)),
57 + 16
58 + );
59 + index += asn1.lengthSize;
60 + }
61 +
62 + // High-order bit Integers have a leading 0x00 to signify that they are positive.
63 + // Bit Streams use the first byte to signify padding, which x.509 doesn't use.
64 + if (0x00 === buf[index] && (0x02 === asn1.type || 0x03 === asn1.type)) {
65 + // However, 0x00 on its own is a valid number
66 + if (asn1.length > 1) {
67 + index += 1;
68 + adjust = -1;
69 + }
70 + }
71 + adjustedLen = asn1.length + adjust;
72 +
73 + //console.warn(depth.join(ws) + '0x' + Enc.numToHex(asn1.type), index, 'len:', asn1.length, asn1);
74 +
75 + function parseChildren(eager) {
76 + asn1.children = [];
77 + //console.warn('1 len:', (2 + asn1.lengthSize + asn1.length), 'idx:', index, 'clen:', 0);
78 + while (
79 + iters < ASN1.ELOOPN &&
80 + index < 2 + asn1.length + asn1.lengthSize
81 + ) {
82 + iters += 1;
83 + depth.length += 1;
84 + child = parseAsn1(
85 + buf.slice(index, index + adjustedLen),
86 + depth,
87 + eager
88 + );
89 + depth.length -= 1;
90 + // The numbers don't match up exactly and I don't remember why...
91 + // probably something with adjustedLen or some such, but the tests pass
92 + index += 2 + child.lengthSize + child.length;
93 + //console.warn('2 len:', (2 + asn1.lengthSize + asn1.length), 'idx:', index, 'clen:', (2 + child.lengthSize + child.length));
94 + if (index > 2 + asn1.lengthSize + asn1.length) {
95 + if (!eager) {
96 + console.error(JSON.stringify(asn1, ASN1._replacer, 2));
97 + }
98 + throw new Error(
99 + 'Parse error: child value length (' +
100 + child.length +
101 + ') is greater than remaining parent length (' +
102 + (asn1.length - index) +
103 + ' = ' +
104 + asn1.length +
105 + ' - ' +
106 + index +
107 + ')'
108 + );
109 + }
110 + asn1.children.push(child);
111 + //console.warn(depth.join(ws) + '0x' + Enc.numToHex(asn1.type), index, 'len:', asn1.length, asn1);
112 + }
113 + if (index !== 2 + asn1.lengthSize + asn1.length) {
114 + //console.warn('index:', index, 'length:', (2 + asn1.lengthSize + asn1.length));
115 + throw new Error('premature end-of-file');
116 + }
117 + if (iters >= ASN1.ELOOPN) {
118 + throw new Error(ASN1.ELOOP);
119 + }
120 +
121 + delete asn1.value;
122 + return asn1;
123 + }
124 +
125 + // Recurse into types that are _always_ containers
126 + if (-1 !== ASN1.CTYPES.indexOf(asn1.type)) {
127 + return parseChildren(eager);
128 + }
129 +
130 + // Return types that are _always_ values
131 + asn1.value = buf.slice(index, index + adjustedLen);
132 + if (opts.json) {
133 + asn1.value = Enc.bufToHex(asn1.value);
134 + }
135 + if (-1 !== ASN1.VTYPES.indexOf(asn1.type)) {
136 + return asn1;
137 + }
138 +
139 + // For ambigious / unknown types, recurse and return on failure
140 + // (and return child array size to zero)
141 + try {
142 + return parseChildren(true);
143 + } catch (e) {
144 + asn1.children.length = 0;
145 + return asn1;
146 + }
147 + }
148 +
149 + var asn1 = parseAsn1(buf, []);
150 + var len = buf.byteLength || buf.length;
151 + if (len !== 2 + asn1.lengthSize + asn1.length) {
152 + throw new Error(
153 + 'Length of buffer does not match length of ASN.1 sequence.'
154 + );
155 + }
156 + return asn1;
157 +};
158 +ASN1._toArray = function toArray(next, opts) {
159 + var typ = opts.json ? Enc.numToHex(next.type) : next.type;
160 + var val = next.value;
161 + if (val) {
162 + if ('string' !== typeof val && opts.json) {
163 + val = Enc.bufToHex(val);
164 + }
165 + return [typ, val];
166 + }
167 + return [
168 + typ,
169 + next.children.map(function(child) {
170 + return toArray(child, opts);
171 + })
172 + ];
173 +};
174 +ASN1.parse = function(opts) {
175 + var opts2 = { json: false !== opts.json };
176 + var verbose = ASN1.parseVerbose(opts.der, opts2);
177 + if (opts.verbose) {
178 + return verbose;
179 + }
180 + return ASN1._toArray(verbose, opts2);
181 +};
182 +ASN1._replacer = function(k, v) {
183 + if ('type' === k) {
184 + return '0x' + Enc.numToHex(v);
185 + }
186 + if (v && 'value' === k) {
187 + return '0x' + Enc.bufToHex(v.data || v);
188 + }
189 + return v;
190 +};
191 +
192 +
193 +//
194 +// Packer
195 +//
196 +
197 +// Almost every ASN.1 type that's important for CSR
198 +// can be represented generically with only a few rules.
199 +function Any(/*type, hexstrings...*/) {
200 + var args = Array.prototype.slice.call(arguments);
201 + var typ = args.shift();
202 + var str = args
203 + .join('')
204 + .replace(/\s+/g, '')
205 + .toLowerCase();
206 + var len = str.length / 2;
207 + var lenlen = 0;
208 + var hex = typ;
209 + if ('number' === typeof hex) {
210 + hex = Enc.numToHex(hex);
211 + }
212 +
213 + // We can't have an odd number of hex chars
214 + if (len !== Math.round(len)) {
215 + throw new Error('invalid hex');
216 + }
217 +
218 + // The first byte of any ASN.1 sequence is the type (Sequence, Integer, etc)
219 + // The second byte is either the size of the value, or the size of its size
220 +
221 + // 1. If the second byte is < 0x80 (128) it is considered the size
222 + // 2. If it is > 0x80 then it describes the number of bytes of the size
223 + // ex: 0x82 means the next 2 bytes describe the size of the value
224 + // 3. The special case of exactly 0x80 is "indefinite" length (to end-of-file)
225 +
226 + if (len > 127) {
227 + lenlen += 1;
228 + while (len > 255) {
229 + lenlen += 1;
230 + len = len >> 8;
231 + }
232 + }
233 +
234 + if (lenlen) {
235 + hex += Enc.numToHex(0x80 + lenlen);
236 + }
237 + return hex + Enc.numToHex(str.length / 2) + str;
238 +}
239 +ASN1.Any = Any;
240 +
241 +// The Integer type has some special rules
242 +ASN1.UInt = function UINT() {
243 + var str = Array.prototype.slice.call(arguments).join('');
244 + var first = parseInt(str.slice(0, 2), 16);
245 +
246 + // If the first byte is 0x80 or greater, the number is considered negative
247 + // Therefore we add a '00' prefix if the 0x80 bit is set
248 + if (0x80 & first) {
249 + str = '00' + str;
250 + }
251 +
252 + return Any('02', str);
253 +};
254 +
255 +// The Bit String type also has a special rule
256 +ASN1.BitStr = function BITSTR() {
257 + var str = Array.prototype.slice.call(arguments).join('');
258 + // '00' is a mask of how many bits of the next byte to ignore
259 + return Any('03', '00' + str);
260 +};
261 +
262 +ASN1._toArray = function toArray(next, opts) {
263 + var typ = opts.json ? Enc.numToHex(next.type) : next.type;
264 + var val = next.value;
265 + if (val) {
266 + if ('string' !== typeof val && opts.json) {
267 + val = Enc.bufToHex(val);
268 + }
269 + return [typ, val];
270 + }
271 + return [
272 + typ,
273 + next.children.map(function(child) {
274 + return toArray(child, opts);
275 + })
276 + ];
277 +};
278 +
279 +ASN1._pack = function(arr) {
280 + var typ = arr[0];
281 + if ('number' === typeof arr[0]) {
282 + typ = Enc.numToHex(arr[0]);
283 + }
284 + var str = '';
285 + if (Array.isArray(arr[1])) {
286 + arr[1].forEach(function(a) {
287 + str += ASN1._pack(a);
288 + });
289 + } else if ('string' === typeof arr[1]) {
290 + str = arr[1];
291 + } else if (arr[1].byteLength) {
292 + str = Enc.bufToHex(arr[1]);
293 + } else {
294 + throw new Error('unexpected array');
295 + }
296 + if ('03' === typ) {
297 + return ASN1.BitStr(str);
298 + } else if ('02' === typ) {
299 + return ASN1.UInt(str);
300 + } else {
301 + return Any(typ, str);
302 + }
303 +};
304 +
305 +// TODO should this return a buffer?
306 +ASN1.pack = function(asn1, opts) {
307 + if (!opts) {
308 + opts = {};
309 + }
310 + if (!Array.isArray(asn1)) {
311 + asn1 = ASN1._toArray(asn1, { json: true });
312 + }
313 + var result = ASN1._pack(asn1);
314 + if (opts.json) {
315 + return result;
316 + }
317 + return Enc.hexToBuf(result);
318 +};
319 +}());
1 +(function(){"use strict";var ASN1=window.ASN1={};var Enc=window.Encoding;ASN1.ELOOPN=102;ASN1.ELOOP="uASN1.js Error: iterated over "+ASN1.ELOOPN+"+ elements (probably a malformed file)";ASN1.EDEEPN=60;ASN1.EDEEP="uASN1.js Error: element nested "+ASN1.EDEEPN+"+ layers deep (probably a malformed file)";ASN1.CTYPES=[48,49,160,161];ASN1.VTYPES=[1,2,5,6,12,130];ASN1.parseVerbose=function parseAsn1Helper(buf,opts){if(!opts){opts={}}function parseAsn1(buf,depth,eager){if(depth.length>=ASN1.EDEEPN){throw new Error(ASN1.EDEEP)}var index=2;var asn1={type:buf[0],lengthSize:0,length:buf[1]};var child;var iters=0;var adjust=0;var adjustedLen;if(128&asn1.length){asn1.lengthSize=127&asn1.length;asn1.length=parseInt(Enc.bufToHex(buf.slice(index,index+asn1.lengthSize)),16);index+=asn1.lengthSize}if(0===buf[index]&&(2===asn1.type||3===asn1.type)){if(asn1.length>1){index+=1;adjust=-1}}adjustedLen=asn1.length+adjust;function parseChildren(eager){asn1.children=[];while(iters<ASN1.ELOOPN&&index<2+asn1.length+asn1.lengthSize){iters+=1;depth.length+=1;child=parseAsn1(buf.slice(index,index+adjustedLen),depth,eager);depth.length-=1;index+=2+child.lengthSize+child.length;if(index>2+asn1.lengthSize+asn1.length){if(!eager){console.error(JSON.stringify(asn1,ASN1._replacer,2))}throw new Error("Parse error: child value length ("+child.length+") is greater than remaining parent length ("+(asn1.length-index)+" = "+asn1.length+" - "+index+")")}asn1.children.push(child)}if(index!==2+asn1.lengthSize+asn1.length){throw new Error("premature end-of-file")}if(iters>=ASN1.ELOOPN){throw new Error(ASN1.ELOOP)}delete asn1.value;return asn1}if(-1!==ASN1.CTYPES.indexOf(asn1.type)){return parseChildren(eager)}asn1.value=buf.slice(index,index+adjustedLen);if(opts.json){asn1.value=Enc.bufToHex(asn1.value)}if(-1!==ASN1.VTYPES.indexOf(asn1.type)){return asn1}try{return parseChildren(true)}catch(e){asn1.children.length=0;return asn1}}var asn1=parseAsn1(buf,[]);var len=buf.byteLength||buf.length;if(len!==2+asn1.lengthSize+asn1.length){throw new Error("Length of buffer does not match length of ASN.1 sequence.")}return asn1};ASN1._toArray=function toArray(next,opts){var typ=opts.json?Enc.numToHex(next.type):next.type;var val=next.value;if(val){if("string"!==typeof val&&opts.json){val=Enc.bufToHex(val)}return[typ,val]}return[typ,next.children.map(function(child){return toArray(child,opts)})]};ASN1.parse=function(opts){var opts2={json:false!==opts.json};var verbose=ASN1.parseVerbose(opts.der,opts2);if(opts.verbose){return verbose}return ASN1._toArray(verbose,opts2)};ASN1._replacer=function(k,v){if("type"===k){return"0x"+Enc.numToHex(v)}if(v&&"value"===k){return"0x"+Enc.bufToHex(v.data||v)}return v};function Any(){var args=Array.prototype.slice.call(arguments);var typ=args.shift();var str=args.join("").replace(/\s+/g,"").toLowerCase();var len=str.length/2;var lenlen=0;var hex=typ;if("number"===typeof hex){hex=Enc.numToHex(hex)}if(len!==Math.round(len)){throw new Error("invalid hex")}if(len>127){lenlen+=1;while(len>255){lenlen+=1;len=len>>8}}if(lenlen){hex+=Enc.numToHex(128+lenlen)}return hex+Enc.numToHex(str.length/2)+str}ASN1.Any=Any;ASN1.UInt=function UINT(){var str=Array.prototype.slice.call(arguments).join("");var first=parseInt(str.slice(0,2),16);if(128&first){str="00"+str}return Any("02",str)};ASN1.BitStr=function BITSTR(){var str=Array.prototype.slice.call(arguments).join("");return Any("03","00"+str)};ASN1._toArray=function toArray(next,opts){var typ=opts.json?Enc.numToHex(next.type):next.type;var val=next.value;if(val){if("string"!==typeof val&&opts.json){val=Enc.bufToHex(val)}return[typ,val]}return[typ,next.children.map(function(child){return toArray(child,opts)})]};ASN1._pack=function(arr){var typ=arr[0];if("number"===typeof arr[0]){typ=Enc.numToHex(arr[0])}var str="";if(Array.isArray(arr[1])){arr[1].forEach(function(a){str+=ASN1._pack(a)})}else if("string"===typeof arr[1]){str=arr[1]}else if(arr[1].byteLength){str=Enc.bufToHex(arr[1])}else{throw new Error("unexpected array")}if("03"===typ){return ASN1.BitStr(str)}else if("02"===typ){return ASN1.UInt(str)}else{return Any(typ,str)}};ASN1.pack=function(asn1,opts){if(!opts){opts={}}if(!Array.isArray(asn1)){asn1=ASN1._toArray(asn1,{json:true})}var result=ASN1._pack(asn1);if(opts.json){return result}return Enc.hexToBuf(result)}})();
No preview for this file type
1 +<html>
2 + <head>
3 + <meta charset="UTF-8" />
4 + </head>
5 + <body>
6 + <script src="./asn1.all.js"></script>
7 + </body>
8 +</html>
1 +'use strict';
2 +
3 +var ASN1 = module.exports;
4 +var packer = require('./packer.js');
5 +var parser = require('./parser.js');
6 +Object.keys(parser).forEach(function(key) {
7 + ASN1[key] = parser[key];
8 +});
9 +Object.keys(packer).forEach(function(key) {
10 + ASN1[key] = packer[key];
11 +});
1 +{
2 + "_from": "@root/asn1@^1.0.0",
3 + "_id": "@root/asn1@1.0.0",
4 + "_inBundle": false,
5 + "_integrity": "sha512-0lfZNuOULKJDJmdIkP8V9RnbV3XaK6PAHD3swnFy4tZwtlMDzLKoM/dfNad7ut8Hu3r91wy9uK0WA/9zym5mig==",
6 + "_location": "/@root/asn1",
7 + "_phantomChildren": {},
8 + "_requested": {
9 + "type": "range",
10 + "registry": true,
11 + "raw": "@root/asn1@^1.0.0",
12 + "name": "@root/asn1",
13 + "escapedName": "@root%2fasn1",
14 + "scope": "@root",
15 + "rawSpec": "^1.0.0",
16 + "saveSpec": null,
17 + "fetchSpec": "^1.0.0"
18 + },
19 + "_requiredBy": [
20 + "/@root/csr",
21 + "/@root/x509"
22 + ],
23 + "_resolved": "https://registry.npmjs.org/@root/asn1/-/asn1-1.0.0.tgz",
24 + "_shasum": "8748cf7b4497324de91a154b606ca1ddfe97c5d7",
25 + "_spec": "@root/asn1@^1.0.0",
26 + "_where": "C:\\Users\\USER\\Documents\\Desktop\\옵소팀플\\LINEBOT\\node_modules\\@root\\x509",
27 + "author": {
28 + "name": "AJ ONeal",
29 + "email": "coolaj86@gmail.com",
30 + "url": "https://coolaj86.com/"
31 + },
32 + "browser": {
33 + "./node/native.js": "./browser/native.js"
34 + },
35 + "bundleDependencies": false,
36 + "dependencies": {
37 + "@root/encoding": "^1.0.1"
38 + },
39 + "deprecated": false,
40 + "description": "VanillaJS, Lightweight, Zero-Dependency, ASN.1 encoder and decoder.",
41 + "devDependencies": {
42 + "@root/pem": "^1.0.3"
43 + },
44 + "files": [
45 + "*.js",
46 + "node",
47 + "browser",
48 + "dist"
49 + ],
50 + "keywords": [
51 + "ASN.1",
52 + "asn1",
53 + "x509",
54 + "PEM"
55 + ],
56 + "license": "MPL-2.0",
57 + "main": "index.js",
58 + "name": "@root/asn1",
59 + "repository": {
60 + "type": "git",
61 + "url": "https://git.rootprojects.org/root/asn1.js.git"
62 + },
63 + "scripts": {
64 + "test": "node tests"
65 + },
66 + "version": "1.0.0"
67 +}
1 +'use strict';
2 +
3 +var ASN1 = module.exports;
4 +var Enc = require('@root/encoding/hex');
5 +
6 +//
7 +// Packer
8 +//
9 +
10 +// Almost every ASN.1 type that's important for CSR
11 +// can be represented generically with only a few rules.
12 +function Any(/*type, hexstrings...*/) {
13 + var args = Array.prototype.slice.call(arguments);
14 + var typ = args.shift();
15 + var str = args
16 + .join('')
17 + .replace(/\s+/g, '')
18 + .toLowerCase();
19 + var len = str.length / 2;
20 + var lenlen = 0;
21 + var hex = typ;
22 + if ('number' === typeof hex) {
23 + hex = Enc.numToHex(hex);
24 + }
25 +
26 + // We can't have an odd number of hex chars
27 + if (len !== Math.round(len)) {
28 + throw new Error('invalid hex');
29 + }
30 +
31 + // The first byte of any ASN.1 sequence is the type (Sequence, Integer, etc)
32 + // The second byte is either the size of the value, or the size of its size
33 +
34 + // 1. If the second byte is < 0x80 (128) it is considered the size
35 + // 2. If it is > 0x80 then it describes the number of bytes of the size
36 + // ex: 0x82 means the next 2 bytes describe the size of the value
37 + // 3. The special case of exactly 0x80 is "indefinite" length (to end-of-file)
38 +
39 + if (len > 127) {
40 + lenlen += 1;
41 + while (len > 255) {
42 + lenlen += 1;
43 + len = len >> 8;
44 + }
45 + }
46 +
47 + if (lenlen) {
48 + hex += Enc.numToHex(0x80 + lenlen);
49 + }
50 + return hex + Enc.numToHex(str.length / 2) + str;
51 +}
52 +ASN1.Any = Any;
53 +
54 +// The Integer type has some special rules
55 +ASN1.UInt = function UINT() {
56 + var str = Array.prototype.slice.call(arguments).join('');
57 + var first = parseInt(str.slice(0, 2), 16);
58 +
59 + // If the first byte is 0x80 or greater, the number is considered negative
60 + // Therefore we add a '00' prefix if the 0x80 bit is set
61 + if (0x80 & first) {
62 + str = '00' + str;
63 + }
64 +
65 + return Any('02', str);
66 +};
67 +
68 +// The Bit String type also has a special rule
69 +ASN1.BitStr = function BITSTR() {
70 + var str = Array.prototype.slice.call(arguments).join('');
71 + // '00' is a mask of how many bits of the next byte to ignore
72 + return Any('03', '00' + str);
73 +};
74 +
75 +ASN1._toArray = function toArray(next, opts) {
76 + var typ = opts.json ? Enc.numToHex(next.type) : next.type;
77 + var val = next.value;
78 + if (val) {
79 + if ('string' !== typeof val && opts.json) {
80 + val = Enc.bufToHex(val);
81 + }
82 + return [typ, val];
83 + }
84 + return [
85 + typ,
86 + next.children.map(function(child) {
87 + return toArray(child, opts);
88 + })
89 + ];
90 +};
91 +
92 +ASN1._pack = function(arr) {
93 + var typ = arr[0];
94 + if ('number' === typeof arr[0]) {
95 + typ = Enc.numToHex(arr[0]);
96 + }
97 + var str = '';
98 + if (Array.isArray(arr[1])) {
99 + arr[1].forEach(function(a) {
100 + str += ASN1._pack(a);
101 + });
102 + } else if ('string' === typeof arr[1]) {
103 + str = arr[1];
104 + } else if (arr[1].byteLength) {
105 + str = Enc.bufToHex(arr[1]);
106 + } else {
107 + throw new Error('unexpected array');
108 + }
109 + if ('03' === typ) {
110 + return ASN1.BitStr(str);
111 + } else if ('02' === typ) {
112 + return ASN1.UInt(str);
113 + } else {
114 + return Any(typ, str);
115 + }
116 +};
117 +
118 +// TODO should this return a buffer?
119 +ASN1.pack = function(asn1, opts) {
120 + if (!opts) {
121 + opts = {};
122 + }
123 + if (!Array.isArray(asn1)) {
124 + asn1 = ASN1._toArray(asn1, { json: true });
125 + }
126 + var result = ASN1._pack(asn1);
127 + if (opts.json) {
128 + return result;
129 + }
130 + return Enc.hexToBuf(result);
131 +};
1 +// Copyright 2018 AJ ONeal. All rights reserved
2 +/* This Source Code Form is subject to the terms of the Mozilla Public
3 + * License, v. 2.0. If a copy of the MPL was not distributed with this
4 + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
5 +'use strict';
6 +
7 +var ASN1 = module.exports;
8 +var Enc = require('@root/encoding/hex');
9 +
10 +//
11 +// Parser
12 +//
13 +
14 +// Although I've only seen 9 max in https certificates themselves,
15 +// but each domain list could have up to 100
16 +ASN1.ELOOPN = 102;
17 +ASN1.ELOOP =
18 + 'uASN1.js Error: iterated over ' +
19 + ASN1.ELOOPN +
20 + '+ elements (probably a malformed file)';
21 +// I've seen https certificates go 29 deep
22 +ASN1.EDEEPN = 60;
23 +ASN1.EDEEP =
24 + 'uASN1.js Error: element nested ' +
25 + ASN1.EDEEPN +
26 + '+ layers deep (probably a malformed file)';
27 +// Container Types are Sequence 0x30, Container Array? (0xA0, 0xA1)
28 +// Value Types are Boolean 0x01, Integer 0x02, Null 0x05, Object ID 0x06, String 0x0C, 0x16, 0x13, 0x1e Value Array? (0x82)
29 +// Bit String (0x03) and Octet String (0x04) may be values or containers
30 +// Sometimes Bit String is used as a container (RSA Pub Spki)
31 +ASN1.CTYPES = [0x30, 0x31, 0xa0, 0xa1];
32 +ASN1.VTYPES = [0x01, 0x02, 0x05, 0x06, 0x0c, 0x82];
33 +ASN1.parseVerbose = function parseAsn1Helper(buf, opts) {
34 + if (!opts) {
35 + opts = {};
36 + }
37 + //var ws = ' ';
38 + function parseAsn1(buf, depth, eager) {
39 + if (depth.length >= ASN1.EDEEPN) {
40 + throw new Error(ASN1.EDEEP);
41 + }
42 +
43 + var index = 2; // we know, at minimum, data starts after type (0) and lengthSize (1)
44 + var asn1 = { type: buf[0], lengthSize: 0, length: buf[1] };
45 + var child;
46 + var iters = 0;
47 + var adjust = 0;
48 + var adjustedLen;
49 +
50 + // Determine how many bytes the length uses, and what it is
51 + if (0x80 & asn1.length) {
52 + asn1.lengthSize = 0x7f & asn1.length;
53 + // I think that buf->hex->int solves the problem of Endianness... not sure
54 + asn1.length = parseInt(
55 + Enc.bufToHex(buf.slice(index, index + asn1.lengthSize)),
56 + 16
57 + );
58 + index += asn1.lengthSize;
59 + }
60 +
61 + // High-order bit Integers have a leading 0x00 to signify that they are positive.
62 + // Bit Streams use the first byte to signify padding, which x.509 doesn't use.
63 + if (0x00 === buf[index] && (0x02 === asn1.type || 0x03 === asn1.type)) {
64 + // However, 0x00 on its own is a valid number
65 + if (asn1.length > 1) {
66 + index += 1;
67 + adjust = -1;
68 + }
69 + }
70 + adjustedLen = asn1.length + adjust;
71 +
72 + //console.warn(depth.join(ws) + '0x' + Enc.numToHex(asn1.type), index, 'len:', asn1.length, asn1);
73 +
74 + function parseChildren(eager) {
75 + asn1.children = [];
76 + //console.warn('1 len:', (2 + asn1.lengthSize + asn1.length), 'idx:', index, 'clen:', 0);
77 + while (
78 + iters < ASN1.ELOOPN &&
79 + index < 2 + asn1.length + asn1.lengthSize
80 + ) {
81 + iters += 1;
82 + depth.length += 1;
83 + child = parseAsn1(
84 + buf.slice(index, index + adjustedLen),
85 + depth,
86 + eager
87 + );
88 + depth.length -= 1;
89 + // The numbers don't match up exactly and I don't remember why...
90 + // probably something with adjustedLen or some such, but the tests pass
91 + index += 2 + child.lengthSize + child.length;
92 + //console.warn('2 len:', (2 + asn1.lengthSize + asn1.length), 'idx:', index, 'clen:', (2 + child.lengthSize + child.length));
93 + if (index > 2 + asn1.lengthSize + asn1.length) {
94 + if (!eager) {
95 + console.error(JSON.stringify(asn1, ASN1._replacer, 2));
96 + }
97 + throw new Error(
98 + 'Parse error: child value length (' +
99 + child.length +
100 + ') is greater than remaining parent length (' +
101 + (asn1.length - index) +
102 + ' = ' +
103 + asn1.length +
104 + ' - ' +
105 + index +
106 + ')'
107 + );
108 + }
109 + asn1.children.push(child);
110 + //console.warn(depth.join(ws) + '0x' + Enc.numToHex(asn1.type), index, 'len:', asn1.length, asn1);
111 + }
112 + if (index !== 2 + asn1.lengthSize + asn1.length) {
113 + //console.warn('index:', index, 'length:', (2 + asn1.lengthSize + asn1.length));
114 + throw new Error('premature end-of-file');
115 + }
116 + if (iters >= ASN1.ELOOPN) {
117 + throw new Error(ASN1.ELOOP);
118 + }
119 +
120 + delete asn1.value;
121 + return asn1;
122 + }
123 +
124 + // Recurse into types that are _always_ containers
125 + if (-1 !== ASN1.CTYPES.indexOf(asn1.type)) {
126 + return parseChildren(eager);
127 + }
128 +
129 + // Return types that are _always_ values
130 + asn1.value = buf.slice(index, index + adjustedLen);
131 + if (opts.json) {
132 + asn1.value = Enc.bufToHex(asn1.value);
133 + }
134 + if (-1 !== ASN1.VTYPES.indexOf(asn1.type)) {
135 + return asn1;
136 + }
137 +
138 + // For ambigious / unknown types, recurse and return on failure
139 + // (and return child array size to zero)
140 + try {
141 + return parseChildren(true);
142 + } catch (e) {
143 + asn1.children.length = 0;
144 + return asn1;
145 + }
146 + }
147 +
148 + var asn1 = parseAsn1(buf, []);
149 + var len = buf.byteLength || buf.length;
150 + if (len !== 2 + asn1.lengthSize + asn1.length) {
151 + throw new Error(
152 + 'Length of buffer does not match length of ASN.1 sequence.'
153 + );
154 + }
155 + return asn1;
156 +};
157 +ASN1._toArray = function toArray(next, opts) {
158 + var typ = opts.json ? Enc.numToHex(next.type) : next.type;
159 + var val = next.value;
160 + if (val) {
161 + if ('string' !== typeof val && opts.json) {
162 + val = Enc.bufToHex(val);
163 + }
164 + return [typ, val];
165 + }
166 + return [
167 + typ,
168 + next.children.map(function(child) {
169 + return toArray(child, opts);
170 + })
171 + ];
172 +};
173 +ASN1.parse = function(opts) {
174 + var opts2 = { json: false !== opts.json };
175 + var verbose = ASN1.parseVerbose(opts.der, opts2);
176 + if (opts.verbose) {
177 + return verbose;
178 + }
179 + return ASN1._toArray(verbose, opts2);
180 +};
181 +ASN1._replacer = function(k, v) {
182 + if ('type' === k) {
183 + return '0x' + Enc.numToHex(v);
184 + }
185 + if (v && 'value' === k) {
186 + return '0x' + Enc.bufToHex(v.data || v);
187 + }
188 + return v;
189 +};
This diff is collapsed. Click to expand it.
1 +# @root/csr
2 +
3 +Lightweight, Zero-Dependency CSR (Certificate Signing Request) generator and parser for Node.js and Browsers
4 +
5 +# Usage
6 +
7 +```js
8 +var CSR = require('@root/csr');
9 +var PEM = require('@root/pem/packer');
10 +
11 +CSR.csr({
12 + jwk: jwk,
13 + domains: ['example.com', '*.example.com', 'foo.bar.example.com'],
14 + encoding: 'pem'
15 +}).then(function(der) {
16 + var csr = PEM.packBlock({ type: 'CERTIFICATE REQUEST', bytes: der });
17 + console.log(csr);
18 +});
19 +```
20 +
21 +```txt
22 +-----BEGIN CERTIFICATE REQUEST-----
23 +MIIBHjCBxQIBADAWMRQwEgYDVQQDDAtleGFtcGxlLmNvbTBZMBMGByqGSM49AgEG
24 +CCqGSM49AwEHA0IABFL897BlwE6Tmco/r7LpwVL2BdDx12zZr+BnA/0/PjkI0lsu
25 +013u1+X5fe6vKnOIjcb5obaFnSQixuMGu3qcVnmgTTBLBgkqhkiG9w0BCQ4xPjA8
26 +MDoGA1UdEQQzMDGCC2V4YW1wbGUuY29tgg0qLmV4YW1wbGUuY29tghNmb28uYmFy
27 +LmV4YW1wbGUuY29tMAoGCCqGSM49BAMCA0gAMEUCIADRCWsMYBjm70Hqi08QrOcR
28 +Gcz8uJTe7vZwqOGtykWiAiEA1FTbMskZR9w2ugFWXkWfBdb1W6cD2v6nK+J0wj2r
29 +Q48=
30 +-----END CERTIFICATE REQUEST-----
31 +```
32 +
33 +# Advanced Usage
34 +
35 +Create an unsigned request
36 +
37 +```
38 +var CSR = require('@root/csr');
39 +
40 +// Note: this requires the public key to embed it in the request
41 +var hex = CSR.request({
42 + jwk: jwk,
43 + domains: ['example.com', '*.example.com', 'foo.bar.example.com'],
44 + encoding: 'hex'
45 +})
46 +```
1 +// Copyright 2018-present AJ ONeal. All rights reserved
2 +/* This Source Code Form is subject to the terms of the Mozilla Public
3 + * License, v. 2.0. If a copy of the MPL was not distributed with this
4 + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
5 +'use strict';
6 +/*global Promise*/
7 +
8 +var Enc = require('@root/encoding');
9 +
10 +var ASN1 = require('@root/asn1/packer'); // DER, actually
11 +var Asn1 = ASN1.Any;
12 +var BitStr = ASN1.BitStr;
13 +var UInt = ASN1.UInt;
14 +var Asn1Parser = require('@root/asn1/parser');
15 +var PEM = require('@root/pem');
16 +var X509 = require('@root/x509');
17 +// TODO @root/keypairs/sign
18 +var Keypairs = require('@root/keypairs');
19 +
20 +// TODO find a way that the prior node-ish way of `module.exports = function () {}` isn't broken
21 +var CSR = module.exports;
22 +
23 +// { jwk, domains }
24 +CSR.csr = function(opts) {
25 + // We're using a Promise here to be compatible with the browser version
26 + // which will probably use the webcrypto API for some of the conversions
27 + return CSR._prepare(opts).then(function(opts) {
28 + return CSR.create(opts).then(function(bytes) {
29 + return CSR._encode(opts, bytes);
30 + });
31 + });
32 +};
33 +
34 +CSR._prepare = function(opts) {
35 + return Promise.resolve().then(function() {
36 + opts = JSON.parse(JSON.stringify(opts));
37 +
38 + // We do a bit of extra error checking for user convenience
39 + if (!opts) {
40 + throw new Error(
41 + 'You must pass options with key and domains to rsacsr'
42 + );
43 + }
44 + if (!Array.isArray(opts.domains) || 0 === opts.domains.length) {
45 + new Error('You must pass options.domains as a non-empty array');
46 + }
47 +
48 + // I need to check that 例.中国 is a valid domain name
49 + if (
50 + !opts.domains.every(function(d) {
51 + // allow punycode? xn--
52 + if (
53 + 'string' === typeof d /*&& /\./.test(d) && !/--/.test(d)*/
54 + ) {
55 + return true;
56 + }
57 + })
58 + ) {
59 + throw new Error('You must pass options.domains as strings');
60 + }
61 +
62 + if (opts.jwk) {
63 + return opts;
64 + }
65 + if (opts.key && opts.key.kty) {
66 + opts.jwk = opts.key;
67 + return opts;
68 + }
69 + if (!opts.pem && !opts.key) {
70 + throw new Error('You must pass options.key as a JSON web key');
71 + }
72 +
73 + return Keypairs.import({ pem: opts.pem || opts.key }).then(function(
74 + pair
75 + ) {
76 + opts.jwk = pair.private;
77 + return opts;
78 + });
79 + });
80 +};
81 +
82 +CSR._encode = function(opts, bytes) {
83 + if ('der' === (opts.encoding || '').toLowerCase()) {
84 + return bytes;
85 + }
86 + return PEM.packBlock({
87 + type: 'CERTIFICATE REQUEST',
88 + bytes: bytes /* { jwk: jwk, domains: opts.domains } */
89 + });
90 +};
91 +
92 +// { jwk, domains }
93 +CSR.create = function createCsr(opts) {
94 + var hex = CSR.request({
95 + jwk: opts.jwk,
96 + domains: opts.domains,
97 + encoding: 'hex'
98 + });
99 + return CSR._sign(opts.jwk, hex).then(function(csr) {
100 + return Enc.hexToBuf(csr);
101 + });
102 +};
103 +
104 +//
105 +// EC / RSA
106 +//
107 +// { jwk, domains }
108 +CSR.request = function createCsrBody(opts) {
109 + var asn1pub;
110 + if (/^EC/i.test(opts.jwk.kty)) {
111 + asn1pub = X509.packCsrEcPublicKey(opts.jwk);
112 + } else {
113 + asn1pub = X509.packCsrRsaPublicKey(opts.jwk);
114 + }
115 + var hex = X509.packCsr(asn1pub, opts.domains);
116 + if ('hex' === opts.encoding) {
117 + return hex;
118 + }
119 + // der
120 + return Enc.hexToBuf(hex);
121 +};
122 +
123 +CSR._sign = function csrEcSig(jwk, request) {
124 + // Took some tips from https://gist.github.com/codermapuche/da4f96cdb6d5ff53b7ebc156ec46a10a
125 + // TODO will have to convert web ECDSA signatures to PEM ECDSA signatures (but RSA should be the same)
126 + // TODO have a consistent non-private way to sign
127 + return Keypairs.sign(
128 + { jwk: jwk, format: 'x509' },
129 + Enc.hexToBuf(request)
130 + ).then(function(sig) {
131 + return CSR._toDer({
132 + request: request,
133 + signature: sig,
134 + kty: jwk.kty
135 + });
136 + });
137 +};
138 +
139 +CSR._toDer = function encode(opts) {
140 + var sty;
141 + if (/^EC/i.test(opts.kty)) {
142 + // 1.2.840.10045.4.3.2 ecdsaWithSHA256 (ANSI X9.62 ECDSA algorithm with SHA256)
143 + sty = Asn1('30', Asn1('06', '2a8648ce3d040302'));
144 + } else {
145 + // 1.2.840.113549.1.1.11 sha256WithRSAEncryption (PKCS #1)
146 + sty = Asn1('30', Asn1('06', '2a864886f70d01010b'), Asn1('05'));
147 + }
148 + return Asn1(
149 + '30',
150 + // The Full CSR Request Body
151 + opts.request,
152 + // The Signature Type
153 + sty,
154 + // The Signature
155 + BitStr(Enc.bufToHex(opts.signature))
156 + );
157 +};
158 +
159 +X509.packCsr = function(asn1pubkey, domains) {
160 + return Asn1(
161 + '30',
162 + // Version (0)
163 + UInt('00'),
164 +
165 + // 2.5.4.3 commonName (X.520 DN component)
166 + Asn1(
167 + '30',
168 + Asn1(
169 + '31',
170 + Asn1(
171 + '30',
172 + Asn1('06', '550403'),
173 + // TODO utf8 => punycode
174 + Asn1('0c', Enc.strToHex(domains[0]))
175 + )
176 + )
177 + ),
178 +
179 + // Public Key (RSA or EC)
180 + asn1pubkey,
181 +
182 + // Request Body
183 + Asn1(
184 + 'a0',
185 + Asn1(
186 + '30',
187 + // 1.2.840.113549.1.9.14 extensionRequest (PKCS #9 via CRMF)
188 + Asn1('06', '2a864886f70d01090e'),
189 + Asn1(
190 + '31',
191 + Asn1(
192 + '30',
193 + Asn1(
194 + '30',
195 + // 2.5.29.17 subjectAltName (X.509 extension)
196 + Asn1('06', '551d11'),
197 + Asn1(
198 + '04',
199 + Asn1(
200 + '30',
201 + domains
202 + .map(function(d) {
203 + // TODO utf8 => punycode
204 + return Asn1('82', Enc.strToHex(d));
205 + })
206 + .join('')
207 + )
208 + )
209 + )
210 + )
211 + )
212 + )
213 + )
214 + );
215 +};
216 +
217 +// TODO finish this later
218 +// we want to parse the domains, the public key, and verify the signature
219 +CSR._info = function(der) {
220 + // standard base64 PEM
221 + if ('string' === typeof der && '-' === der[0]) {
222 + der = PEM.parseBlock(der).bytes;
223 + }
224 + // jose urlBase64 not-PEM
225 + if ('string' === typeof der) {
226 + der = Enc.base64ToBuf(der);
227 + }
228 + // not supporting binary-encoded base64
229 + var c = Asn1Parser.parse({ der: der, verbose: true, json: false });
230 + var kty;
231 + // A cert has 3 parts: cert, signature meta, signature
232 + if (c.children.length !== 3) {
233 + throw new Error(
234 + "doesn't look like a certificate request: expected 3 parts of header"
235 + );
236 + }
237 + var sig = c.children[2];
238 + if (sig.children.length) {
239 + // ASN1/X509 EC
240 + sig = sig.children[0];
241 + sig = Asn1(
242 + '30',
243 + UInt(Enc.bufToHex(sig.children[0].value)),
244 + UInt(Enc.bufToHex(sig.children[1].value))
245 + );
246 + sig = Enc.hexToBuf(sig);
247 + kty = 'EC';
248 + } else {
249 + // Raw RSA Sig
250 + sig = sig.value;
251 + kty = 'RSA';
252 + }
253 + //c.children[1]; // signature type
254 + var req = c.children[0];
255 + if (4 !== req.children.length) {
256 + throw new Error(
257 + "doesn't look like a certificate request: expected 4 parts to request"
258 + );
259 + }
260 + // 0 null
261 + // 1 commonName / subject
262 + var sub = Enc.bufToStr(
263 + req.children[1].children[0].children[0].children[1].value
264 + );
265 + // 3 public key (type, key)
266 + //console.log('oid', Enc.bufToHex(req.children[2].children[0].children[0].value));
267 + var pub;
268 + // TODO reuse ASN1 parser for these?
269 + if ('EC' === kty) {
270 + // throw away compression byte
271 + pub = req.children[2].children[1].value.slice(1);
272 + pub = { kty: kty, x: pub.slice(0, 32), y: pub.slice(32) };
273 + while (0 === pub.x[0]) {
274 + pub.x = pub.x.slice(1);
275 + }
276 + while (0 === pub.y[0]) {
277 + pub.y = pub.y.slice(1);
278 + }
279 + if ((pub.x.length || pub.x.byteLength) > 48) {
280 + pub.crv = 'P-521';
281 + } else if ((pub.x.length || pub.x.byteLength) > 32) {
282 + pub.crv = 'P-384';
283 + } else {
284 + pub.crv = 'P-256';
285 + }
286 + pub.x = Enc.bufToUrlBase64(pub.x);
287 + pub.y = Enc.bufToUrlBase64(pub.y);
288 + } else {
289 + pub = req.children[2].children[1].children[0];
290 + pub = {
291 + kty: kty,
292 + n: pub.children[0].value,
293 + e: pub.children[1].value
294 + };
295 + while (0 === pub.n[0]) {
296 + pub.n = pub.n.slice(1);
297 + }
298 + while (0 === pub.e[0]) {
299 + pub.e = pub.e.slice(1);
300 + }
301 + pub.n = Enc.bufToUrlBase64(pub.n);
302 + pub.e = Enc.bufToUrlBase64(pub.e);
303 + }
304 + // 4 extensions
305 + var domains = req.children[3].children
306 + .filter(function(seq) {
307 + // 1.2.840.113549.1.9.14 extensionRequest (PKCS #9 via CRMF)
308 + if ('2a864886f70d01090e' === Enc.bufToHex(seq.children[0].value)) {
309 + return true;
310 + }
311 + })
312 + .map(function(seq) {
313 + return seq.children[1].children[0].children
314 + .filter(function(seq2) {
315 + // subjectAltName (X.509 extension)
316 + if ('551d11' === Enc.bufToHex(seq2.children[0].value)) {
317 + return true;
318 + }
319 + })
320 + .map(function(seq2) {
321 + return seq2.children[1].children[0].children.map(function(
322 + name
323 + ) {
324 + // TODO utf8 => punycode
325 + return Enc.bufToStr(name.value);
326 + });
327 + })[0];
328 + })[0];
329 +
330 + return {
331 + subject: sub,
332 + altnames: domains,
333 + jwk: pub,
334 + signature: sig
335 + };
336 +};
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
No preview for this file type
1 +;(function () {
2 +'use strict';
3 +var CSR = window.CSR = {};
4 +var Enc = window.Encoding;
5 +var X509 = window.X509;
6 +var Keypairs = window.Keypairs;
7 +var ASN1 = window.ASN1;
8 +var PEM = window.PEM;
9 +var Asn1Packer = window.ASN1;
10 +// Copyright 2018-present AJ ONeal. All rights reserved
11 +/* This Source Code Form is subject to the terms of the Mozilla Public
12 + * License, v. 2.0. If a copy of the MPL was not distributed with this
13 + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
14 +/*global Promise*/
15 +
16 +
17 +var Asn1 = ASN1.Any;
18 +var BitStr = ASN1.BitStr;
19 +var UInt = ASN1.UInt;
20 +// TODO @root/keypairs/sign
21 +
22 +
23 +// { jwk, domains }
24 +CSR.csr = function(opts) {
25 + // We're using a Promise here to be compatible with the browser version
26 + // which will probably use the webcrypto API for some of the conversions
27 + return CSR._prepare(opts).then(function(opts) {
28 + return CSR.create(opts).then(function(bytes) {
29 + return CSR._encode(opts, bytes);
30 + });
31 + });
32 +};
33 +
34 +CSR._prepare = function(opts) {
35 + return Promise.resolve().then(function() {
36 + opts = JSON.parse(JSON.stringify(opts));
37 +
38 + // We do a bit of extra error checking for user convenience
39 + if (!opts) {
40 + throw new Error(
41 + 'You must pass options with key and domains to rsacsr'
42 + );
43 + }
44 + if (!Array.isArray(opts.domains) || 0 === opts.domains.length) {
45 + new Error('You must pass options.domains as a non-empty array');
46 + }
47 +
48 + // I need to check that 例.中国 is a valid domain name
49 + if (
50 + !opts.domains.every(function(d) {
51 + // allow punycode? xn--
52 + if (
53 + 'string' === typeof d /*&& /\./.test(d) && !/--/.test(d)*/
54 + ) {
55 + return true;
56 + }
57 + })
58 + ) {
59 + throw new Error('You must pass options.domains as strings');
60 + }
61 +
62 + if (opts.jwk) {
63 + return opts;
64 + }
65 + if (opts.key && opts.key.kty) {
66 + opts.jwk = opts.key;
67 + return opts;
68 + }
69 + if (!opts.pem && !opts.key) {
70 + throw new Error('You must pass options.key as a JSON web key');
71 + }
72 +
73 + return Keypairs.import({ pem: opts.pem || opts.key }).then(function(
74 + pair
75 + ) {
76 + opts.jwk = pair.private;
77 + return opts;
78 + });
79 + });
80 +};
81 +
82 +CSR._encode = function(opts, bytes) {
83 + if ('der' === (opts.encoding || '').toLowerCase()) {
84 + return bytes;
85 + }
86 + return PEM.packBlock({
87 + type: 'CERTIFICATE REQUEST',
88 + bytes: bytes /* { jwk: jwk, domains: opts.domains } */
89 + });
90 +};
91 +
92 +// { jwk, domains }
93 +CSR.create = function createCsr(opts) {
94 + var hex = CSR.request({
95 + jwk: opts.jwk,
96 + domains: opts.domains,
97 + encoding: 'hex'
98 + });
99 + return CSR._sign(opts.jwk, hex).then(function(csr) {
100 + return Enc.hexToBuf(csr);
101 + });
102 +};
103 +
104 +//
105 +// EC / RSA
106 +//
107 +// { jwk, domains }
108 +CSR.request = function createCsrBody(opts) {
109 + var asn1pub;
110 + if (/^EC/i.test(opts.jwk.kty)) {
111 + asn1pub = X509.packCsrEcPublicKey(opts.jwk);
112 + } else {
113 + asn1pub = X509.packCsrRsaPublicKey(opts.jwk);
114 + }
115 + var hex = X509.packCsr(asn1pub, opts.domains);
116 + if ('hex' === opts.encoding) {
117 + return hex;
118 + }
119 + // der
120 + return Enc.hexToBuf(hex);
121 +};
122 +
123 +CSR._sign = function csrEcSig(jwk, request) {
124 + // Took some tips from https://gist.github.com/codermapuche/da4f96cdb6d5ff53b7ebc156ec46a10a
125 + // TODO will have to convert web ECDSA signatures to PEM ECDSA signatures (but RSA should be the same)
126 + // TODO have a consistent non-private way to sign
127 + return Keypairs.sign(
128 + { jwk: jwk, format: 'x509' },
129 + Enc.hexToBuf(request)
130 + ).then(function(sig) {
131 + return CSR._toDer({
132 + request: request,
133 + signature: sig,
134 + kty: jwk.kty
135 + });
136 + });
137 +};
138 +
139 +CSR._toDer = function encode(opts) {
140 + var sty;
141 + if (/^EC/i.test(opts.kty)) {
142 + // 1.2.840.10045.4.3.2 ecdsaWithSHA256 (ANSI X9.62 ECDSA algorithm with SHA256)
143 + sty = Asn1('30', Asn1('06', '2a8648ce3d040302'));
144 + } else {
145 + // 1.2.840.113549.1.1.11 sha256WithRSAEncryption (PKCS #1)
146 + sty = Asn1('30', Asn1('06', '2a864886f70d01010b'), Asn1('05'));
147 + }
148 + return Asn1(
149 + '30',
150 + // The Full CSR Request Body
151 + opts.request,
152 + // The Signature Type
153 + sty,
154 + // The Signature
155 + BitStr(Enc.bufToHex(opts.signature))
156 + );
157 +};
158 +
159 +X509.packCsr = function(asn1pubkey, domains) {
160 + return Asn1(
161 + '30',
162 + // Version (0)
163 + UInt('00'),
164 +
165 + // 2.5.4.3 commonName (X.520 DN component)
166 + Asn1(
167 + '30',
168 + Asn1(
169 + '31',
170 + Asn1(
171 + '30',
172 + Asn1('06', '550403'),
173 + // TODO utf8 => punycode
174 + Asn1('0c', Enc.strToHex(domains[0]))
175 + )
176 + )
177 + ),
178 +
179 + // Public Key (RSA or EC)
180 + asn1pubkey,
181 +
182 + // Request Body
183 + Asn1(
184 + 'a0',
185 + Asn1(
186 + '30',
187 + // 1.2.840.113549.1.9.14 extensionRequest (PKCS #9 via CRMF)
188 + Asn1('06', '2a864886f70d01090e'),
189 + Asn1(
190 + '31',
191 + Asn1(
192 + '30',
193 + Asn1(
194 + '30',
195 + // 2.5.29.17 subjectAltName (X.509 extension)
196 + Asn1('06', '551d11'),
197 + Asn1(
198 + '04',
199 + Asn1(
200 + '30',
201 + domains
202 + .map(function(d) {
203 + // TODO utf8 => punycode
204 + return Asn1('82', Enc.strToHex(d));
205 + })
206 + .join('')
207 + )
208 + )
209 + )
210 + )
211 + )
212 + )
213 + )
214 + );
215 +};
216 +
217 +// TODO finish this later
218 +// we want to parse the domains, the public key, and verify the signature
219 +CSR._info = function(der) {
220 + // standard base64 PEM
221 + if ('string' === typeof der && '-' === der[0]) {
222 + der = PEM.parseBlock(der).bytes;
223 + }
224 + // jose urlBase64 not-PEM
225 + if ('string' === typeof der) {
226 + der = Enc.base64ToBuf(der);
227 + }
228 + // not supporting binary-encoded base64
229 + var c = Asn1Parser.parse({ der: der, verbose: true, json: false });
230 + var kty;
231 + // A cert has 3 parts: cert, signature meta, signature
232 + if (c.children.length !== 3) {
233 + throw new Error(
234 + "doesn't look like a certificate request: expected 3 parts of header"
235 + );
236 + }
237 + var sig = c.children[2];
238 + if (sig.children.length) {
239 + // ASN1/X509 EC
240 + sig = sig.children[0];
241 + sig = Asn1(
242 + '30',
243 + UInt(Enc.bufToHex(sig.children[0].value)),
244 + UInt(Enc.bufToHex(sig.children[1].value))
245 + );
246 + sig = Enc.hexToBuf(sig);
247 + kty = 'EC';
248 + } else {
249 + // Raw RSA Sig
250 + sig = sig.value;
251 + kty = 'RSA';
252 + }
253 + //c.children[1]; // signature type
254 + var req = c.children[0];
255 + if (4 !== req.children.length) {
256 + throw new Error(
257 + "doesn't look like a certificate request: expected 4 parts to request"
258 + );
259 + }
260 + // 0 null
261 + // 1 commonName / subject
262 + var sub = Enc.bufToStr(
263 + req.children[1].children[0].children[0].children[1].value
264 + );
265 + // 3 public key (type, key)
266 + //console.log('oid', Enc.bufToHex(req.children[2].children[0].children[0].value));
267 + var pub;
268 + // TODO reuse ASN1 parser for these?
269 + if ('EC' === kty) {
270 + // throw away compression byte
271 + pub = req.children[2].children[1].value.slice(1);
272 + pub = { kty: kty, x: pub.slice(0, 32), y: pub.slice(32) };
273 + while (0 === pub.x[0]) {
274 + pub.x = pub.x.slice(1);
275 + }
276 + while (0 === pub.y[0]) {
277 + pub.y = pub.y.slice(1);
278 + }
279 + if ((pub.x.length || pub.x.byteLength) > 48) {
280 + pub.crv = 'P-521';
281 + } else if ((pub.x.length || pub.x.byteLength) > 32) {
282 + pub.crv = 'P-384';
283 + } else {
284 + pub.crv = 'P-256';
285 + }
286 + pub.x = Enc.bufToUrlBase64(pub.x);
287 + pub.y = Enc.bufToUrlBase64(pub.y);
288 + } else {
289 + pub = req.children[2].children[1].children[0];
290 + pub = {
291 + kty: kty,
292 + n: pub.children[0].value,
293 + e: pub.children[1].value
294 + };
295 + while (0 === pub.n[0]) {
296 + pub.n = pub.n.slice(1);
297 + }
298 + while (0 === pub.e[0]) {
299 + pub.e = pub.e.slice(1);
300 + }
301 + pub.n = Enc.bufToUrlBase64(pub.n);
302 + pub.e = Enc.bufToUrlBase64(pub.e);
303 + }
304 + // 4 extensions
305 + var domains = req.children[3].children
306 + .filter(function(seq) {
307 + // 1.2.840.113549.1.9.14 extensionRequest (PKCS #9 via CRMF)
308 + if ('2a864886f70d01090e' === Enc.bufToHex(seq.children[0].value)) {
309 + return true;
310 + }
311 + })
312 + .map(function(seq) {
313 + return seq.children[1].children[0].children
314 + .filter(function(seq2) {
315 + // subjectAltName (X.509 extension)
316 + if ('551d11' === Enc.bufToHex(seq2.children[0].value)) {
317 + return true;
318 + }
319 + })
320 + .map(function(seq2) {
321 + return seq2.children[1].children[0].children.map(function(
322 + name
323 + ) {
324 + // TODO utf8 => punycode
325 + return Enc.bufToStr(name.value);
326 + });
327 + })[0];
328 + })[0];
329 +
330 + return {
331 + subject: sub,
332 + altnames: domains,
333 + jwk: pub,
334 + signature: sig
335 + };
336 +};
337 +}());
1 +(function(){"use strict";var CSR=window.CSR={};var Enc=window.Encoding;var X509=window.X509;var Keypairs=window.Keypairs;var ASN1=window.ASN1;var PEM=window.PEM;var Asn1Packer=window.ASN1;var Asn1=ASN1.Any;var BitStr=ASN1.BitStr;var UInt=ASN1.UInt;CSR.csr=function(opts){return CSR._prepare(opts).then(function(opts){return CSR.create(opts).then(function(bytes){return CSR._encode(opts,bytes)})})};CSR._prepare=function(opts){return Promise.resolve().then(function(){opts=JSON.parse(JSON.stringify(opts));if(!opts){throw new Error("You must pass options with key and domains to rsacsr")}if(!Array.isArray(opts.domains)||0===opts.domains.length){new Error("You must pass options.domains as a non-empty array")}if(!opts.domains.every(function(d){if("string"===typeof d){return true}})){throw new Error("You must pass options.domains as strings")}if(opts.jwk){return opts}if(opts.key&&opts.key.kty){opts.jwk=opts.key;return opts}if(!opts.pem&&!opts.key){throw new Error("You must pass options.key as a JSON web key")}return Keypairs.import({pem:opts.pem||opts.key}).then(function(pair){opts.jwk=pair.private;return opts})})};CSR._encode=function(opts,bytes){if("der"===(opts.encoding||"").toLowerCase()){return bytes}return PEM.packBlock({type:"CERTIFICATE REQUEST",bytes:bytes})};CSR.create=function createCsr(opts){var hex=CSR.request({jwk:opts.jwk,domains:opts.domains,encoding:"hex"});return CSR._sign(opts.jwk,hex).then(function(csr){return Enc.hexToBuf(csr)})};CSR.request=function createCsrBody(opts){var asn1pub;if(/^EC/i.test(opts.jwk.kty)){asn1pub=X509.packCsrEcPublicKey(opts.jwk)}else{asn1pub=X509.packCsrRsaPublicKey(opts.jwk)}var hex=X509.packCsr(asn1pub,opts.domains);if("hex"===opts.encoding){return hex}return Enc.hexToBuf(hex)};CSR._sign=function csrEcSig(jwk,request){return Keypairs.sign({jwk:jwk,format:"x509"},Enc.hexToBuf(request)).then(function(sig){return CSR._toDer({request:request,signature:sig,kty:jwk.kty})})};CSR._toDer=function encode(opts){var sty;if(/^EC/i.test(opts.kty)){sty=Asn1("30",Asn1("06","2a8648ce3d040302"))}else{sty=Asn1("30",Asn1("06","2a864886f70d01010b"),Asn1("05"))}return Asn1("30",opts.request,sty,BitStr(Enc.bufToHex(opts.signature)))};X509.packCsr=function(asn1pubkey,domains){return Asn1("30",UInt("00"),Asn1("30",Asn1("31",Asn1("30",Asn1("06","550403"),Asn1("0c",Enc.strToHex(domains[0]))))),asn1pubkey,Asn1("a0",Asn1("30",Asn1("06","2a864886f70d01090e"),Asn1("31",Asn1("30",Asn1("30",Asn1("06","551d11"),Asn1("04",Asn1("30",domains.map(function(d){return Asn1("82",Enc.strToHex(d))}).join("")))))))))};CSR._info=function(der){if("string"===typeof der&&"-"===der[0]){der=PEM.parseBlock(der).bytes}if("string"===typeof der){der=Enc.base64ToBuf(der)}var c=Asn1Parser.parse({der:der,verbose:true,json:false});var kty;if(c.children.length!==3){throw new Error("doesn't look like a certificate request: expected 3 parts of header")}var sig=c.children[2];if(sig.children.length){sig=sig.children[0];sig=Asn1("30",UInt(Enc.bufToHex(sig.children[0].value)),UInt(Enc.bufToHex(sig.children[1].value)));sig=Enc.hexToBuf(sig);kty="EC"}else{sig=sig.value;kty="RSA"}var req=c.children[0];if(4!==req.children.length){throw new Error("doesn't look like a certificate request: expected 4 parts to request")}var sub=Enc.bufToStr(req.children[1].children[0].children[0].children[1].value);var pub;if("EC"===kty){pub=req.children[2].children[1].value.slice(1);pub={kty:kty,x:pub.slice(0,32),y:pub.slice(32)};while(0===pub.x[0]){pub.x=pub.x.slice(1)}while(0===pub.y[0]){pub.y=pub.y.slice(1)}if((pub.x.length||pub.x.byteLength)>48){pub.crv="P-521"}else if((pub.x.length||pub.x.byteLength)>32){pub.crv="P-384"}else{pub.crv="P-256"}pub.x=Enc.bufToUrlBase64(pub.x);pub.y=Enc.bufToUrlBase64(pub.y)}else{pub=req.children[2].children[1].children[0];pub={kty:kty,n:pub.children[0].value,e:pub.children[1].value};while(0===pub.n[0]){pub.n=pub.n.slice(1)}while(0===pub.e[0]){pub.e=pub.e.slice(1)}pub.n=Enc.bufToUrlBase64(pub.n);pub.e=Enc.bufToUrlBase64(pub.e)}var domains=req.children[3].children.filter(function(seq){if("2a864886f70d01090e"===Enc.bufToHex(seq.children[0].value)){return true}}).map(function(seq){return seq.children[1].children[0].children.filter(function(seq2){if("551d11"===Enc.bufToHex(seq2.children[0].value)){return true}}).map(function(seq2){return seq2.children[1].children[0].children.map(function(name){return Enc.bufToStr(name.value)})})[0]})[0];return{subject:sub,altnames:domains,jwk:pub,signature:sig}}})();
No preview for this file type
1 +{
2 + "_from": "@root/csr@^0.8.1",
3 + "_id": "@root/csr@0.8.1",
4 + "_inBundle": false,
5 + "_integrity": "sha512-hKl0VuE549TK6SnS2Yn9nRvKbFZXn/oAg+dZJU/tlKl/f/0yRXeuUzf8akg3JjtJq+9E592zDqeXZ7yyrg8fSQ==",
6 + "_location": "/@root/csr",
7 + "_phantomChildren": {},
8 + "_requested": {
9 + "type": "range",
10 + "registry": true,
11 + "raw": "@root/csr@^0.8.1",
12 + "name": "@root/csr",
13 + "escapedName": "@root%2fcsr",
14 + "scope": "@root",
15 + "rawSpec": "^0.8.1",
16 + "saveSpec": null,
17 + "fetchSpec": "^0.8.1"
18 + },
19 + "_requiredBy": [
20 + "/@root/greenlock"
21 + ],
22 + "_resolved": "https://registry.npmjs.org/@root/csr/-/csr-0.8.1.tgz",
23 + "_shasum": "97a1b821331a4ed5895eee33bedb6ad49cdef74e",
24 + "_spec": "@root/csr@^0.8.1",
25 + "_where": "C:\\Users\\USER\\Documents\\Desktop\\옵소팀플\\LINEBOT\\node_modules\\@root\\greenlock",
26 + "author": {
27 + "name": "AJ ONeal",
28 + "email": "coolaj86@gmail.com",
29 + "url": "https://coolaj86.com/"
30 + },
31 + "bundleDependencies": false,
32 + "dependencies": {
33 + "@root/asn1": "^1.0.0",
34 + "@root/pem": "^1.0.4",
35 + "@root/x509": "^0.7.2"
36 + },
37 + "deprecated": false,
38 + "description": "Lightweight, Zero-Dependency CSR (Certificate Signing Request) generator and parser for Node.js and Browsers",
39 + "devDependencies": {
40 + "@root/keypairs": "^0.9.0"
41 + },
42 + "files": [
43 + "*.js",
44 + "lib",
45 + "dist"
46 + ],
47 + "keywords": [
48 + "CSR",
49 + "ASN.1",
50 + "DER",
51 + "PEM",
52 + "x509",
53 + "RSA",
54 + "EC",
55 + "ECDSA",
56 + "letsencrypt",
57 + "ACME",
58 + "asn1"
59 + ],
60 + "license": "MPL-2.0",
61 + "main": "csr.js",
62 + "name": "@root/csr",
63 + "repository": {
64 + "type": "git",
65 + "url": "https://git.rootprojects.org/root/csr.js.git"
66 + },
67 + "scripts": {
68 + "test": "node tests"
69 + },
70 + "version": "0.8.1"
71 +}
This diff is collapsed. Click to expand it.
1 +# @root/encoding
2 +
3 +Lightweight, Zero-dependency, translation between Unicode Strings, Binary Strings, Buffers, Base64, Hex, UCS-2, UTF-8, etc.
4 +
5 +| < 1k gzipped | 2.6k minified | 3.6k full |
6 +
7 +Works identically on all platforms:
8 +
9 +- [x] Web Browsers
10 + - Chrome
11 + - Firefox
12 + - Microsoft Edge
13 + - Internet Explorer
14 +- [x] Node.js
15 +- [x] WebPack
16 +
17 +# Usage
18 +
19 +**Vanilla JS**
20 +
21 +```html
22 +<script src="https://unpkg.com/@root/encoding@1.0.0/dist/encoding.all.js"></script>
23 +```
24 +
25 +```html
26 +<script src="https://unpkg.com/@root/encoding@1.0.0/dist/encoding.all.min.js"></script>
27 +```
28 +
29 +```js
30 +var Enc = window.Encoding;
31 +
32 +Enc.strToBuf('Hello, 世界!');
33 +```
34 +
35 +**WebPack**, Node
36 +
37 +```js
38 +var Enc = require('@root/encoding');
39 +
40 +Enc.strToBuf('Hello, 世界!');
41 +```
42 +
43 +# Use cases
44 +
45 +Typically you want to use this in a browser when you need to convert user input to some sort
46 +of Byte Array for hashing or encoding in an ancient format.
47 +
48 +For example:
49 +
50 +- [x] Hashing passwords
51 +- [x] Secure Remote Password
52 +- [x] JWT and JWS signing and verifying
53 +- [x] ASN1 parsing and packing
54 + - [x] DER
55 + - [x] x509
56 + - [x] CSR
57 + - [x] PEM
58 +
59 +The purpose of this library is to make it easy to support common string and buffer encoding and decoding
60 +in both Browsers and node with minimal code.
61 +
62 +# Examples
63 +
64 +Strings and Byte Arrays
65 +
66 +```js
67 +var Enc = require('@root/encoding/bytes');
68 +
69 +Enc.binToStr(bin);
70 +Enc.binToBuf(bin);
71 +
72 +Enc.bufToBin(buf);
73 +Enc.bufToStr(buf);
74 +
75 +Enc.strToBin(str);
76 +Enc.strToBuf(str);
77 +```
78 +
79 +Hex
80 +
81 +```js
82 +var Enc = require('@root/encoding/hex');
83 +
84 +Enc.hexToBuf(hex);
85 +Enc.hexToStr(hex);
86 +
87 +Enc.bufToHex(buf);
88 +Enc.strToHex(str);
89 +```
90 +
91 +Base64
92 +
93 +```js
94 +var Enc = require('@root/encoding/base64');
95 +
96 +Enc.base64ToBuf(b64);
97 +Enc.base64ToStr(b64);
98 +
99 +Enc.bufToBase64(buf);
100 +Enc.strToBase64(str);
101 +```
102 +
103 +URL Safe Base64
104 +
105 +(all of `base64To*()` accept URL Safe Base64)
106 +
107 +```js
108 +var Enc = require('@root/encoding/base64');
109 +
110 +Enc.base64ToUrlBase64(b64);
111 +Enc.urlBase64ToBase64(u64);
112 +
113 +Enc.bufToUrlBase64(buf);
114 +Enc.strToUrlBase64(str);
115 +```
116 +
117 +Base64 and Hex
118 +
119 +```
120 +require('@root/encoding/base64');
121 +require('@root/encoding/hex');
122 +
123 +var Enc = require('@root/encoding');
124 +
125 +Enc.hexToBase64(hex);
126 +Enc.base64ToHex(b64);
127 +```
128 +
129 +# Browser API
130 +
131 +(the Node API signatures are the same, but implemented with `Buffer`)
132 +
133 +Conversions between these formats are supported:
134 +
135 +- Strings and Buffers
136 +- Hex
137 +- Base64
138 +
139 +## Strings and Buffers
140 +
141 +JavaScript has two types of strings:
142 +
143 +- _Binary Strings_, which we call `bin`
144 +- _Unicode Strings_, which we call `str` (USC-2, essentially UTF-16)
145 + - treated as UTF-8 for the purposes of `encodeURIComponent`
146 +
147 +JavaScript has two (and a half) ways to support Byte Arrays:
148 +
149 +- `Array`, which we call `arr`
150 +- `Uint8Array`, which we call `buf` (of the `ArrayBuffer` family)
151 +- `Buffer` (node-only, but implemented as `Uint8Array`)
152 +
153 +The API for the conversions is centered around `Uint8Array` (`Buffer`) but,
154 +for browser compatibility, sometimes requires the use of _Binary Strings_.
155 +
156 +**API**
157 +
158 +We provide conversions directly to each of the following:
159 +
160 +| Name | Type | Description |
161 +| :---- | :------------- | :-------------------------------------------- |
162 +| `str` | Unicode String | Handled by `split('')` as two-byte characters |
163 +| `bin` | Binary String | Handled by `split('')` as single-byte chars |
164 +| `buf` | Byte Array | Truncated to single-byte chars |
165 +
166 +The names and signatures of the functions are as follows:
167 +
168 +To Buffer
169 +
170 +- Binary String to Buffer
171 + - binToBuf(bin)
172 +- Unicode String (UTF-8) to Buffer
173 + - strToBuf(str)
174 +
175 +To Unicode String
176 +
177 +- Binary String to Unicode String (UTF-8)
178 + - binToStr(bin)
179 +- Buffer to Unicode String (UTF-8)
180 + - bufToStr(buf)
181 +
182 +To Binary String
183 +
184 +- Buffer to Binary String
185 + - bufToBin(buf)
186 +- Unicode String to Binary String
187 + - strToBin(str)
188 +
189 +It's very easy to convert from Binary Strings to Byte Arrays (`Uint8Array.from(bin.split(''))`)
190 +and from `Uint8Array` to Binary String (`Array.from(buf).join('')`).
191 +
192 +The real value is converting between Unicode Strings to (UTF-8) Binary Strings, and back:
193 +
194 +```js
195 +function toBin(str) {
196 + var escstr = encodeURIComponent(str);
197 + return escstr.replace(/%([0-9A-F]{2})/g, function(match, p1) {
198 + return String.fromCharCode(parseInt(p1, 16));
199 + });
200 +}
201 +```
202 +
203 +```js
204 +function toStr(bin) {
205 + var escstr = bin.replace(/(.)/g, function(m, p) {
206 + var code = p
207 + .charCodeAt(0)
208 + .toString(16)
209 + .toUpperCase();
210 + if (code.length < 2) {
211 + code = '0' + code;
212 + }
213 + return '%' + code;
214 + });
215 +
216 + return decodeURIComponent(escstr);
217 +}
218 +```
219 +
220 +## Hex
221 +
222 +JavaScript does not have a native way to create hex, aside from small numbers:
223 +
224 +```js
225 +(12345).toString(16);
226 +```
227 +
228 +The hex functions convert to and from hexidecimal:
229 +
230 +| Name | Type | Description |
231 +| :---- | :--------- | :--------------------------------------------- |
232 +| `hex` | Hex String | Handled by `split('')` as half-byte characters |
233 +
234 +To Hex
235 +
236 +- Binary String to Hex
237 + - Enc.bufToHex(Enc.binToBuf(bin))
238 +- Byte Array to Hex
239 + - bufToHex
240 +- Unicode String (UTF-8) to Hex
241 + - strToHex
242 +
243 +From Hex
244 +
245 +- Hex to Binary String
246 + - Enc.hexToBuf(Enc.bufToBin(hex))
247 +- Hex to Byte Array
248 + - hexToBuf
249 +- Hex to Unicode String (UTF-8)
250 + - hexToStr
251 +
252 +However, assuming you have a single-byte string, it's very easy to convert back and forth:
253 +
254 +```js
255 +function toHex(any) {
256 + var hex = [];
257 + var i, h;
258 + var len = any.byteLength || any.length;
259 +
260 + for (i = 0; i < len; i += 1) {
261 + h = any[i].toString(16);
262 + if (h.length % 2) {
263 + h = '0' + h;
264 + }
265 + hex.push(h);
266 + }
267 +
268 + return hex.join('').toLowerCase();
269 +}
270 +```
271 +
272 +```js
273 +function fromHex(hex) {
274 + var arr = hex.match(/.{2}/g).map(function(h) {
275 + return parseInt(h, 16);
276 + });
277 + return Uint8Array.from(arr);
278 +}
279 +```
280 +
281 +## Base64
282 +
283 +Browser JavaScript _does_ have a native way convert between Binary Strings and Base64:
284 +
285 +```js
286 +var b64 = btoa('An ASCII string is a Binary String');
287 +// Note: A Unicode String is NOT
288 +```
289 +
290 +```js
291 +var bin = atob('SGVsbG8sIOS4lueVjCE=');
292 +```
293 +
294 +However, it does **not** have a native way to convert between Unicode Strings and Binary Strings,
295 +nor to and from URL Safe Base64.
296 +
297 +The base64 module provides simpler conversions to and from Base 64 and URL Safe Base64:
298 +
299 +| Name | Type | Description |
300 +| :---- | :-------------- | :-------------------------------------------------------- |
301 +| `b64` | Base64 | Standard Base64 as handled by `btoa` and `atob` |
302 +| `u64` | URL Safe Base64 | Replaces `+` with `-` and `/` with `_`, and omits padding |
303 +
304 +To Base64
305 +
306 +- Unicode String (UTF-8) to Base64
307 + - strToBase64(str)
308 +- Binary String to Base64
309 + - Enc.bufToBase64(Enc.binToBuf(bin))
310 +- Byte Array to Base64
311 + - bufToBase64(buf)
312 +
313 +From Base64 (and URL Safe Base64)
314 +
315 +- Base64 to Unicode String (UTF-8)
316 + - base64ToStr(b64)
317 +- Base64 to Binary String
318 + - Enc.bufToBin(Enc.base64ToBuf(b64)))
319 +- Base64 to Byte Array
320 + - base64ToBuf(b64)
321 +
322 +To URL Safe Base64
323 +
324 +- Base64 to URL Safe Base64
325 + - base64ToUrlBase64(b64);
326 +- URL Safe Base64 to Base64
327 + - urlBase64ToBase64(u64);
328 +- Binary String to URL Safe Base64
329 + - Enc.bufToUrlBase64(Enc.binToBuf(bin));
330 +- Byte Array to URL Safe Base64
331 + - bufToUrlBase64(buf);
332 +- Unicode String (UTF-8) to URL Safe Base64
333 + - strToUrlBase64(str);
334 +
335 +# FAQ
336 +
337 +## Why yet another encoding library?
338 +
339 +We write code that works both in node and in browsers,
340 +and we like to keep it small, light, and focused.
341 +
342 +By using browser native functions rather than 're-inventing the wheel'
343 +
344 +## Why not 'browserified' Buffer?
345 +
346 +The most common 'browserified' `Buffer` implementations are quite large -
347 +either because they don't use browser-native code or they guarantee perfect
348 +compatibility with node's `Buffer`, which isn't necessary for most people.
349 +
350 +On the other hand, Browsers have already been able to translate between
351 +Base64, UTF-8, Binary Strings, and Byte Arrays (Buffers) all the way back
352 +since _before_ IE6!
353 +
354 +Using these browser-native methods eliminates hundreds of lines of code:
355 +
356 +- `btoa` Binary String to Base64 (ASCII)
357 +- `atob` Base64 (ASCII) to Binary String
358 +- `encodeURIComponent` Unicode String to Hex-Escaped String
359 +- `decodeURIComponent` Hex-Escaped String to Unicode String
360 +- `String.prototype.charCodeAt` ASCII to Byte
361 +- `String.fromCharCode` Byte to ASCII
362 +
363 +The code is typically also much easier to read. In many cases the conversion is only one line long.
364 +
365 +Since a node `Buffer` is actually an `ArrayBuffer`, node's `Buffer` really only has the advantage
366 +of convenient conversions, so that's really all that needs to be implemented.
367 +
368 +In the case of ancient browsers which do not support `Uint8Array`, the native `Array` is still
369 +the best substitute.
370 +
371 +## Why use this in node?
372 +
373 +Unless you're writing code that's intended to work in the browser, you probably shouldn't -
374 +Node's `Buffer` does the job quite well.
375 +
376 +The one function you may still be interested in, which Node's `Buffer` omits, is this one:
377 +
378 +```js
379 +function toUrlSafeBase64(base64) {
380 + return base64
381 + .replace(/\+/g, '-')
382 + .replace(/\//g, '_')
383 + .replace(/=/g, '');
384 +}
385 +```
386 +
387 +HOWEVER, if you believe that browser users would benefit from your library, this is a much
388 +better alternative for simple use cases where you're dealing with small bits of code.
1 +'use strict';
2 +
3 +var Enc = require('./bytes.js');
4 +
5 +// to Base64
6 +
7 +function bufToBase64(buf) {
8 + // we want to maintain api compatability with browser APIs,
9 + // so we assume that this could be a Uint8Array
10 + return Buffer.from(buf).toString('base64');
11 +}
12 +
13 +Enc.bufToBase64 = bufToBase64;
14 +
15 +Enc.strToBase64 = function(str) {
16 + return Buffer.from(str).toString('base64');
17 +};
18 +
19 +// from Base64
20 +
21 +function base64ToBuf(b64) {
22 + // node handles URL Safe Base64 automatically
23 + return Buffer.from(b64, 'base64');
24 +}
25 +
26 +Enc.base64ToBuf = base64ToBuf;
27 +
28 +Enc.base64ToStr = function(b64) {
29 + return base64ToBuf(b64).toString('utf8');
30 +};
31 +
32 +// URL Safe Base64
33 +
34 +Enc.urlBase64ToBase64 = function(u64) {
35 + var r = u64 % 4;
36 + if (2 === r) {
37 + u64 += '==';
38 + } else if (3 === r) {
39 + u64 += '=';
40 + }
41 + return u64.replace(/-/g, '+').replace(/_/g, '/');
42 +};
43 +
44 +Enc.base64ToUrlBase64 = function(b64) {
45 + return b64
46 + .replace(/\+/g, '-')
47 + .replace(/\//g, '_')
48 + .replace(/=/g, '');
49 +};
50 +
51 +Enc.bufToUrlBase64 = function(buf) {
52 + return Enc.base64ToUrlBase64(bufToBase64(buf));
53 +};
54 +
55 +Enc.strToUrlBase64 = function(str) {
56 + return Enc.base64ToUrlBase64(bufToBase64(Buffer.from(str)));
57 +};
58 +
59 +module.exports = Enc;
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
No preview for this file type
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
No preview for this file type
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff could not be displayed because it is too large.
This diff could not be displayed because it is too large.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff could not be displayed because it is too large.
This diff could not be displayed because it is too large.
This diff could not be displayed because it is too large.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff could not be displayed because it is too large.
This diff is collapsed. Click to expand it.
This diff could not be displayed because it is too large.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.