hipchat-secrets 0.9.1

Sign up to get free protection for your applications and to get access to all the features.
data/.gitignore ADDED
@@ -0,0 +1,2 @@
1
+ Gemfile.lock
2
+ tmp
data/Gemfile ADDED
@@ -0,0 +1,3 @@
1
+ source 'http://rubygems.org'
2
+
3
+ gemspec
data/Guardfile ADDED
@@ -0,0 +1,15 @@
1
+ # More info at https://github.com/guard/guard#readme
2
+ interactor :off
3
+
4
+ guard 'bundler' do
5
+ watch('Gemfile')
6
+ watch(%r{\.gemspec$})
7
+ end
8
+
9
+ guard 'rspec', :cli => '--drb' do
10
+ watch(%r{^spec/.+_spec\.rb$})
11
+ watch(%r{^lib/(.+)\.rb$}) { |m| "spec/lib/#{m[1]}_spec.rb" }
12
+
13
+ watch('spec/spec_helper.rb') { "spec" }
14
+ watch(%r{^spec/support/(.+)\.rb$}) { "spec" }
15
+ end
data/LICENSE.txt ADDED
@@ -0,0 +1,22 @@
1
+ Copyright © 2013 Jeremy Ebler
2
+
3
+ MIT License
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining
6
+ a copy of this software and associated documentation files (the
7
+ "Software"), to deal in the Software without restriction, including
8
+ without limitation the rights to use, copy, modify, merge, publish,
9
+ distribute, sublicense, and/or sell copies of the Software, and to
10
+ permit persons to whom the Software is furnished to do so, subject to
11
+ the following conditions:
12
+
13
+ The above copyright notice and this permission notice shall be
14
+ included in all copies or substantial portions of the Software.
15
+
16
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
17
+ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
18
+ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
19
+ NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
20
+ LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
21
+ OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
22
+ WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
data/Rakefile ADDED
@@ -0,0 +1 @@
1
+ require "bundler/gem_tasks"
data/Readme.md ADDED
@@ -0,0 +1,66 @@
1
+ hipchat-secrets
2
+ ===============
3
+
4
+ Decode the weakly crypted password from the hipchat configuration file. The API allows decoding/encoding but the wrapper script only decodes passwords. See the specs, if you care.
5
+
6
+ ## Prerequsite: Find the HipChat Secret
7
+
8
+ 1. Discover Hipchat's Secret Hashing key. You're on your own for this.
9
+ 1. Put the secret in ~/.hipchat_secret or in your environment, HIPCHAT_SECRET
10
+ 1. …
11
+ 1. Profit!
12
+
13
+ ## Example Usage
14
+
15
+ Automagical:
16
+
17
+ ```
18
+ $ hipchat-secrets
19
+ Analyzing HipChat config: /Users/xxx/Library/Preferences/com.hipchat.xxx/Local Store/hipchatConfig.json
20
+
21
+ xxx@xxx.com's password is xxx
22
+ ```
23
+
24
+ With non-standard config file location:
25
+
26
+ ```
27
+ $ hipchat-secrets /some/other/file/that/was/a/hipchatConfig.json
28
+ Analyzing HipChat config: /some/other/file/that/was/a/hipchatConfig.json
29
+
30
+ xxx@xxx.com's password is xxx
31
+ ```
32
+
33
+ With secret from environment:
34
+
35
+ ```
36
+ $ HIPCHAT_SECRET=IFoundTheSecret hipchat-secrets
37
+ ```
38
+
39
+ Windows:
40
+
41
+ ```
42
+ > env HIPCHAT_SECRET=IFoundTheSecret hipchat-secrets
43
+ ```
44
+
45
+
46
+ ## Tested against
47
+
48
+ - 1.8.7-p371
49
+ - 1.9.2-p320
50
+ - 1.9.3-p374
51
+ - 2.0.0-rc1
52
+ - jruby-1.7.0
53
+ - jruby-1.7.2
54
+
55
+
56
+ ## Contributing
57
+
58
+ 1. Fork it
59
+ 2. Create your feature branch (`git checkout -b my-new-feature`)
60
+ 3. Commit your changes (`git commit -am 'Add some feature'`)
61
+ 4. Push to the branch (`git push origin my-new-feature`)
62
+ 5. Create new Pull Request
63
+
64
+ ## Come on Atlassian
65
+
66
+ Seriously. Your password _encryption_ is hardly better than plaintext. Use real encryption to protect secrets.
@@ -0,0 +1,13 @@
1
+ #!/usr/bin/env ruby
2
+ # hipchat-secrets.rb
3
+ require 'rubygems'
4
+
5
+ $:<< File.join(File.dirname(__FILE__), '../lib')
6
+ require 'settings_file'
7
+ require 'crypt'
8
+
9
+ settings = HipChatSecrets::SettingsFile.new ARGV[0]
10
+
11
+ puts "Analyzing HipChat config: #{settings.config_file}",
12
+ nil,
13
+ "#{settings.email}'s password is #{HipChatSecrets::Crypt.decode settings.password}"
@@ -0,0 +1,28 @@
1
+ # encoding: utf-8
2
+ lib = File.expand_path('../lib', __FILE__)
3
+ $LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
4
+ require 'version'
5
+
6
+ Gem::Specification.new do |gem|
7
+ gem.name = "hipchat-secrets"
8
+ gem.version = HipChatSecrets::VERSION
9
+ gem.authors = ["Jeremy Ebler"]
10
+ gem.email = ["jebler@gmail.com"]
11
+ gem.description = %q{Extract secrets from hipchat configuration files}
12
+ gem.summary = %q{Decode the weakly crypted password from the hipchat configuration file. The API allows decoding/encoding—everything you need to discover the secret key!}
13
+ gem.homepage = "https://github.com/whitehat101/hipchat-secrets"
14
+
15
+ gem.files = `git ls-files`.split($/)
16
+ gem.executables = gem.files.grep(%r{^bin/}).map{ |f| File.basename(f) }
17
+ gem.test_files = gem.files.grep(%r{^spec/})
18
+ gem.require_paths = ["lib"]
19
+
20
+ gem.add_dependency 'json'
21
+ # gem.add_dependency 'base64'
22
+
23
+ gem.add_development_dependency 'spork'
24
+ gem.add_development_dependency 'rspec'
25
+ gem.add_development_dependency 'guard-rspec'
26
+ gem.add_development_dependency 'guard-bundler'
27
+ gem.add_development_dependency 'rb-fsevent', '~> 0.9.1'
28
+ end
data/lib/crypt.rb ADDED
@@ -0,0 +1,51 @@
1
+ # crypt.rb
2
+ require 'base64'
3
+
4
+ module HipChatSecrets
5
+ class Crypt
6
+
7
+ def self.encode str
8
+ Base64::encode64(xor str).strip
9
+ end
10
+
11
+ def self.decode str
12
+ xor Base64::decode64(str)
13
+ end
14
+
15
+ def self.xor input
16
+ input = input.unpack 'U*'
17
+ output = []
18
+
19
+ input.each_with_index do |num,index|
20
+ output << (num ^ secret[index%secret.length])
21
+ end
22
+
23
+ output.pack 'U*'
24
+ end
25
+
26
+ # You have to figure out the Secret on your own. Good luck!
27
+
28
+ def self.secret
29
+ return @@key if defined? @@key
30
+ key_file = File.expand_path('~/.hipchat_secret')
31
+
32
+ send 'secret=',
33
+ if ENV['HIPCHAT_SECRET']
34
+ ENV['HIPCHAT_SECRET']
35
+ elsif File.exists? key_file
36
+ File.open(key_file, 'r') {|f| f.read }
37
+ else
38
+ raise "Could not locate HipChat Secret Key in HIPCHAT_SECRET or #{key_file}"
39
+ end
40
+ end
41
+
42
+ def self.secret= key
43
+ @@key = key.strip.unpack 'U*'
44
+ end
45
+
46
+ def self.secret_str
47
+ secret.pack 'U*'
48
+ end
49
+
50
+ end
51
+ end
@@ -0,0 +1,59 @@
1
+ # settings_file.rb
2
+ require 'json'
3
+
4
+ module HipChatSecrets
5
+ class SettingsFile
6
+ attr_reader :config_file, :config
7
+
8
+ def initialize setting_path=nil
9
+ configs = find_configs(setting_path)
10
+ raise "Could not locate any config files." if configs.length < 1
11
+ @config_file = configs.first
12
+ parse_config
13
+ end
14
+
15
+ # pass unknown method calls to the config object
16
+ def method_missing meth, *args, &block
17
+ if @config.include? meth.to_s
18
+ @config[meth.to_s]
19
+ else
20
+ super
21
+ end
22
+ end
23
+
24
+ private
25
+
26
+ def find_configs additional_path=nil
27
+ possible_configs = [
28
+ additional_path,
29
+ "~/Library/Preferences/com.hipchat.87969878BBF1203EC547B61E69990E8273C4626D.1/Local Store/hipchatConfig.json", # OS X
30
+ "~/.appdata/com.hipchat.87969878BBF1203EC547B61E69990E8273C4626D.1/Local Store/hipchatConfig.json", # Linux
31
+ "~/AppData/Roaming/com.hipchat.87969878BBF1203EC547B61E69990E8273C4626D.1/Local Store/hipchatConfig.json", # Win 7
32
+ # TODO: where does older windows stash this file? does anyone care?
33
+ ].compact.map {|path| File.expand_path path }
34
+
35
+ Dir[*possible_configs]
36
+ end
37
+
38
+ def parse_config
39
+ config_data = File.open(@config_file,'r') {|f| f.read }
40
+
41
+ begin
42
+ @config = JSON.parse config_data
43
+ rescue JSON::ParserError => e
44
+ raise e.exception("I cannot parse #{@config_file}! Is is a valid JSON hipchatConfig.json? (I doubt it!)")
45
+ end
46
+
47
+
48
+ # verify that config smells right
49
+ # ['firstLogin','email'].each do |key|
50
+ # unless @config.include? key
51
+ # puts %Q{I was expecting key '#{key}' in the config, but it's missing. Strange.}
52
+ # end
53
+ # end
54
+
55
+ raise "The 'password' key is missing! I cannot continue." unless @config.include? 'password'
56
+ end
57
+
58
+ end
59
+ end
data/lib/version.rb ADDED
@@ -0,0 +1,3 @@
1
+ module HipChatSecrets
2
+ VERSION = "0.9.1"
3
+ end
@@ -0,0 +1 @@
1
+ {"55555":{"5555_room_one@conf.hipchat.com":{},"chatToFocus":"5555_room_two@conf.hipchat.com","5555_room_two@conf.hipchat.com":{},"autoJoin":[{"name":"room one","jid":"5555_room_one@conf.hipchat.com"},{"name":"room two","jid":"5555_room_two@conf.hipchat.com"},{"name":"Robert Paulson","jid":"5555_555555@chat.hipchat.com"}]},"enableSpellcheck":true,"email":"test@pass.com","rosterSorting":"alpha","checkForUpdate":true,"runOnStartup":false,"timeFormat24Hour":false,"enableLogging":false,"password":"DRh7OjodIAYxEyk5NQc/EnkYMQ==","secondsToIdle":300,"width":1127,"disableSounds":true,"showLog":false,"height":524,"autoLogin":true,"visualNotifications":false,"uploadServer":"uploads.hipchat.com","hidePresenceMessages":false,"notifyDnd":false,"enableEmoticons":true,"notifyForPrivateRoom":true,"hideGifs":false,"playIncomingCallSound":true,"notifyForRoom":false,"persistentToasters":false,"showTypingNotif":true,"x":285,"fontSize":12,"firstLogin":false,"y":314,"showToasters":true,"checkMinorUpdates":false,"enableNumberShortcuts":true,"macCRFix":false,"notifyForPrivate":true,"notifyForTag":true,"i18nKeyboardFix":false}
@@ -0,0 +1 @@
1
+ {"55555":{"5555_room_one@conf.hipchat.com":{},"chatToFocus":"5555_room_two@conf.hipchat.com","5555_room_two@conf.hipchat.com":{},"autoJoin":[{"name":"room one","jid":"5555_room_one@conf.hipchat.com"},{"name":"room two","jid":"5555_room_two@conf.hipchat.com"},{"name":"Robert Paulson","jid":"5555_555555@chat.hipchat.com"}]},"enableSpellcheck":true,"rosterSorting":"alpha","checkForUpdate":true,"runOnStartup":false,"timeFormat24Hour":false,"enableLogging":false,"secondsToIdle":300,"width":1127,"disableSounds":true,"showLog":false,"height":524,"autoLogin":true,"visualNotifications":false,"uploadServer":"uploads.hipchat.com","hidePresenceMessages":false,"notifyDnd":false,"enableEmoticons":true,"notifyForPrivateRoom":true,"hideGifs":false,"playIncomingCallSound":true,"notifyForRoom":false,"persistentToasters":false,"showTypingNotif":true,"x":285,"fontSize":12,"firstLogin":false,"y":314,"showToasters":true,"checkMinorUpdates":false,"enableNumberShortcuts":true,"macCRFix":false,"notifyForPrivate":true,"notifyForTag":true,"i18nKeyboardFix":false}
@@ -0,0 +1 @@
1
+ }}{}{}::
@@ -0,0 +1,43 @@
1
+ require 'spec_helper'
2
+ require 'crypt'
3
+
4
+ describe HipChatSecrets::Crypt do
5
+ # The subject is static methods / don't create an object
6
+ subject { HipChatSecrets::Crypt }
7
+
8
+ before do
9
+ subject.secret = 'not the real secret'
10
+ end
11
+
12
+ it "tests with a phoney secret" do
13
+ subject.secret_str.should eq 'not the real secret'
14
+ end
15
+
16
+ it "xor of string => string" do
17
+ subject.xor('hello').should be_a_kind_of String
18
+ end
19
+
20
+ it "xor of xor of string => string" do
21
+ result = subject.xor(subject.xor 'hello')
22
+ result.should be_a_kind_of String
23
+ result.should eq 'hello'
24
+ end
25
+
26
+ it "decodes secrets" do
27
+ subject.decode('Hg4aRBUb').should eq 'pandas'
28
+ end
29
+
30
+ it "encodes secrets" do
31
+ subject.encode('pandas').should eq 'Hg4aRBUb'
32
+ end
33
+
34
+ it "is symmetric" do
35
+ subject.decode(subject.encode 'pandas').should eq 'pandas'
36
+ end
37
+
38
+ it "is symmetric even with long strings" do
39
+ str = 'Hello, I noticed that you are reading my code. Enjoy and happy hacking!'
40
+ subject.decode(subject.encode str*20).should eq str*20
41
+ end
42
+
43
+ end
@@ -0,0 +1,55 @@
1
+ require 'spec_helper'
2
+ require 'settings_file'
3
+
4
+ describe HipChatSecrets::SettingsFile do
5
+
6
+ context "with a valid config" do
7
+
8
+ subject do
9
+ HipChatSecrets::SettingsFile.new File.join(File.dirname(__FILE__), '../fixtures/hipchatConfig.json')
10
+ end
11
+
12
+ it "uses the fixture config" do
13
+ subject.email.should eq 'test@pass.com'
14
+ end
15
+
16
+ it "can find a settings file" do
17
+ subject.send(:find_configs).should be_a_kind_of Array
18
+ subject.send(:find_configs,'~/a_file_that_shouldnt_exist').should be_a_kind_of Array
19
+ end
20
+
21
+ it "exposes the raw config" do
22
+ subject.config.should be_a_kind_of Hash
23
+ end
24
+
25
+ it "exposes the config_file's path" do
26
+ subject.config_file.should be_a_kind_of String
27
+ end
28
+
29
+ it "can pass missing method calls to the config hash" do
30
+ subject.email.should be_a_kind_of String
31
+ subject.password.should be_a_kind_of String
32
+ end
33
+ end
34
+
35
+ context "with an invalid config" do
36
+ subject do
37
+ HipChatSecrets::SettingsFile.new File.join(File.dirname(__FILE__), '../fixtures/hipchatConfigBad.json')
38
+ end
39
+
40
+ it "aborts when the password is missing" do
41
+ expect { subject }.to raise_error /'password' key is missing!/
42
+ end
43
+ end
44
+
45
+ context "with a malformed config" do
46
+ subject do
47
+ HipChatSecrets::SettingsFile.new File.join(File.dirname(__FILE__), '../fixtures/hipchatConfigMalformed.json')
48
+ end
49
+
50
+ it "aborts when the config is garbage" do
51
+ expect { subject }.to raise_error JSON::ParserError
52
+ end
53
+ end
54
+
55
+ end
@@ -0,0 +1,16 @@
1
+ require 'rubygems'
2
+ require 'spork'
3
+
4
+ Spork.prefork do
5
+ $:<< File.join(File.dirname(__FILE__), '../lib')
6
+ require 'rspec/autorun'
7
+
8
+ RSpec.configure do |config|
9
+ config.mock_with :rspec
10
+ config.order = "random"
11
+ end
12
+ end
13
+
14
+ Spork.each_run do
15
+ Dir[File.join(File.dirname(__FILE__), '../support/**/*.rb')].each {|f| require f }
16
+ end
metadata ADDED
@@ -0,0 +1,136 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: hipchat-secrets
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.9.1
5
+ prerelease:
6
+ platform: ruby
7
+ authors:
8
+ - Jeremy Ebler
9
+ autorequire:
10
+ bindir: bin
11
+ cert_chain: []
12
+ date: 2013-02-06 00:00:00.000000000 Z
13
+ dependencies:
14
+ - !ruby/object:Gem::Dependency
15
+ name: json
16
+ requirement: &70275614471580 !ruby/object:Gem::Requirement
17
+ none: false
18
+ requirements:
19
+ - - ! '>='
20
+ - !ruby/object:Gem::Version
21
+ version: '0'
22
+ type: :runtime
23
+ prerelease: false
24
+ version_requirements: *70275614471580
25
+ - !ruby/object:Gem::Dependency
26
+ name: spork
27
+ requirement: &70275614470960 !ruby/object:Gem::Requirement
28
+ none: false
29
+ requirements:
30
+ - - ! '>='
31
+ - !ruby/object:Gem::Version
32
+ version: '0'
33
+ type: :development
34
+ prerelease: false
35
+ version_requirements: *70275614470960
36
+ - !ruby/object:Gem::Dependency
37
+ name: rspec
38
+ requirement: &70275614470200 !ruby/object:Gem::Requirement
39
+ none: false
40
+ requirements:
41
+ - - ! '>='
42
+ - !ruby/object:Gem::Version
43
+ version: '0'
44
+ type: :development
45
+ prerelease: false
46
+ version_requirements: *70275614470200
47
+ - !ruby/object:Gem::Dependency
48
+ name: guard-rspec
49
+ requirement: &70275614469660 !ruby/object:Gem::Requirement
50
+ none: false
51
+ requirements:
52
+ - - ! '>='
53
+ - !ruby/object:Gem::Version
54
+ version: '0'
55
+ type: :development
56
+ prerelease: false
57
+ version_requirements: *70275614469660
58
+ - !ruby/object:Gem::Dependency
59
+ name: guard-bundler
60
+ requirement: &70275614468980 !ruby/object:Gem::Requirement
61
+ none: false
62
+ requirements:
63
+ - - ! '>='
64
+ - !ruby/object:Gem::Version
65
+ version: '0'
66
+ type: :development
67
+ prerelease: false
68
+ version_requirements: *70275614468980
69
+ - !ruby/object:Gem::Dependency
70
+ name: rb-fsevent
71
+ requirement: &70275614467800 !ruby/object:Gem::Requirement
72
+ none: false
73
+ requirements:
74
+ - - ~>
75
+ - !ruby/object:Gem::Version
76
+ version: 0.9.1
77
+ type: :development
78
+ prerelease: false
79
+ version_requirements: *70275614467800
80
+ description: Extract secrets from hipchat configuration files
81
+ email:
82
+ - jebler@gmail.com
83
+ executables:
84
+ - hipchat-secrets
85
+ extensions: []
86
+ extra_rdoc_files: []
87
+ files:
88
+ - .gitignore
89
+ - Gemfile
90
+ - Guardfile
91
+ - LICENSE.txt
92
+ - Rakefile
93
+ - Readme.md
94
+ - bin/hipchat-secrets
95
+ - hipchat-secrets.gemspec
96
+ - lib/crypt.rb
97
+ - lib/settings_file.rb
98
+ - lib/version.rb
99
+ - spec/fixtures/hipchatConfig.json
100
+ - spec/fixtures/hipchatConfigBad.json
101
+ - spec/fixtures/hipchatConfigMalformed.json
102
+ - spec/lib/crypt_spec.rb
103
+ - spec/lib/settings_file_spec.rb
104
+ - spec/spec_helper.rb
105
+ homepage: https://github.com/whitehat101/hipchat-secrets
106
+ licenses: []
107
+ post_install_message:
108
+ rdoc_options: []
109
+ require_paths:
110
+ - lib
111
+ required_ruby_version: !ruby/object:Gem::Requirement
112
+ none: false
113
+ requirements:
114
+ - - ! '>='
115
+ - !ruby/object:Gem::Version
116
+ version: '0'
117
+ required_rubygems_version: !ruby/object:Gem::Requirement
118
+ none: false
119
+ requirements:
120
+ - - ! '>='
121
+ - !ruby/object:Gem::Version
122
+ version: '0'
123
+ requirements: []
124
+ rubyforge_project:
125
+ rubygems_version: 1.8.10
126
+ signing_key:
127
+ specification_version: 3
128
+ summary: Decode the weakly crypted password from the hipchat configuration file. The
129
+ API allows decoding/encoding—everything you need to discover the secret key!
130
+ test_files:
131
+ - spec/fixtures/hipchatConfig.json
132
+ - spec/fixtures/hipchatConfigBad.json
133
+ - spec/fixtures/hipchatConfigMalformed.json
134
+ - spec/lib/crypt_spec.rb
135
+ - spec/lib/settings_file_spec.rb
136
+ - spec/spec_helper.rb