├── .editorconfig ├── .gitignore ├── LICENSE ├── README.md ├── index.js ├── package.json └── yarn.lock /.editorconfig: -------------------------------------------------------------------------------- 1 | # editorconfig.org 2 | root = true 3 | 4 | [*] 5 | indent_style = space 6 | end_of_line = lf 7 | charset = utf-8 8 | trim_trailing_whitespace = true 9 | insert_final_newline = true 10 | 11 | [*.md] 12 | trim_trailing_whitespace = false -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | logs 2 | *.log 3 | pids 4 | *.pid 5 | *.seed 6 | lib-cov 7 | coverage 8 | .grunt 9 | .lock-wscript 10 | build/Release 11 | node_modules -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | Copyright for portions of this library are held by Rocket Chat, 2015. 2 | All other copyright is held by Keybase Inc, 2019. 3 | 4 | The MIT License (MIT) 5 | 6 | Permission is hereby granted, free of charge, to any person obtaining a copy 7 | of this software and associated documentation files (the "Software"), to deal 8 | in the Software without restriction, including without limitation the rights 9 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 10 | copies of the Software, and to permit persons to whom the Software is 11 | furnished to do so, subject to the following conditions: 12 | 13 | The above copyright notice and this permission notice shall be included in all 14 | copies or substantial portions of the Software. 15 | 16 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 17 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 18 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 19 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 20 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 21 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 22 | SOFTWARE. 23 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # hubot-keybase 2 | 3 | Hubot adapter for Keybase Chat. 4 | 5 | ## Building a bot 6 | 7 | ```bash 8 | mkdir mybot 9 | cd mybot 10 | yo hubot # choose the "keybase" adapter 11 | # Set the desired environment variables 12 | ./bin/hubot -a keybase 13 | ``` 14 | 15 | ## Configuration 16 | 17 | All of `hubot-keybase` configuration is done using environment variables. 18 | 19 | In local development, the following can be set in an `.env` file. Using 20 | that approach in production is not recommended, as paper keys should be 21 | kept a secret. 22 | 23 | | Env variable | Description | 24 | |------------------|-------------| 25 | | `KB_USERNAME`* | If passed, a new Keybase service will be spawned using the passed username. | 26 | | `KB_PAPERKEY`* | If passed, a new Keybase service will be spawned using the passed paper key. | 27 | | `KB_UNFURL_MODE` | If set, [unfurling mode](#unfurling) will be changed to the passed value. | 28 | 29 | \* If you don't set either `KB_USERNAME` or `KB_PAPERKEY` the adapter will 30 | try to attach to an already running Keybase service. This might be 31 | desirable if you require support for features such as exploding messages. 32 | 33 | ## Unfurling 34 | 35 | In Keybase, unfurling means generating previews for links that you're 36 | sending in chat messages. If the mode is set to `always` or the domain in 37 | the URL is present on the whitelist (which is not configurable using 38 | `hubot-keybase`), the Keybase service will automatically send a preview 39 | to the message recipient in a background chat channel. 40 | 41 | This is incredibly useful for all sorts of Hubot plugins, as nearly every 42 | single script expects the chat software to automatically unfurl links. 43 | That being said, this feature also has quite a few caveats, most 44 | importantly it might leak the IP address of the server running Hubot. 45 | -------------------------------------------------------------------------------- /index.js: -------------------------------------------------------------------------------- 1 | 'use strict' 2 | 3 | const Adapter = require.main.require('hubot/src/adapter') 4 | const Response = require.main.require('hubot/src/response') 5 | const msgs = require.main.require('hubot/src/message') 6 | const Bot = require('keybase-bot') 7 | 8 | const convertChannelToRoom = (x) => { 9 | if (!x.topicName) { 10 | return x.name 11 | } 12 | return x.name + '#' + x.topicName 13 | } 14 | 15 | const composeMessageID = (room, id) => { 16 | return room + '@' + id 17 | } 18 | 19 | const membersCount = (name) => { 20 | return name.split(',').length 21 | } 22 | 23 | const convertRoomToChannel = (name) => { 24 | if (membersCount(name) > 1) { 25 | // We're dealing with an impteamnative 26 | return { 27 | name: name, 28 | public: false, 29 | membersType: 'impteamnative', 30 | topicType: 'chat', 31 | } 32 | } 33 | 34 | // Otherwise it should be a team channel 35 | const parts = name.split('#') 36 | return { 37 | name: parts[0], 38 | public: false, 39 | membersType: 'team', 40 | topicType: 'chat', 41 | topicName: parts[1], 42 | } 43 | } 44 | 45 | /** Main API for Hubot on Keybase */ 46 | class KeybaseAdapter extends Adapter { 47 | async run () { 48 | // Overwrite Robot's response class with Keybase custom one 49 | // this.robot.Response = RocketChatResponse 50 | 51 | try { 52 | this.robot.logger.info(`[startup] Keybase adapter in use`) 53 | this.keybase = new Bot() 54 | 55 | if (process.env.KB_USERNAME && process.env.KB_PAPERKEY) { 56 | await this.keybase.init( 57 | process.env.KB_USERNAME, 58 | process.env.KB_PAPERKEY, 59 | {verbose: false} 60 | ) 61 | } else { 62 | await this.keybase.initFromRunningService() 63 | } 64 | 65 | if (process.env.KB_UNFURL_MODE) { 66 | await this.keybase.chat.setUnfurlSettings({ 67 | mode: process.env.KB_UNFURL_MODE, 68 | }) 69 | this.robot.logger.info(`Changed unfurl settings: ${JSON.stringify(await this.keybase.chat.getUnfurlSettings())}`) 70 | } 71 | 72 | // Print logs with current configs 73 | this.robot.logger.info(`[startup] Respond to name: ${this.robot.name}`) 74 | if (this.robot.alias) { 75 | this.robot.logger.info(`[startup] Respond to alias: ${this.robot.alias}`) 76 | } 77 | 78 | this.keybase.chat.watchAllChannelsForNewMessages(this.process.bind(this), (err) => { 79 | throw err 80 | }) 81 | this.emit('connected') // tells hubot to load scripts 82 | } catch(err) { 83 | this.robot.logger.error(`Unable to start ${JSON.stringify(err)}`) 84 | throw err 85 | } 86 | } 87 | 88 | /** Process every incoming message in subscription */ 89 | process (msg) { 90 | const roomName = convertChannelToRoom(msg.channel) 91 | const messageID = composeMessageID(roomName, msg.id) 92 | const user = this.robot.brain.userForId(msg.sender.uid, { 93 | name: msg.sender.username, 94 | }) 95 | const isDM = (msg.channel.membersType === 'impteamnative' && membersCount(msg.channel.name) === 2) 96 | user.roomID = roomName 97 | user.roomType = msg.channel.membersType 98 | user.room = roomName 99 | 100 | if (msg.content.type === 'system') { 101 | // "User Bob was added by Alice" messages are not supported because 102 | // system messages don't include UIDs. 103 | return 104 | } 105 | 106 | if (msg.content.type === 'join') { 107 | this.robot.logger.debug('Received an EnterMessage') 108 | return this.robot.receive(new msgs.EnterMessage(user, null, messageID)) 109 | } 110 | 111 | if (msg.content.type === 'leave') { 112 | this.robot.logger.debug('Received an LeaveMessage') 113 | return this.robot.receive(new msgs.LeaveMessage(user, null, messageID)) 114 | } 115 | 116 | // Direct messages prepend bot's name so Hubot can `.respond` 117 | if (msg.content.type === 'text') { 118 | let text = msg.content.text.body 119 | const startOfText = (text.indexOf('@') === 0) ? 1 : 0 120 | const robotIsNamed = text.indexOf(this.robot.name) === startOfText || 121 | text.indexOf(this.robot.alias) === startOfText 122 | 123 | if (isDM && !robotIsNamed) { 124 | text = `${this.robot.name} ${text}` 125 | } 126 | 127 | const textMessage = new msgs.TextMessage(user, text, messageID) 128 | this.robot.logger.debug(`TextMessage: ${textMessage.toString()}`) 129 | return this.robot.receive(textMessage) 130 | } 131 | } 132 | 133 | /** Send messages to user addressed in envelope */ 134 | async send (envelope, ...strings) { 135 | return await Promise.all(strings.map((text) => { 136 | return this.keybase.chat.send(convertRoomToChannel(envelope.room), { 137 | body: text, 138 | }) 139 | })) 140 | } 141 | 142 | /** Reply to a user's message (mention them if not a DM) */ 143 | reply (envelope, ...strings) { 144 | if (membersCount(envelope.room) === 2) { 145 | strings = strings.map((s) => `@${envelope.user.name} ${s}`) 146 | } 147 | return this.send(envelope, ...strings) 148 | } 149 | } 150 | 151 | exports.use = (robot) => new KeybaseAdapter(robot) 152 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "hubot-keybase", 3 | "version": "1.0.0", 4 | "files": [ 5 | "index.js" 6 | ], 7 | "author": { 8 | "name": "Keybase", 9 | "url": "https://keybase.io" 10 | }, 11 | "contributors": [ 12 | { 13 | "name": "Piotr Zduniak", 14 | "email": "piotr@keyba.se" 15 | } 16 | ], 17 | "description": "Hubot Keybase Adapter", 18 | "keywords": [ 19 | "hubot", 20 | "adapter", 21 | "keybase", 22 | "bot" 23 | ], 24 | "license": "MIT", 25 | "repository": { 26 | "type": "git", 27 | "url": "https://github.com/keybase/hubot-keybase.git" 28 | }, 29 | "bugs": { 30 | "url": "https://github.com/keybase/hubot-keybase/issues", 31 | "email": "piotr@keyba.se" 32 | }, 33 | "main": "index.js", 34 | "dependencies": { 35 | "keybase-bot": "^2.0.5", 36 | "hubot": "3" 37 | }, 38 | "peerDependencies": { 39 | "hubot": "3" 40 | } 41 | } 42 | -------------------------------------------------------------------------------- /yarn.lock: -------------------------------------------------------------------------------- 1 | # THIS IS AN AUTOGENERATED FILE. DO NOT EDIT THIS FILE DIRECTLY. 2 | # yarn lockfile v1 3 | 4 | 5 | accepts@~1.3.7: 6 | version "1.3.7" 7 | resolved "https://registry.yarnpkg.com/accepts/-/accepts-1.3.7.tgz#531bc726517a3b2b41f850021c6cc15eaab507cd" 8 | integrity sha512-Il80Qs2WjYlJIBNzNkK6KYqlVMTbZLXgHx2oT0pU/fjRHyEp+PEfEPY0R3WCwAGVOtauxh1hOxNgIf5bv7dQpA== 9 | dependencies: 10 | mime-types "~2.1.24" 11 | negotiator "0.6.2" 12 | 13 | ansi-regex@^2.0.0: 14 | version "2.1.1" 15 | resolved "https://registry.yarnpkg.com/ansi-regex/-/ansi-regex-2.1.1.tgz#c3b33ab5ee360d86e0e628f0468ae7ef27d654df" 16 | integrity sha1-w7M6te42DYbg5ijwRorn7yfWVN8= 17 | 18 | ansi-styles@^2.2.1: 19 | version "2.2.1" 20 | resolved "https://registry.yarnpkg.com/ansi-styles/-/ansi-styles-2.2.1.tgz#b432dd3358b634cf75e1e4664368240533c1ddbe" 21 | integrity sha1-tDLdM1i2NM914eRmQ2gkBTPB3b4= 22 | 23 | array-flatten@1.1.1: 24 | version "1.1.1" 25 | resolved "https://registry.yarnpkg.com/array-flatten/-/array-flatten-1.1.1.tgz#9a5f699051b1e7073328f2a008968b64ea2955d2" 26 | integrity sha1-ml9pkFGx5wczKPKgCJaLZOopVdI= 27 | 28 | "async@>=0.1.0 <1.0.0": 29 | version "0.9.2" 30 | resolved "https://registry.yarnpkg.com/async/-/async-0.9.2.tgz#aea74d5e61c1f899613bf64bda66d4c78f2fd17d" 31 | integrity sha1-rqdNXmHB+JlhO/ZL2mbUx48v0X0= 32 | 33 | body-parser@1.19.0: 34 | version "1.19.0" 35 | resolved "https://registry.yarnpkg.com/body-parser/-/body-parser-1.19.0.tgz#96b2709e57c9c4e09a6fd66a8fd979844f69f08a" 36 | integrity sha512-dhEPs72UPbDnAQJ9ZKMNTP6ptJaionhP5cBb541nXPlW60Jepo9RV/a4fX4XWW9CuFNK22krhrj1+rgzifNCsw== 37 | dependencies: 38 | bytes "3.1.0" 39 | content-type "~1.0.4" 40 | debug "2.6.9" 41 | depd "~1.1.2" 42 | http-errors "1.7.2" 43 | iconv-lite "0.4.24" 44 | on-finished "~2.3.0" 45 | qs "6.7.0" 46 | raw-body "2.4.0" 47 | type-is "~1.6.17" 48 | 49 | bytes@3.1.0: 50 | version "3.1.0" 51 | resolved "https://registry.yarnpkg.com/bytes/-/bytes-3.1.0.tgz#f6cf7933a360e0588fa9fde85651cdc7f805d1f6" 52 | integrity sha512-zauLjrfCG+xvoyaqLoV8bLVXXNGC4JqlxFCutSDWA6fJrTo2ZuvLYTqZ7aHBLZSMOopbzwv8f+wZcVzfVTI2Dg== 53 | 54 | chalk@^1.0.0: 55 | version "1.1.3" 56 | resolved "https://registry.yarnpkg.com/chalk/-/chalk-1.1.3.tgz#a8115c55e4a702fe4d150abd3872822a7e09fc98" 57 | integrity sha1-qBFcVeSnAv5NFQq9OHKCKn4J/Jg= 58 | dependencies: 59 | ansi-styles "^2.2.1" 60 | escape-string-regexp "^1.0.2" 61 | has-ansi "^2.0.0" 62 | strip-ansi "^3.0.0" 63 | supports-color "^2.0.0" 64 | 65 | cline@^0.8.2: 66 | version "0.8.2" 67 | resolved "https://registry.yarnpkg.com/cline/-/cline-0.8.2.tgz#e911e741a0ad2e24d29e6fab2cf89fa322d59c76" 68 | integrity sha1-6RHnQaCtLiTSnm+rLPifoyLVnHY= 69 | 70 | coffeescript@1.6.3: 71 | version "1.6.3" 72 | resolved "https://registry.yarnpkg.com/coffeescript/-/coffeescript-1.6.3.tgz#41749750c621a6553c7c03818a5384bb24c30541" 73 | integrity sha1-QXSXUMYhplU8fAOBilOEuyTDBUE= 74 | 75 | connect-multiparty@^2.1.1: 76 | version "2.2.0" 77 | resolved "https://registry.yarnpkg.com/connect-multiparty/-/connect-multiparty-2.2.0.tgz#b4932482dba298f82b8a54b70fb60ec5d72393c3" 78 | integrity sha512-zKcpA7cuXGEhuw9Pz7JmVCFmp85jzGLGm/iiagXTwyEAJp4ypLPtRS/V4IGuGb9KjjrgHBs6P/gDCpZHnFzksA== 79 | dependencies: 80 | http-errors "~1.7.0" 81 | multiparty "~4.2.1" 82 | on-finished "~2.3.0" 83 | qs "~6.5.2" 84 | type-is "~1.6.16" 85 | 86 | content-disposition@0.5.3: 87 | version "0.5.3" 88 | resolved "https://registry.yarnpkg.com/content-disposition/-/content-disposition-0.5.3.tgz#e130caf7e7279087c5616c2007d0485698984fbd" 89 | integrity sha512-ExO0774ikEObIAEV9kDo50o+79VCUdEB6n6lzKgGwupcVeRlhrj3qGAfwq8G6uBJjkqLrhT0qEYFcWng8z1z0g== 90 | dependencies: 91 | safe-buffer "5.1.2" 92 | 93 | content-type@~1.0.4: 94 | version "1.0.4" 95 | resolved "https://registry.yarnpkg.com/content-type/-/content-type-1.0.4.tgz#e138cc75e040c727b1966fe5e5f8c9aee256fe3b" 96 | integrity sha512-hIP3EEPs8tB9AT1L+NUqtwOAps4mk2Zob89MWXMHjHWg9milF/j4osnnQLXBCBFBk/tvIG/tUc9mOUJiPBhPXA== 97 | 98 | cookie-signature@1.0.6: 99 | version "1.0.6" 100 | resolved "https://registry.yarnpkg.com/cookie-signature/-/cookie-signature-1.0.6.tgz#e303a882b342cc3ee8ca513a79999734dab3ae2c" 101 | integrity sha1-4wOogrNCzD7oylE6eZmXNNqzriw= 102 | 103 | cookie@0.4.0: 104 | version "0.4.0" 105 | resolved "https://registry.yarnpkg.com/cookie/-/cookie-0.4.0.tgz#beb437e7022b3b6d49019d088665303ebe9c14ba" 106 | integrity sha512-+Hp8fLp57wnUSt0tY0tHEXh4voZRDnoIrZPqlo3DPiI4y9lwg/jqx+1Om94/W6ZaPDOUbnjOt/99w66zk+l1Xg== 107 | 108 | debug@2.6.9: 109 | version "2.6.9" 110 | resolved "https://registry.yarnpkg.com/debug/-/debug-2.6.9.tgz#5d128515df134ff327e90a4c93f4e077a536341f" 111 | integrity sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA== 112 | dependencies: 113 | ms "2.0.0" 114 | 115 | depd@~1.1.2: 116 | version "1.1.2" 117 | resolved "https://registry.yarnpkg.com/depd/-/depd-1.1.2.tgz#9bcd52e14c097763e749b274c4346ed2e560b5a9" 118 | integrity sha1-m81S4UwJd2PnSbJ0xDRu0uVgtak= 119 | 120 | destroy@~1.0.4: 121 | version "1.0.4" 122 | resolved "https://registry.yarnpkg.com/destroy/-/destroy-1.0.4.tgz#978857442c44749e4206613e37946205826abd80" 123 | integrity sha1-l4hXRCxEdJ5CBmE+N5RiBYJqvYA= 124 | 125 | ee-first@1.1.1: 126 | version "1.1.1" 127 | resolved "https://registry.yarnpkg.com/ee-first/-/ee-first-1.1.1.tgz#590c61156b0ae2f4f0255732a158b266bc56b21d" 128 | integrity sha1-WQxhFWsK4vTwJVcyoViyZrxWsh0= 129 | 130 | encodeurl@~1.0.2: 131 | version "1.0.2" 132 | resolved "https://registry.yarnpkg.com/encodeurl/-/encodeurl-1.0.2.tgz#ad3ff4c86ec2d029322f5a02c3a9a606c95b3f59" 133 | integrity sha1-rT/0yG7C0CkyL1oCw6mmBslbP1k= 134 | 135 | escape-html@~1.0.3: 136 | version "1.0.3" 137 | resolved "https://registry.yarnpkg.com/escape-html/-/escape-html-1.0.3.tgz#0258eae4d3d0c0974de1c169188ef0051d1d1988" 138 | integrity sha1-Aljq5NPQwJdN4cFpGI7wBR0dGYg= 139 | 140 | escape-string-regexp@^1.0.2: 141 | version "1.0.5" 142 | resolved "https://registry.yarnpkg.com/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz#1b61c0562190a8dff6ae3bb2cf0200ca130b86d4" 143 | integrity sha1-G2HAViGQqN/2rjuyzwIAyhMLhtQ= 144 | 145 | etag@~1.8.1: 146 | version "1.8.1" 147 | resolved "https://registry.yarnpkg.com/etag/-/etag-1.8.1.tgz#41ae2eeb65efa62268aebfea83ac7d79299b0887" 148 | integrity sha1-Qa4u62XvpiJorr/qg6x9eSmbCIc= 149 | 150 | express@^4.16.3: 151 | version "4.17.1" 152 | resolved "https://registry.yarnpkg.com/express/-/express-4.17.1.tgz#4491fc38605cf51f8629d39c2b5d026f98a4c134" 153 | integrity sha512-mHJ9O79RqluphRrcw2X/GTh3k9tVv8YcoyY4Kkh4WDMUYKRZUq0h1o0w2rrrxBqM7VoeUVqgb27xlEMXTnYt4g== 154 | dependencies: 155 | accepts "~1.3.7" 156 | array-flatten "1.1.1" 157 | body-parser "1.19.0" 158 | content-disposition "0.5.3" 159 | content-type "~1.0.4" 160 | cookie "0.4.0" 161 | cookie-signature "1.0.6" 162 | debug "2.6.9" 163 | depd "~1.1.2" 164 | encodeurl "~1.0.2" 165 | escape-html "~1.0.3" 166 | etag "~1.8.1" 167 | finalhandler "~1.1.2" 168 | fresh "0.5.2" 169 | merge-descriptors "1.0.1" 170 | methods "~1.1.2" 171 | on-finished "~2.3.0" 172 | parseurl "~1.3.3" 173 | path-to-regexp "0.1.7" 174 | proxy-addr "~2.0.5" 175 | qs "6.7.0" 176 | range-parser "~1.2.1" 177 | safe-buffer "5.1.2" 178 | send "0.17.1" 179 | serve-static "1.14.1" 180 | setprototypeof "1.1.1" 181 | statuses "~1.5.0" 182 | type-is "~1.6.18" 183 | utils-merge "1.0.1" 184 | vary "~1.1.2" 185 | 186 | fd-slicer@1.1.0: 187 | version "1.1.0" 188 | resolved "https://registry.yarnpkg.com/fd-slicer/-/fd-slicer-1.1.0.tgz#25c7c89cb1f9077f8891bbe61d8f390eae256f1e" 189 | integrity sha1-JcfInLH5B3+IkbvmHY85Dq4lbx4= 190 | dependencies: 191 | pend "~1.2.0" 192 | 193 | finalhandler@~1.1.2: 194 | version "1.1.2" 195 | resolved "https://registry.yarnpkg.com/finalhandler/-/finalhandler-1.1.2.tgz#b7e7d000ffd11938d0fdb053506f6ebabe9f587d" 196 | integrity sha512-aAWcW57uxVNrQZqFXjITpW3sIUQmHGG3qSb9mUah9MgMC4NeWhNOlNjXEYq3HjRAvL6arUviZGGJsBg6z0zsWA== 197 | dependencies: 198 | debug "2.6.9" 199 | encodeurl "~1.0.2" 200 | escape-html "~1.0.3" 201 | on-finished "~2.3.0" 202 | parseurl "~1.3.3" 203 | statuses "~1.5.0" 204 | unpipe "~1.0.0" 205 | 206 | forwarded@~0.1.2: 207 | version "0.1.2" 208 | resolved "https://registry.yarnpkg.com/forwarded/-/forwarded-0.1.2.tgz#98c23dab1175657b8c0573e8ceccd91b0ff18c84" 209 | integrity sha1-mMI9qxF1ZXuMBXPozszZGw/xjIQ= 210 | 211 | fresh@0.5.2: 212 | version "0.5.2" 213 | resolved "https://registry.yarnpkg.com/fresh/-/fresh-0.5.2.tgz#3d8cadd90d976569fa835ab1f8e4b23a105605a7" 214 | integrity sha1-PYyt2Q2XZWn6g1qx+OSyOhBWBac= 215 | 216 | has-ansi@^2.0.0: 217 | version "2.0.0" 218 | resolved "https://registry.yarnpkg.com/has-ansi/-/has-ansi-2.0.0.tgz#34f5049ce1ecdf2b0649af3ef24e45ed35416d91" 219 | integrity sha1-NPUEnOHs3ysGSa8+8k5F7TVBbZE= 220 | dependencies: 221 | ansi-regex "^2.0.0" 222 | 223 | http-errors@1.7.2, http-errors@~1.7.0, http-errors@~1.7.2: 224 | version "1.7.2" 225 | resolved "https://registry.yarnpkg.com/http-errors/-/http-errors-1.7.2.tgz#4f5029cf13239f31036e5b2e55292bcfbcc85c8f" 226 | integrity sha512-uUQBt3H/cSIVfch6i1EuPNy/YsRSOUBXTVfZ+yR7Zjez3qjBz6i9+i4zjNaoqcoFVI4lQJ5plg63TvGfRSDCRg== 227 | dependencies: 228 | depd "~1.1.2" 229 | inherits "2.0.3" 230 | setprototypeof "1.1.1" 231 | statuses ">= 1.5.0 < 2" 232 | toidentifier "1.0.0" 233 | 234 | hubot@3: 235 | version "3.3.2" 236 | resolved "https://registry.yarnpkg.com/hubot/-/hubot-3.3.2.tgz#6ad13db19082cbe57ee3f9cc1c2c856d15cba223" 237 | integrity sha512-+8h/s+t5GirjuDW5K1QjTGBGzOU8ksEi51HeLdFghYOWj40x6ndhAU3C6SRPk/7yHj6luVPuVi/Y8s0P+lqM9Q== 238 | dependencies: 239 | async ">=0.1.0 <1.0.0" 240 | chalk "^1.0.0" 241 | cline "^0.8.2" 242 | coffeescript "1.6.3" 243 | connect-multiparty "^2.1.1" 244 | express "^4.16.3" 245 | log "1.4.0" 246 | optparse "1.0.4" 247 | scoped-http-client "0.11.0" 248 | 249 | iconv-lite@0.4.24: 250 | version "0.4.24" 251 | resolved "https://registry.yarnpkg.com/iconv-lite/-/iconv-lite-0.4.24.tgz#2022b4b25fbddc21d2f524974a474aafe733908b" 252 | integrity sha512-v3MXnZAcvnywkTUEZomIActle7RXXeedOR31wwl7VlyoXO4Qi9arvSenNQWne1TcRwhCL1HwLI21bEqdpj8/rA== 253 | dependencies: 254 | safer-buffer ">= 2.1.2 < 3" 255 | 256 | inherits@2.0.3: 257 | version "2.0.3" 258 | resolved "https://registry.yarnpkg.com/inherits/-/inherits-2.0.3.tgz#633c2c83e3da42a502f52466022480f4208261de" 259 | integrity sha1-Yzwsg+PaQqUC9SRmAiSA9CCCYd4= 260 | 261 | ipaddr.js@1.9.0: 262 | version "1.9.0" 263 | resolved "https://registry.yarnpkg.com/ipaddr.js/-/ipaddr.js-1.9.0.tgz#37df74e430a0e47550fe54a2defe30d8acd95f65" 264 | integrity sha512-M4Sjn6N/+O6/IXSJseKqHoFc+5FdGJ22sXqnjTpdZweHK64MzEPAyQZyEU3R/KRv2GLoa7nNtg/C2Ev6m7z+eA== 265 | 266 | keybase-bot@^2.0.5: 267 | version "2.0.5" 268 | resolved "https://registry.yarnpkg.com/keybase-bot/-/keybase-bot-2.0.5.tgz#d2136466efa20709719238281cda6bf9511dfd2a" 269 | integrity sha512-Ff4WYYzh6wGeOygiYRemIZBF2d1Z+xK7Jo9ZPwxoB3iIdN1ZFve2Y8c//bq7wa/QbR5jwvk/sX9Ti2mUK3WWZQ== 270 | dependencies: 271 | lodash.camelcase "4.3.0" 272 | lodash.kebabcase "4.1.1" 273 | lodash.snakecase "4.1.1" 274 | mkdirp "0.5.1" 275 | 276 | lodash.camelcase@4.3.0: 277 | version "4.3.0" 278 | resolved "https://registry.yarnpkg.com/lodash.camelcase/-/lodash.camelcase-4.3.0.tgz#b28aa6288a2b9fc651035c7711f65ab6190331a6" 279 | integrity sha1-soqmKIorn8ZRA1x3EfZathkDMaY= 280 | 281 | lodash.kebabcase@4.1.1: 282 | version "4.1.1" 283 | resolved "https://registry.yarnpkg.com/lodash.kebabcase/-/lodash.kebabcase-4.1.1.tgz#8489b1cb0d29ff88195cceca448ff6d6cc295c36" 284 | integrity sha1-hImxyw0p/4gZXM7KRI/21swpXDY= 285 | 286 | lodash.snakecase@4.1.1: 287 | version "4.1.1" 288 | resolved "https://registry.yarnpkg.com/lodash.snakecase/-/lodash.snakecase-4.1.1.tgz#39d714a35357147837aefd64b5dcbb16becd8f8d" 289 | integrity sha1-OdcUo1NXFHg3rv1ktdy7Fr7Nj40= 290 | 291 | log@1.4.0: 292 | version "1.4.0" 293 | resolved "https://registry.yarnpkg.com/log/-/log-1.4.0.tgz#4ba1d890fde249b031dca03bc37eaaf325656f1c" 294 | integrity sha1-S6HYkP3iSbAx3KA7w36q8yVlbxw= 295 | 296 | media-typer@0.3.0: 297 | version "0.3.0" 298 | resolved "https://registry.yarnpkg.com/media-typer/-/media-typer-0.3.0.tgz#8710d7af0aa626f8fffa1ce00168545263255748" 299 | integrity sha1-hxDXrwqmJvj/+hzgAWhUUmMlV0g= 300 | 301 | merge-descriptors@1.0.1: 302 | version "1.0.1" 303 | resolved "https://registry.yarnpkg.com/merge-descriptors/-/merge-descriptors-1.0.1.tgz#b00aaa556dd8b44568150ec9d1b953f3f90cbb61" 304 | integrity sha1-sAqqVW3YtEVoFQ7J0blT8/kMu2E= 305 | 306 | methods@~1.1.2: 307 | version "1.1.2" 308 | resolved "https://registry.yarnpkg.com/methods/-/methods-1.1.2.tgz#5529a4d67654134edcc5266656835b0f851afcee" 309 | integrity sha1-VSmk1nZUE07cxSZmVoNbD4Ua/O4= 310 | 311 | mime-db@1.40.0: 312 | version "1.40.0" 313 | resolved "https://registry.yarnpkg.com/mime-db/-/mime-db-1.40.0.tgz#a65057e998db090f732a68f6c276d387d4126c32" 314 | integrity sha512-jYdeOMPy9vnxEqFRRo6ZvTZ8d9oPb+k18PKoYNYUe2stVEBPPwsln/qWzdbmaIvnhZ9v2P+CuecK+fpUfsV2mA== 315 | 316 | mime-types@~2.1.24: 317 | version "2.1.24" 318 | resolved "https://registry.yarnpkg.com/mime-types/-/mime-types-2.1.24.tgz#b6f8d0b3e951efb77dedeca194cff6d16f676f81" 319 | integrity sha512-WaFHS3MCl5fapm3oLxU4eYDw77IQM2ACcxQ9RIxfaC3ooc6PFuBMGZZsYpvoXS5D5QTWPieo1jjLdAm3TBP3cQ== 320 | dependencies: 321 | mime-db "1.40.0" 322 | 323 | mime@1.6.0: 324 | version "1.6.0" 325 | resolved "https://registry.yarnpkg.com/mime/-/mime-1.6.0.tgz#32cd9e5c64553bd58d19a568af452acff04981b1" 326 | integrity sha512-x0Vn8spI+wuJ1O6S7gnbaQg8Pxh4NNHb7KSINmEWKiPE4RKOplvijn+NkmYmmRgP68mc70j2EbeTFRsrswaQeg== 327 | 328 | minimist@0.0.8: 329 | version "0.0.8" 330 | resolved "https://registry.yarnpkg.com/minimist/-/minimist-0.0.8.tgz#857fcabfc3397d2625b8228262e86aa7a011b05d" 331 | integrity sha1-hX/Kv8M5fSYluCKCYuhqp6ARsF0= 332 | 333 | mkdirp@0.5.1: 334 | version "0.5.1" 335 | resolved "https://registry.yarnpkg.com/mkdirp/-/mkdirp-0.5.1.tgz#30057438eac6cf7f8c4767f38648d6697d75c903" 336 | integrity sha1-MAV0OOrGz3+MR2fzhkjWaX11yQM= 337 | dependencies: 338 | minimist "0.0.8" 339 | 340 | ms@2.0.0: 341 | version "2.0.0" 342 | resolved "https://registry.yarnpkg.com/ms/-/ms-2.0.0.tgz#5608aeadfc00be6c2901df5f9861788de0d597c8" 343 | integrity sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g= 344 | 345 | ms@2.1.1: 346 | version "2.1.1" 347 | resolved "https://registry.yarnpkg.com/ms/-/ms-2.1.1.tgz#30a5864eb3ebb0a66f2ebe6d727af06a09d86e0a" 348 | integrity sha512-tgp+dl5cGk28utYktBsrFqA7HKgrhgPsg6Z/EfhWI4gl1Hwq8B/GmY/0oXZ6nF8hDVesS/FpnYaD/kOWhYQvyg== 349 | 350 | multiparty@~4.2.1: 351 | version "4.2.1" 352 | resolved "https://registry.yarnpkg.com/multiparty/-/multiparty-4.2.1.tgz#d9b6c46d8b8deab1ee70c734b0af771dd46e0b13" 353 | integrity sha512-AvESCnNoQlZiOfP9R4mxN8M9csy2L16EIbWIkt3l4FuGti9kXBS8QVzlfyg4HEnarJhrzZilgNFlZtqmoiAIIA== 354 | dependencies: 355 | fd-slicer "1.1.0" 356 | http-errors "~1.7.0" 357 | safe-buffer "5.1.2" 358 | uid-safe "2.1.5" 359 | 360 | negotiator@0.6.2: 361 | version "0.6.2" 362 | resolved "https://registry.yarnpkg.com/negotiator/-/negotiator-0.6.2.tgz#feacf7ccf525a77ae9634436a64883ffeca346fb" 363 | integrity sha512-hZXc7K2e+PgeI1eDBe/10Ard4ekbfrrqG8Ep+8Jmf4JID2bNg7NvCPOZN+kfF574pFQI7mum2AUqDidoKqcTOw== 364 | 365 | on-finished@~2.3.0: 366 | version "2.3.0" 367 | resolved "https://registry.yarnpkg.com/on-finished/-/on-finished-2.3.0.tgz#20f1336481b083cd75337992a16971aa2d906947" 368 | integrity sha1-IPEzZIGwg811M3mSoWlxqi2QaUc= 369 | dependencies: 370 | ee-first "1.1.1" 371 | 372 | optparse@1.0.4: 373 | version "1.0.4" 374 | resolved "https://registry.yarnpkg.com/optparse/-/optparse-1.0.4.tgz#c062579d2d05d243c221a304a71e0c979623ccf1" 375 | integrity sha1-wGJXnS0F0kPCIaMEpx4Ml5YjzPE= 376 | 377 | parseurl@~1.3.3: 378 | version "1.3.3" 379 | resolved "https://registry.yarnpkg.com/parseurl/-/parseurl-1.3.3.tgz#9da19e7bee8d12dff0513ed5b76957793bc2e8d4" 380 | integrity sha512-CiyeOxFT/JZyN5m0z9PfXw4SCBJ6Sygz1Dpl0wqjlhDEGGBP1GnsUVEL0p63hoG1fcj3fHynXi9NYO4nWOL+qQ== 381 | 382 | path-to-regexp@0.1.7: 383 | version "0.1.7" 384 | resolved "https://registry.yarnpkg.com/path-to-regexp/-/path-to-regexp-0.1.7.tgz#df604178005f522f15eb4490e7247a1bfaa67f8c" 385 | integrity sha1-32BBeABfUi8V60SQ5yR6G/qmf4w= 386 | 387 | pend@~1.2.0: 388 | version "1.2.0" 389 | resolved "https://registry.yarnpkg.com/pend/-/pend-1.2.0.tgz#7a57eb550a6783f9115331fcf4663d5c8e007a50" 390 | integrity sha1-elfrVQpng/kRUzH89GY9XI4AelA= 391 | 392 | proxy-addr@~2.0.5: 393 | version "2.0.5" 394 | resolved "https://registry.yarnpkg.com/proxy-addr/-/proxy-addr-2.0.5.tgz#34cbd64a2d81f4b1fd21e76f9f06c8a45299ee34" 395 | integrity sha512-t/7RxHXPH6cJtP0pRG6smSr9QJidhB+3kXu0KgXnbGYMgzEnUxRQ4/LDdfOwZEMyIh3/xHb8PX3t+lfL9z+YVQ== 396 | dependencies: 397 | forwarded "~0.1.2" 398 | ipaddr.js "1.9.0" 399 | 400 | qs@6.7.0: 401 | version "6.7.0" 402 | resolved "https://registry.yarnpkg.com/qs/-/qs-6.7.0.tgz#41dc1a015e3d581f1621776be31afb2876a9b1bc" 403 | integrity sha512-VCdBRNFTX1fyE7Nb6FYoURo/SPe62QCaAyzJvUjwRaIsc+NePBEniHlvxFmmX56+HZphIGtV0XeCirBtpDrTyQ== 404 | 405 | qs@~6.5.2: 406 | version "6.5.2" 407 | resolved "https://registry.yarnpkg.com/qs/-/qs-6.5.2.tgz#cb3ae806e8740444584ef154ce8ee98d403f3e36" 408 | integrity sha512-N5ZAX4/LxJmF+7wN74pUD6qAh9/wnvdQcjq9TZjevvXzSUo7bfmw91saqMjzGS2xq91/odN2dW/WOl7qQHNDGA== 409 | 410 | random-bytes@~1.0.0: 411 | version "1.0.0" 412 | resolved "https://registry.yarnpkg.com/random-bytes/-/random-bytes-1.0.0.tgz#4f68a1dc0ae58bd3fb95848c30324db75d64360b" 413 | integrity sha1-T2ih3Arli9P7lYSMMDJNt11kNgs= 414 | 415 | range-parser@~1.2.1: 416 | version "1.2.1" 417 | resolved "https://registry.yarnpkg.com/range-parser/-/range-parser-1.2.1.tgz#3cf37023d199e1c24d1a55b84800c2f3e6468031" 418 | integrity sha512-Hrgsx+orqoygnmhFbKaHE6c296J+HTAQXoxEF6gNupROmmGJRoyzfG3ccAveqCBrwr/2yxQ5BVd/GTl5agOwSg== 419 | 420 | raw-body@2.4.0: 421 | version "2.4.0" 422 | resolved "https://registry.yarnpkg.com/raw-body/-/raw-body-2.4.0.tgz#a1ce6fb9c9bc356ca52e89256ab59059e13d0332" 423 | integrity sha512-4Oz8DUIwdvoa5qMJelxipzi/iJIi40O5cGV1wNYp5hvZP8ZN0T+jiNkL0QepXs+EsQ9XJ8ipEDoiH70ySUJP3Q== 424 | dependencies: 425 | bytes "3.1.0" 426 | http-errors "1.7.2" 427 | iconv-lite "0.4.24" 428 | unpipe "1.0.0" 429 | 430 | safe-buffer@5.1.2: 431 | version "5.1.2" 432 | resolved "https://registry.yarnpkg.com/safe-buffer/-/safe-buffer-5.1.2.tgz#991ec69d296e0313747d59bdfd2b745c35f8828d" 433 | integrity sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g== 434 | 435 | "safer-buffer@>= 2.1.2 < 3": 436 | version "2.1.2" 437 | resolved "https://registry.yarnpkg.com/safer-buffer/-/safer-buffer-2.1.2.tgz#44fa161b0187b9549dd84bb91802f9bd8385cd6a" 438 | integrity sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg== 439 | 440 | scoped-http-client@0.11.0: 441 | version "0.11.0" 442 | resolved "https://registry.yarnpkg.com/scoped-http-client/-/scoped-http-client-0.11.0.tgz#887fa82a8360f15d639a52e504e563c157d26d74" 443 | integrity sha1-iH+oKoNg8V1jmlLlBOVjwVfSbXQ= 444 | 445 | send@0.17.1: 446 | version "0.17.1" 447 | resolved "https://registry.yarnpkg.com/send/-/send-0.17.1.tgz#c1d8b059f7900f7466dd4938bdc44e11ddb376c8" 448 | integrity sha512-BsVKsiGcQMFwT8UxypobUKyv7irCNRHk1T0G680vk88yf6LBByGcZJOTJCrTP2xVN6yI+XjPJcNuE3V4fT9sAg== 449 | dependencies: 450 | debug "2.6.9" 451 | depd "~1.1.2" 452 | destroy "~1.0.4" 453 | encodeurl "~1.0.2" 454 | escape-html "~1.0.3" 455 | etag "~1.8.1" 456 | fresh "0.5.2" 457 | http-errors "~1.7.2" 458 | mime "1.6.0" 459 | ms "2.1.1" 460 | on-finished "~2.3.0" 461 | range-parser "~1.2.1" 462 | statuses "~1.5.0" 463 | 464 | serve-static@1.14.1: 465 | version "1.14.1" 466 | resolved "https://registry.yarnpkg.com/serve-static/-/serve-static-1.14.1.tgz#666e636dc4f010f7ef29970a88a674320898b2f9" 467 | integrity sha512-JMrvUwE54emCYWlTI+hGrGv5I8dEwmco/00EvkzIIsR7MqrHonbD9pO2MOfFnpFntl7ecpZs+3mW+XbQZu9QCg== 468 | dependencies: 469 | encodeurl "~1.0.2" 470 | escape-html "~1.0.3" 471 | parseurl "~1.3.3" 472 | send "0.17.1" 473 | 474 | setprototypeof@1.1.1: 475 | version "1.1.1" 476 | resolved "https://registry.yarnpkg.com/setprototypeof/-/setprototypeof-1.1.1.tgz#7e95acb24aa92f5885e0abef5ba131330d4ae683" 477 | integrity sha512-JvdAWfbXeIGaZ9cILp38HntZSFSo3mWg6xGcJJsd+d4aRMOqauag1C63dJfDw7OaMYwEbHMOxEZ1lqVRYP2OAw== 478 | 479 | "statuses@>= 1.5.0 < 2", statuses@~1.5.0: 480 | version "1.5.0" 481 | resolved "https://registry.yarnpkg.com/statuses/-/statuses-1.5.0.tgz#161c7dac177659fd9811f43771fa99381478628c" 482 | integrity sha1-Fhx9rBd2Wf2YEfQ3cfqZOBR4Yow= 483 | 484 | strip-ansi@^3.0.0: 485 | version "3.0.1" 486 | resolved "https://registry.yarnpkg.com/strip-ansi/-/strip-ansi-3.0.1.tgz#6a385fb8853d952d5ff05d0e8aaf94278dc63dcf" 487 | integrity sha1-ajhfuIU9lS1f8F0Oiq+UJ43GPc8= 488 | dependencies: 489 | ansi-regex "^2.0.0" 490 | 491 | supports-color@^2.0.0: 492 | version "2.0.0" 493 | resolved "https://registry.yarnpkg.com/supports-color/-/supports-color-2.0.0.tgz#535d045ce6b6363fa40117084629995e9df324c7" 494 | integrity sha1-U10EXOa2Nj+kARcIRimZXp3zJMc= 495 | 496 | toidentifier@1.0.0: 497 | version "1.0.0" 498 | resolved "https://registry.yarnpkg.com/toidentifier/-/toidentifier-1.0.0.tgz#7e1be3470f1e77948bc43d94a3c8f4d7752ba553" 499 | integrity sha512-yaOH/Pk/VEhBWWTlhI+qXxDFXlejDGcQipMlyxda9nthulaxLZUNcUqFxokp0vcYnvteJln5FNQDRrxj3YcbVw== 500 | 501 | type-is@~1.6.16, type-is@~1.6.17, type-is@~1.6.18: 502 | version "1.6.18" 503 | resolved "https://registry.yarnpkg.com/type-is/-/type-is-1.6.18.tgz#4e552cd05df09467dcbc4ef739de89f2cf37c131" 504 | integrity sha512-TkRKr9sUTxEH8MdfuCSP7VizJyzRNMjj2J2do2Jr3Kym598JVdEksuzPQCnlFPW4ky9Q+iA+ma9BGm06XQBy8g== 505 | dependencies: 506 | media-typer "0.3.0" 507 | mime-types "~2.1.24" 508 | 509 | uid-safe@2.1.5: 510 | version "2.1.5" 511 | resolved "https://registry.yarnpkg.com/uid-safe/-/uid-safe-2.1.5.tgz#2b3d5c7240e8fc2e58f8aa269e5ee49c0857bd3a" 512 | integrity sha512-KPHm4VL5dDXKz01UuEd88Df+KzynaohSL9fBh096KWAxSKZQDI2uBrVqtvRM4rwrIrRRKsdLNML/lnaaVSRioA== 513 | dependencies: 514 | random-bytes "~1.0.0" 515 | 516 | unpipe@1.0.0, unpipe@~1.0.0: 517 | version "1.0.0" 518 | resolved "https://registry.yarnpkg.com/unpipe/-/unpipe-1.0.0.tgz#b2bf4ee8514aae6165b4817829d21b2ef49904ec" 519 | integrity sha1-sr9O6FFKrmFltIF4KdIbLvSZBOw= 520 | 521 | utils-merge@1.0.1: 522 | version "1.0.1" 523 | resolved "https://registry.yarnpkg.com/utils-merge/-/utils-merge-1.0.1.tgz#9f95710f50a267947b2ccc124741c1028427e713" 524 | integrity sha1-n5VxD1CiZ5R7LMwSR0HBAoQn5xM= 525 | 526 | vary@~1.1.2: 527 | version "1.1.2" 528 | resolved "https://registry.yarnpkg.com/vary/-/vary-1.1.2.tgz#2299f02c6ded30d4a5961b0b9f74524a18f634fc" 529 | integrity sha1-IpnwLG3tMNSllhsLn3RSShj2NPw= 530 | --------------------------------------------------------------------------------