lita-confirmation 0.0.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA1:
3
+ metadata.gz: e2c924f5bde1d77a7df72e5a9c2740a4938741b2
4
+ data.tar.gz: b1ca21f9a0768bf904d13f05c1f8efb0d9f252b5
5
+ SHA512:
6
+ metadata.gz: 3d15be8fb17d7b2bc78f99494e77030c5b330dba303dfb077df3c79173c9144a56661ad84a93258aeb40887b4d6e8790a7dcc9cd03fc876e9a4be3cd60047c25
7
+ data.tar.gz: 01fb383bd4ebbdf4c50692abf78f0036b6a0e8cc16fb7ee0b577fe462e93b710ea89c2ede3046b481a15e891964870afc01e0a1ed42de8524f51b6b048744220
@@ -0,0 +1,17 @@
1
+ *.gem
2
+ *.rbc
3
+ .bundle
4
+ .config
5
+ .yardoc
6
+ Gemfile.lock
7
+ InstalledFiles
8
+ _yardoc
9
+ coverage
10
+ doc/
11
+ lib/bundler/man
12
+ pkg
13
+ rdoc
14
+ spec/reports
15
+ test/tmp
16
+ test/version_tmp
17
+ tmp
@@ -0,0 +1,12 @@
1
+ language: ruby
2
+ rvm:
3
+ - 2.0.0
4
+ script: bundle exec rake
5
+ before_install:
6
+ - gem update --system
7
+ services:
8
+ - redis-server
9
+ notifications:
10
+ webhooks:
11
+ urls:
12
+ - https://lita-freenode.herokuapp.com/travis
data/Gemfile ADDED
@@ -0,0 +1,3 @@
1
+ source "https://rubygems.org"
2
+
3
+ gemspec
data/LICENSE ADDED
@@ -0,0 +1,19 @@
1
+ Copyright (c) 2014 Jimmy Cuadra
2
+
3
+ Permission is hereby granted, free of charge, to any person obtaining a copy
4
+ of this software and associated documentation files (the "Software"), to deal
5
+ in the Software without restriction, including without limitation the rights
6
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
7
+ copies of the Software, and to permit persons to whom the Software is
8
+ furnished to do so, subject to the following conditions:
9
+
10
+ The above copyright notice and this permission notice shall be included in
11
+ all copies or substantial portions of the Software.
12
+
13
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
14
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
15
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
16
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
17
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
18
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
19
+ THE SOFTWARE.
@@ -0,0 +1,92 @@
1
+ # lita-confirmation
2
+
3
+ [![Build Status](https://travis-ci.org/jimmycuadra/lita-confirmation.png?branch=master)](https://travis-ci.org/jimmycuadra/lita-confirmation)
4
+ [![Code Climate](https://codeclimate.com/github/jimmycuadra/lita-confirmation.png)](https://codeclimate.com/github/jimmycuadra/lita-confirmation)
5
+ [![Coverage Status](https://coveralls.io/repos/jimmycuadra/lita-confirmation/badge.png)](https://coveralls.io/r/jimmycuadra/lita-confirmation)
6
+
7
+ **lita-confirmation** is an extension for [Lita](https://www.lita.io/) that allows handler routes to require "confirmation" before being triggered. Confirmation consists of a second message sent to the robot with a confirmation code.
8
+
9
+ ## Installation
10
+
11
+ Add lita-confirmation to your Lita plugin's gemspec:
12
+
13
+ ``` ruby
14
+ spec.add_runtime_dependency "lita-confirmation"
15
+ ```
16
+
17
+ ## Usage
18
+
19
+ ### Basic confirmation
20
+
21
+ For basic confirmation, simply set the `:confirmation` option to true when defining a route.
22
+
23
+ ``` ruby
24
+ route /danger/, :danger, command: true, confirmation: true
25
+ ```
26
+
27
+ This will result in the following behavior:
28
+
29
+ ```
30
+ Alice: Lita, danger
31
+ Lita: This command requires confirmation. To confirm, send the command "confirm 636f308"
32
+ Alice: Lita, confirm 636f308
33
+ Lita: Dangerous command executed!
34
+ ```
35
+
36
+ ### Customized confirmation
37
+
38
+ There are a few different options that can be supplied to customize the way the confirmation behaves. To supply one or more options, pass a hash as the value for the `:confirmation` option instead of just a boolean.
39
+
40
+ #### allow_self
41
+
42
+ By default, the same user who initially triggered the command can confirm it. If you want to make it even harder to trigger a command accidentally, you can require that another user send the confirmation command by setting the `:allow_self` option to false.
43
+
44
+ ``` ruby
45
+ route /danger/, :danger, command: true, confirmation: { allow_self: false }
46
+ ```
47
+
48
+ ```
49
+ Alice: Lita, danger
50
+ Lita: This command requires confirmation. To confirm, send the command "confirm 636f308"
51
+ Alice: Lita, confirm 636f308
52
+ Lita: Confirmation 636f308 must come from a different user.
53
+ Bob: Lita, confirm 636f308
54
+ Lita: Dangerous command executed!
55
+ ```
56
+
57
+ #### restrict_to
58
+
59
+ If you want to require that the confirming user be a member of a particular authorization group, use the `:restrict_to` option. The value can be either a string, a symbol, or an array or strings/symbols.
60
+
61
+ ``` ruby
62
+ route /danger/, :danger, command: true, confirmation: { restrict_to: :managers }
63
+ ```
64
+
65
+ ```
66
+ Alice: Lita, danger
67
+ Lita: This command requires confirmation. To confirm, send the command "confirm 636f308"
68
+ Alice: Lita, confirm 636f308
69
+ Lita: Confirmation 636f308 must come from a user in one of the following authorization groups: managers
70
+ Manager: Lita, confirm 636f308
71
+ Lita: Dangerous command executed!
72
+ ```
73
+
74
+ #### expire_after
75
+
76
+ By default, a confirmation must be made within one minute of the original command. After the expiry period, the original command must be sent again, and a new confirmation code will be generated. To change the length of the expiry, set the `:expire_after` value to an integer or string number of seconds.
77
+
78
+ ``` ruby
79
+ route /danger/, :danger, command: true, confirmation: { expire_after: 10 }
80
+ ```
81
+
82
+ ```
83
+ Alice: Lita, danger
84
+ Lita: This command requires confirmation. To confirm, send the command "confirm 636f308"
85
+ Alice: Waiting 15 seconds...
86
+ Alice: Lita, confirm 636f308
87
+ Lita: 636f308 is not a valid confirmation code. It may have expired. Please run the original command agin.
88
+ ```
89
+
90
+ ## License
91
+
92
+ [MIT](http://opensource.org/licenses/MIT)
@@ -0,0 +1,6 @@
1
+ require "bundler/gem_tasks"
2
+ require "rspec/core/rake_task"
3
+
4
+ RSpec::Core::RakeTask.new(:spec)
5
+
6
+ task default: :spec
@@ -0,0 +1,11 @@
1
+ require "securerandom"
2
+
3
+ require "lita"
4
+
5
+ Lita.load_locales Dir[File.expand_path(
6
+ File.join("..", "..", "locales", "*.yml"), __FILE__
7
+ )]
8
+
9
+ require "lita/handlers/confirmation"
10
+ require "lita/extensions/confirmation/unconfirmed_command"
11
+ require "lita/extensions/confirmation"
@@ -0,0 +1,40 @@
1
+ module Lita
2
+ module Extensions
3
+ class Confirmation
4
+ attr_reader :handler, :message, :robot, :route
5
+
6
+ def self.call(payload)
7
+ new(
8
+ payload.fetch(:handler),
9
+ payload.fetch(:message),
10
+ payload.fetch(:robot),
11
+ payload.fetch(:route)
12
+ ).call
13
+ end
14
+
15
+ def initialize(handler, message, robot, route)
16
+ @handler = handler
17
+ @message = message
18
+ @robot = robot
19
+ @route = route
20
+ end
21
+
22
+ def call
23
+ if (options = route.extensions[:confirmation])
24
+ message.reply(
25
+ I18n.t(
26
+ "lita.extensions.confirmation.request",
27
+ code: UnconfirmedCommand.new(handler, message, robot, route, options).code
28
+ )
29
+ )
30
+
31
+ return false
32
+ end
33
+
34
+ true
35
+ end
36
+ end
37
+
38
+ Lita.register_hook(:validate_route, Confirmation)
39
+ end
40
+ end
@@ -0,0 +1,77 @@
1
+ require "securerandom"
2
+
3
+ module Lita
4
+ module Extensions
5
+ class Confirmation
6
+ class UnconfirmedCommand
7
+ attr_reader :allow_self, :code, :groups, :handler, :message, :robot, :route, :timer_thread
8
+
9
+ class << self
10
+ def find(code)
11
+ confirmations[code]
12
+ end
13
+
14
+ def confirmations
15
+ @confirmations ||= {}
16
+ end
17
+
18
+ def reset
19
+ confirmations.clear
20
+ end
21
+ end
22
+
23
+ def initialize(handler, message, robot, route, options)
24
+ @handler = handler
25
+ @message = message
26
+ @robot = robot
27
+ @route = route
28
+
29
+ @code = SecureRandom.hex(3)
30
+
31
+ self.class.confirmations[code] = self
32
+
33
+ process_options(options)
34
+ end
35
+
36
+ def call(user)
37
+ return :other_user_required if disallow_self?(user)
38
+ return :user_in_group_required unless in_required_group?(user)
39
+
40
+ expire
41
+ timer_thread.kill if timer_thread
42
+ handler.dispatch_to_route(route, robot, message)
43
+ end
44
+
45
+ private
46
+
47
+ def disallow_self?(confirming_user)
48
+ true if !allow_self && message.user == confirming_user
49
+ end
50
+
51
+ def expire
52
+ self.class.confirmations.delete(code)
53
+ end
54
+
55
+ def in_required_group?(user)
56
+ return true unless groups
57
+
58
+ groups.any? { |group| Lita::Authorization.user_in_group?(user, group) }
59
+ end
60
+
61
+ def process_options(options)
62
+ options = Hash === options ? options : {}
63
+
64
+ @allow_self = options.key?(:allow_self) ? options[:allow_self] : true
65
+ @groups = options.key?(:restrict_to) ? Array(options[:restrict_to]) : nil
66
+
67
+ expiry = options.key?(:expire_after) ? options[:expire_after] : 60
68
+ @timer_thread = Thread.new do
69
+ Lita::Timer.new(interval: expiry) do
70
+ expire
71
+ end.start
72
+ end
73
+ end
74
+ end
75
+ end
76
+ end
77
+ end
@@ -0,0 +1,36 @@
1
+ module Lita
2
+ module Handlers
3
+ class Confirmation < Handler
4
+ route /^confirm\s+([a-f0-9]{6})$/i, :confirm, command: true, help: {
5
+ t("help.key") => t("help.value")
6
+ }
7
+
8
+ def confirm(response)
9
+ code = response.matches[0][0]
10
+
11
+ command = Extensions::Confirmation::UnconfirmedCommand.find(code)
12
+
13
+ if command
14
+ call_command(command, code, response)
15
+ else
16
+ response.reply(t("invalid_code", code: code))
17
+ end
18
+ end
19
+
20
+ private
21
+
22
+ def call_command(command, code, response)
23
+ case command.call(response.user)
24
+ when :other_user_required
25
+ response.reply(t("other_user_required", code: code))
26
+ when :user_in_group_required
27
+ response.reply(
28
+ t("user_in_group_required", code: code, groups: command.groups.join(", "))
29
+ )
30
+ end
31
+ end
32
+ end
33
+
34
+ Lita.register_handler(Confirmation)
35
+ end
36
+ end
@@ -0,0 +1,24 @@
1
+ Gem::Specification.new do |spec|
2
+ spec.name = "lita-confirmation"
3
+ spec.version = "0.0.1"
4
+ spec.authors = ["Jimmy Cuadra"]
5
+ spec.email = ["jimmy@jimmycuadra.com"]
6
+ spec.description = %q{A Lita extension to require confirmation for commands.}
7
+ spec.summary = %q{A Lita extension to require confirmation for potentially dangerous commands.}
8
+ spec.homepage = "https://github.com/jimmycuadra/lita-confirmation"
9
+ spec.license = "MIT"
10
+ spec.metadata = { "lita_plugin_type" => "extension" }
11
+
12
+ spec.files = `git ls-files`.split($/)
13
+ spec.executables = spec.files.grep(%r{^bin/}) { |f| File.basename(f) }
14
+ spec.test_files = spec.files.grep(%r{^(test|spec|features)/})
15
+ spec.require_paths = ["lib"]
16
+
17
+ spec.add_runtime_dependency "lita", ">= 3.3"
18
+
19
+ spec.add_development_dependency "bundler", "~> 1.3"
20
+ spec.add_development_dependency "rake"
21
+ spec.add_development_dependency "rspec", ">= 3.0.0.beta2"
22
+ spec.add_development_dependency "simplecov"
23
+ spec.add_development_dependency "coveralls"
24
+ end
@@ -0,0 +1,13 @@
1
+ en:
2
+ lita:
3
+ extensions:
4
+ confirmation:
5
+ request: This command requires confirmation. To confirm, send the command "confirm %{code}"
6
+ handlers:
7
+ confirmation:
8
+ help:
9
+ key: confirm CODE
10
+ value: Confirms a previously sent command with the confirmation code CODE.
11
+ invalid_code: "%{code} is not a valid confirmation code. It may have expired. Please run the original command agin."
12
+ other_user_required: "Confirmation %{code} must come from a different user."
13
+ user_in_group_required: "Confirmation %{code} must come from a user in one of the following authorization groups: %{groups}"
@@ -0,0 +1,125 @@
1
+ require "spec_helper"
2
+
3
+ class Dangerous < Lita::Handler
4
+ route /^danger$/, :danger, command: true, confirmation: true
5
+ route /^danger self$/, :disallow_self, command: true, confirmation: { allow_self: false }
6
+ route(
7
+ /^danger restrict$/,
8
+ :require_auth_group,
9
+ command: true,
10
+ confirmation: { restrict_to: :managers }
11
+ )
12
+ route /^danger expire$/, :expire_early, command: true, confirmation: { expire_after: 0 }
13
+
14
+ def danger(response)
15
+ response.reply("Dangerous command executed!")
16
+ end
17
+
18
+ def disallow_self(response)
19
+ response.reply("Dangerous command confirmed by another user and executed!")
20
+ end
21
+
22
+ def require_auth_group(response)
23
+ response.reply("Dangerous command confirmed by a manager!")
24
+ end
25
+
26
+ def expire_early(response)
27
+ response.reply("Dangerous command executed within 0 seconds!")
28
+ end
29
+ end
30
+
31
+ describe Dangerous, lita_handler: true do
32
+ before do
33
+ allow(Lita).to receive(:handlers).and_return([described_class, Lita::Handlers::Confirmation])
34
+ Lita::Extensions::Confirmation::UnconfirmedCommand.reset
35
+ end
36
+
37
+ context "with confirmation: true" do
38
+ it "requires confirmation" do
39
+ send_command("danger")
40
+ expect(replies.last).to match(/send the command "confirm [a-f0-9]{6}"/)
41
+ end
42
+
43
+ it "invokes the original route on confirmation" do
44
+ send_command("danger")
45
+ code = replies.last.match(/([a-f0-9]{6})"$/)[1]
46
+ send_command("confirm #{code}")
47
+ expect(replies.last).to eq("Dangerous command executed!")
48
+ end
49
+
50
+ it "expires when confirmed" do
51
+ send_command("danger")
52
+ code = replies.last.match(/([a-f0-9]{6})"$/)[1]
53
+ send_command("confirm #{code}")
54
+ send_command("confirm #{code}")
55
+ expect(replies.last).to include("not a valid confirmation code")
56
+ end
57
+
58
+ it "responds with a message when an invalid code is provided" do
59
+ send_command("danger")
60
+ send_command("confirm 000000")
61
+ expect(replies.last).to include("000000 is not a valid confirmation code")
62
+ end
63
+ end
64
+
65
+ context "with allow_self: false" do
66
+ it "responds with a message if the user tries to confirm their own command" do
67
+ send_command("danger self")
68
+ code = replies.last.match(/([a-f0-9]{6})"$/)[1]
69
+ send_command("confirm #{code}")
70
+ expect(replies.last).to include("must come from a different user")
71
+ end
72
+
73
+ it "invokes the original route on confirmation by another user" do
74
+ send_command("danger self")
75
+ code = replies.last.match(/([a-f0-9]{6})"$/)[1]
76
+ send_command("confirm #{code}", as: Lita::User.create(123))
77
+ expect(replies.last).to eq("Dangerous command confirmed by another user and executed!")
78
+ end
79
+ end
80
+
81
+ context "with restrict_to: :managers" do
82
+ let(:manager) do
83
+ manager = Lita::User.create(123)
84
+ allow(Lita::Authorization).to receive(:user_in_group?).with(
85
+ manager, :managers
86
+ ).and_return(true)
87
+ manager
88
+ end
89
+
90
+ it "responds with a message if a user not in a required group tries to confirm a command" do
91
+ send_command("danger restrict")
92
+ code = replies.last.match(/([a-f0-9]{6})"$/)[1]
93
+ send_command("confirm #{code}")
94
+ expect(replies.last).to include(
95
+ "must come from a user in one of the following authorization groups: managers"
96
+ )
97
+ end
98
+
99
+ it "invokes the original route on confirmation by a manager" do
100
+ send_command("danger restrict")
101
+ code = replies.last.match(/([a-f0-9]{6})"$/)[1]
102
+ send_command("confirm #{code}", as: manager)
103
+ expect(replies.last).to include("confirmed by a manager")
104
+ end
105
+ end
106
+
107
+ context "with expire_after: 0" do
108
+ before { allow(Thread).to receive(:new) }
109
+
110
+ it "invokes the original route on confirmation within the expiry" do
111
+ send_command("danger expire")
112
+ code = replies.last.match(/([a-f0-9]{6})"$/)[1]
113
+ send_command("confirm #{code}")
114
+ expect(replies.last).to include("within 0 seconds")
115
+ end
116
+
117
+ it "responds that the code is invalid after 0 seconds" do
118
+ allow(Thread).to receive(:new).and_yield
119
+ send_command("danger expire")
120
+ code = replies.last.match(/([a-f0-9]{6})"$/)[1]
121
+ send_command("confirm #{code}")
122
+ expect(replies.last).to include("not a valid confirmation code")
123
+ end
124
+ end
125
+ end
@@ -0,0 +1,10 @@
1
+ require "simplecov"
2
+ require "coveralls"
3
+ SimpleCov.formatter = SimpleCov::Formatter::MultiFormatter[
4
+ SimpleCov::Formatter::HTMLFormatter,
5
+ Coveralls::SimpleCov::Formatter
6
+ ]
7
+ SimpleCov.start { add_filter "/spec/" }
8
+
9
+ require "lita-confirmation"
10
+ require "lita/rspec"
metadata ADDED
@@ -0,0 +1,145 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: lita-confirmation
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.0.1
5
+ platform: ruby
6
+ authors:
7
+ - Jimmy Cuadra
8
+ autorequire:
9
+ bindir: bin
10
+ cert_chain: []
11
+ date: 2014-06-19 00:00:00.000000000 Z
12
+ dependencies:
13
+ - !ruby/object:Gem::Dependency
14
+ name: lita
15
+ requirement: !ruby/object:Gem::Requirement
16
+ requirements:
17
+ - - ">="
18
+ - !ruby/object:Gem::Version
19
+ version: '3.3'
20
+ type: :runtime
21
+ prerelease: false
22
+ version_requirements: !ruby/object:Gem::Requirement
23
+ requirements:
24
+ - - ">="
25
+ - !ruby/object:Gem::Version
26
+ version: '3.3'
27
+ - !ruby/object:Gem::Dependency
28
+ name: bundler
29
+ requirement: !ruby/object:Gem::Requirement
30
+ requirements:
31
+ - - "~>"
32
+ - !ruby/object:Gem::Version
33
+ version: '1.3'
34
+ type: :development
35
+ prerelease: false
36
+ version_requirements: !ruby/object:Gem::Requirement
37
+ requirements:
38
+ - - "~>"
39
+ - !ruby/object:Gem::Version
40
+ version: '1.3'
41
+ - !ruby/object:Gem::Dependency
42
+ name: rake
43
+ requirement: !ruby/object:Gem::Requirement
44
+ requirements:
45
+ - - ">="
46
+ - !ruby/object:Gem::Version
47
+ version: '0'
48
+ type: :development
49
+ prerelease: false
50
+ version_requirements: !ruby/object:Gem::Requirement
51
+ requirements:
52
+ - - ">="
53
+ - !ruby/object:Gem::Version
54
+ version: '0'
55
+ - !ruby/object:Gem::Dependency
56
+ name: rspec
57
+ requirement: !ruby/object:Gem::Requirement
58
+ requirements:
59
+ - - ">="
60
+ - !ruby/object:Gem::Version
61
+ version: 3.0.0.beta2
62
+ type: :development
63
+ prerelease: false
64
+ version_requirements: !ruby/object:Gem::Requirement
65
+ requirements:
66
+ - - ">="
67
+ - !ruby/object:Gem::Version
68
+ version: 3.0.0.beta2
69
+ - !ruby/object:Gem::Dependency
70
+ name: simplecov
71
+ requirement: !ruby/object:Gem::Requirement
72
+ requirements:
73
+ - - ">="
74
+ - !ruby/object:Gem::Version
75
+ version: '0'
76
+ type: :development
77
+ prerelease: false
78
+ version_requirements: !ruby/object:Gem::Requirement
79
+ requirements:
80
+ - - ">="
81
+ - !ruby/object:Gem::Version
82
+ version: '0'
83
+ - !ruby/object:Gem::Dependency
84
+ name: coveralls
85
+ requirement: !ruby/object:Gem::Requirement
86
+ requirements:
87
+ - - ">="
88
+ - !ruby/object:Gem::Version
89
+ version: '0'
90
+ type: :development
91
+ prerelease: false
92
+ version_requirements: !ruby/object:Gem::Requirement
93
+ requirements:
94
+ - - ">="
95
+ - !ruby/object:Gem::Version
96
+ version: '0'
97
+ description: A Lita extension to require confirmation for commands.
98
+ email:
99
+ - jimmy@jimmycuadra.com
100
+ executables: []
101
+ extensions: []
102
+ extra_rdoc_files: []
103
+ files:
104
+ - ".gitignore"
105
+ - ".travis.yml"
106
+ - Gemfile
107
+ - LICENSE
108
+ - README.md
109
+ - Rakefile
110
+ - lib/lita-confirmation.rb
111
+ - lib/lita/extensions/confirmation.rb
112
+ - lib/lita/extensions/confirmation/unconfirmed_command.rb
113
+ - lib/lita/handlers/confirmation.rb
114
+ - lita-confirmation.gemspec
115
+ - locales/en.yml
116
+ - spec/lita/extensions/confirmation_spec.rb
117
+ - spec/spec_helper.rb
118
+ homepage: https://github.com/jimmycuadra/lita-confirmation
119
+ licenses:
120
+ - MIT
121
+ metadata:
122
+ lita_plugin_type: extension
123
+ post_install_message:
124
+ rdoc_options: []
125
+ require_paths:
126
+ - lib
127
+ required_ruby_version: !ruby/object:Gem::Requirement
128
+ requirements:
129
+ - - ">="
130
+ - !ruby/object:Gem::Version
131
+ version: '0'
132
+ required_rubygems_version: !ruby/object:Gem::Requirement
133
+ requirements:
134
+ - - ">="
135
+ - !ruby/object:Gem::Version
136
+ version: '0'
137
+ requirements: []
138
+ rubyforge_project:
139
+ rubygems_version: 2.2.2
140
+ signing_key:
141
+ specification_version: 4
142
+ summary: A Lita extension to require confirmation for potentially dangerous commands.
143
+ test_files:
144
+ - spec/lita/extensions/confirmation_spec.rb
145
+ - spec/spec_helper.rb