hipchat-secrets 0.9.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.
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