├── .npmignore ├── .gitignore ├── examples └── echo.js ├── .babelrc ├── .eslintrc ├── webpack.config.js ├── src ├── index.js └── browser.js ├── LICENSE ├── package.json ├── dist ├── certstream.min.js ├── certstream.js.map ├── certstream.js └── certstream.min.js.map └── README.md /.npmignore: -------------------------------------------------------------------------------- 1 | src/ 2 | test/ 3 | .nyc_output/ 4 | coverage/ 5 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | npm-debug.log* 2 | node_modules 3 | 4 | # build artifacts 5 | **/lib/* 6 | **/.nyc_output/* 7 | **/coverage/* 8 | 9 | .idea/ -------------------------------------------------------------------------------- /examples/echo.js: -------------------------------------------------------------------------------- 1 | const CertStreamClient = require('../lib/index.js'); 2 | 3 | let client = new CertStreamClient(function(message){ 4 | console.log("Received -> ", message) 5 | }); 6 | 7 | client.connect(); 8 | -------------------------------------------------------------------------------- /.babelrc: -------------------------------------------------------------------------------- 1 | { 2 | "presets": ["es2015"], 3 | "plugins": ["transform-object-rest-spread", "add-module-exports"], 4 | "env": { 5 | "test": { 6 | "plugins": [ 7 | "__coverage__", 8 | ] 9 | } 10 | } 11 | } 12 | -------------------------------------------------------------------------------- /.eslintrc: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "airbnb", 3 | "rules": { 4 | "no-unused-expressions": 0, 5 | "space-infix-ops": 0, 6 | "default-case": 0, 7 | "no-else-return": 0, 8 | "brace-style": [2, "stroustrup"], 9 | "quote-props": [2, "consistent-as-needed"], 10 | "new-cap": 0, 11 | }, 12 | "parserOptions": { 13 | "ecmaFeatures": { 14 | "experimentalObjectRestSpread": true, 15 | } 16 | }, 17 | } 18 | -------------------------------------------------------------------------------- /webpack.config.js: -------------------------------------------------------------------------------- 1 | const join = require('path').join; 2 | 3 | module.exports = { 4 | entry: './src/browser.js', 5 | output: { 6 | path: join(__dirname, 'dist'), 7 | libraryTarget: 'umd', 8 | library: 'CertStream', 9 | }, 10 | devtool: 'source-map', 11 | module: { 12 | loaders: [ 13 | { 14 | test: /.js$/, 15 | loader: 'babel-loader', 16 | exclude: /node_modules/, 17 | query: { 18 | presets: ['es2015'], 19 | }, 20 | }, 21 | ], 22 | }, 23 | }; 24 | -------------------------------------------------------------------------------- /src/index.js: -------------------------------------------------------------------------------- 1 | const WebSocket = require('ws'); 2 | 3 | export default class CertStreamClient{ 4 | constructor(callback, skipHeartbeats = false) { 5 | this.context = {}; 6 | this.callback = callback; 7 | this.skipHeartbeats = skipHeartbeats; 8 | } 9 | 10 | connect(url="wss://certstream.calidog.io/"){ 11 | console.log(`Connecting to ${url}...`); 12 | this.ws = new WebSocket(url); 13 | 14 | this.ws.on('open', () => { 15 | console.log("Connection established to certstream! Waiting for messages..."); 16 | }); 17 | 18 | this.ws.on('message', (message) => { 19 | let parsedMessage = JSON.parse(message); 20 | 21 | if (parsedMessage.message_type === "heartbeat" && this.skipHeartbeats) { 22 | return; 23 | } 24 | 25 | this.callback(parsedMessage, this.context); 26 | }); 27 | } 28 | }; 29 | -------------------------------------------------------------------------------- /src/browser.js: -------------------------------------------------------------------------------- 1 | import ReconnectingWebsocket from "reconnectingwebsocket" 2 | 3 | export default class CertStreamClient{ 4 | constructor(callback, skipHeartbeats = false) { 5 | this.context = {}; 6 | this.callback = callback; 7 | this.skipHeartbeats = skipHeartbeats; 8 | } 9 | 10 | connect(url="wss://certstream.calidog.io/"){ 11 | console.log(`Connecting to ${url}...`); 12 | 13 | this.ws = new ReconnectingWebsocket(url); 14 | 15 | console.log("Created ws -> ", this.ws); 16 | 17 | this.ws.onmessage = (message) => { 18 | console.log("onmessage called!"); 19 | let parsedMessage = JSON.parse(message.data); 20 | 21 | if (parsedMessage.message_type === "heartbeat" && this.skipHeartbeats) { 22 | return 23 | } 24 | 25 | this.callback(message, this.context) 26 | }; 27 | 28 | this.ws.onopen = () => { 29 | console.log("Connection established to certstream! Waiting for messages..."); 30 | } 31 | 32 | this.ws.open(); 33 | } 34 | }; 35 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | The MIT License (MIT) 2 | 3 | Copyright (c) 2017 fitblip (https://calidog.io) 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in 13 | all copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 21 | THE SOFTWARE. 22 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "certstream", 3 | "version": "1.1.1", 4 | "description": "certstream is a library for interacting with the CertStream network using JS.", 5 | "main": "./lib/index.js", 6 | "directories": { 7 | "test": "test" 8 | }, 9 | "scripts": { 10 | "prebuild": "npm run clean", 11 | "build": "npm-run-all --parallel build:*", 12 | "build:lib": "babel src --out-dir lib", 13 | "build:umd": "webpack --output-filename certstream.js", 14 | "build:umd.min": "webpack -p --output-filename certstream.min.js", 15 | "prepublish": "in-install || npm run build", 16 | "semantic-release": "semantic-release pre && npm publish && semantic-release post", 17 | "clean": "npm-run-all --parallel clean:*", 18 | "clean:build": "rimraf dist lib", 19 | "clean:coverage": "rimraf .nyc_output coverage" 20 | }, 21 | "repository": { 22 | "type": "git", 23 | "url": "https://github.com/CaliDog/certstream-js.git" 24 | }, 25 | "keywords": [], 26 | "author": { 27 | "name": "fitblip", 28 | "email": "ryan@calidog.io", 29 | "website": "https://calidog.io" 30 | }, 31 | "license": "MIT", 32 | "bugs": { 33 | "url": "https://github.com/CaliDog/certstream-js/issues" 34 | }, 35 | "homepage": "https://github.com/CaliDog/certstream-js#readme", 36 | "devDependencies": { 37 | "babel-cli": "^6.9.0", 38 | "babel-core": "^6.9.0", 39 | "babel-loader": "^6.2.4", 40 | "babel-plugin-__coverage__": "^11.0.0", 41 | "babel-plugin-add-module-exports": "^0.2.1", 42 | "babel-plugin-transform-object-rest-spread": "^6.8.0", 43 | "babel-preset-es2015": "^6.9.0", 44 | "chai": "^3.5.0", 45 | "codecov": "^1.0.1", 46 | "commitizen": "^2.8.2", 47 | "cross-env": "^1.0.8", 48 | "cz-conventional-changelog": "^1.1.6", 49 | "eslint": "^2.12.0", 50 | "eslint-config-airbnb": "^9.0.1", 51 | "eslint-plugin-import": "^1.8.0", 52 | "eslint-plugin-jsx-a11y": "^1.2.2", 53 | "eslint-plugin-react": "^5.1.1", 54 | "ghooks": "^1.2.4", 55 | "mocha": "^3.0.0", 56 | "npm-run-all": "^2.1.2", 57 | "nyc": "^6.4.4", 58 | "rimraf": "^2.5.2", 59 | "semantic-release": "^4.3.5", 60 | "sinon": "^1.17.4", 61 | "sinon-chai": "^2.8.0", 62 | "webpack": "^1.13.1", 63 | "validate-commit-msg": "^2.6.1" 64 | }, 65 | "dependencies": { 66 | "in-publish": "^2.0.0", 67 | "reconnectingwebsocket": "^1.0.0", 68 | "ws": "^3.2.0" 69 | }, 70 | "nyc": { 71 | "instrument": false, 72 | "sourceMap": false 73 | }, 74 | "browser": { 75 | "./index.js": "./browser.js" 76 | } 77 | } 78 | -------------------------------------------------------------------------------- /dist/certstream.min.js: -------------------------------------------------------------------------------- 1 | !function(e,t){"object"==typeof exports&&"object"==typeof module?module.exports=t():"function"==typeof define&&define.amd?define([],t):"object"==typeof exports?exports.CertStream=t():e.CertStream=t()}(this,function(){return function(e){function t(o){if(n[o])return n[o].exports;var c=n[o]={exports:{},id:o,loaded:!1};return e[o].call(c.exports,c,c.exports,t),c.loaded=!0,c.exports}var n={};return t.m=e,t.c=n,t.p="",t(0)}([function(e,t,n){"use strict";function o(e){return e&&e.__esModule?e:{default:e}}function c(e,t){if(!(e instanceof t))throw new TypeError("Cannot call a class as a function")}Object.defineProperty(t,"__esModule",{value:!0});var r=function(){function e(e,t){for(var n=0;n1&&void 0!==arguments[1]&&arguments[1];c(this,e),this.context={},this.callback=t,this.skipHeartbeats=n}return r(e,[{key:"connect",value:function(){var e=this;console.log("Connecting..."),this.ws=new s.default("wss://certstream.calidog.io/"),console.log("Created ws -> ",this.ws),this.ws.onmessage=function(t){console.log("onmessage called!");var n=JSON.parse(t.data);"heartbeat"===n.message_type&&e.skipHeartbeats||e.callback(t,e.context)},this.ws.onopen=function(){console.log("Connection established to certstream! Waiting for messages...")},this.ws.open()}}]),e}();t.default=a},function(e,t,n){var o,c,r;!function(n,i){c=[],o=i,r="function"==typeof o?o.apply(t,c):o,!(void 0!==r&&(e.exports=r))}(this,function(){function e(t,n,o){function c(e,t){var n=document.createEvent("CustomEvent");return n.initCustomEvent(e,!1,!1,t),n}var r={debug:!1,automaticOpen:!0,reconnectInterval:1e3,maxReconnectInterval:3e4,reconnectDecay:1.5,timeoutInterval:2e3,maxReconnectAttempts:null};o||(o={});for(var i in r)"undefined"!=typeof o[i]?this[i]=o[i]:this[i]=r[i];this.url=t,this.reconnectAttempts=0,this.readyState=WebSocket.CONNECTING,this.protocol=null;var s,a=this,u=!1,l=!1,d=document.createElement("div");d.addEventListener("open",function(e){a.onopen(e)}),d.addEventListener("close",function(e){a.onclose(e)}),d.addEventListener("connecting",function(e){a.onconnecting(e)}),d.addEventListener("message",function(e){a.onmessage(e)}),d.addEventListener("error",function(e){a.onerror(e)}),this.addEventListener=d.addEventListener.bind(d),this.removeEventListener=d.removeEventListener.bind(d),this.dispatchEvent=d.dispatchEvent.bind(d),this.open=function(t){if(s=new WebSocket(a.url,n||[]),t){if(this.maxReconnectAttempts&&this.reconnectAttempts>this.maxReconnectAttempts)return}else d.dispatchEvent(c("connecting")),this.reconnectAttempts=0;(a.debug||e.debugAll)&&console.debug("ReconnectingWebSocket","attempt-connect",a.url);var o=s,r=setTimeout(function(){(a.debug||e.debugAll)&&console.debug("ReconnectingWebSocket","connection-timeout",a.url),l=!0,o.close(),l=!1},a.timeoutInterval);s.onopen=function(n){clearTimeout(r),(a.debug||e.debugAll)&&console.debug("ReconnectingWebSocket","onopen",a.url),a.protocol=s.protocol,a.readyState=WebSocket.OPEN,a.reconnectAttempts=0;var o=c("open");o.isReconnect=t,t=!1,d.dispatchEvent(o)},s.onclose=function(n){if(clearTimeout(r),s=null,u)a.readyState=WebSocket.CLOSED,d.dispatchEvent(c("close"));else{a.readyState=WebSocket.CONNECTING;var o=c("connecting");o.code=n.code,o.reason=n.reason,o.wasClean=n.wasClean,d.dispatchEvent(o),t||l||((a.debug||e.debugAll)&&console.debug("ReconnectingWebSocket","onclose",a.url),d.dispatchEvent(c("close")));var r=a.reconnectInterval*Math.pow(a.reconnectDecay,a.reconnectAttempts);setTimeout(function(){a.reconnectAttempts++,a.open(!0)},r>a.maxReconnectInterval?a.maxReconnectInterval:r)}},s.onmessage=function(t){(a.debug||e.debugAll)&&console.debug("ReconnectingWebSocket","onmessage",a.url,t.data);var n=c("message");n.data=t.data,d.dispatchEvent(n)},s.onerror=function(t){(a.debug||e.debugAll)&&console.debug("ReconnectingWebSocket","onerror",a.url,t),d.dispatchEvent(c("error"))}},1==this.automaticOpen&&this.open(!1),this.send=function(t){if(s)return(a.debug||e.debugAll)&&console.debug("ReconnectingWebSocket","send",a.url,t),s.send(t);throw"INVALID_STATE_ERR : Pausing to reconnect websocket"},this.close=function(e,t){"undefined"==typeof e&&(e=1e3),u=!0,s&&s.close(e,t)},this.refresh=function(){s&&s.close()}}if("WebSocket"in window)return e.prototype.onopen=function(e){},e.prototype.onclose=function(e){},e.prototype.onconnecting=function(e){},e.prototype.onmessage=function(e){},e.prototype.onerror=function(e){},e.debugAll=!1,e.CONNECTING=WebSocket.CONNECTING,e.OPEN=WebSocket.OPEN,e.CLOSING=WebSocket.CLOSING,e.CLOSED=WebSocket.CLOSED,e})}])}); 2 | //# sourceMappingURL=certstream.min.js.map -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 |

2 | 3 |

CertStream-JS

4 |

See SSL certs as they're issued live.

5 |

6 | 7 | This is a library for interacting with the [certstream network](https://certstream.calidog.io/) to monitor an aggregated feed from a collection of [Certificate Transparency Logs](https://www.certificate-transparency.org/known-logs). 8 | 9 | It is built to be compatible with both node.js and a standard browser with UMD. 10 | 11 | # Installing 12 | 13 | ``` 14 | npm install --save certstream 15 | ``` 16 | 17 | Or if you're using this in the browser, just add `dist/certstream.min.js` to a `