An unofficial, mostly Bitwarden-compatible API server written in Ruby (Sinatra and ActiveRecord)
1require_relative "spec_helper.rb"
2
3@access_token = nil
4
5describe "cipher module" do
6 before do
7 User.all.delete_all
8
9 Rubywarden::Test::Factory.create_user
10 @access_token = Rubywarden::Test::Factory.login_user
11 end
12
13 it "should not allow access with bogus bearer token" do
14 post_json "/api/ciphers", {
15 :type => 1,
16 :folderId => nil,
17 :organizationId => nil,
18 :name => "2.d7MttWzJTSSKx1qXjHUxlQ==|01Ath5UqFZHk7csk5DVtkQ==|EMLoLREgCUP5Cu4HqIhcLqhiZHn+NsUDp8dAg1Xu0Io=",
19 :notes => nil,
20 :favorite => false,
21 :login => {
22 :uri => "2.T57BwAuV8ubIn/sZPbQC+A==|EhUSSpJWSzSYOdJ/AQzfXuUXxwzcs/6C4tOXqhWAqcM=|OWV2VIqLfoWPs9DiouXGUOtTEkVeklbtJQHkQFIXkC8=",
23 :username => "2.JbFkAEZPnuMm70cdP44wtA==|fsN6nbT+udGmOWv8K4otgw==|JbtwmNQa7/48KszT2hAdxpmJ6DRPZst0EDEZx5GzesI=",
24 :password => "2.e83hIsk6IRevSr/H1lvZhg==|48KNkSCoTacopXRmIZsbWg==|CIcWgNbaIN2ix2Fx1Gar6rWQeVeboehp4bioAwngr0o=",
25 :totp => nil
26 }
27 }, {
28 "HTTP_AUTHORIZATION" => "Bearer #{@access_token.upcase}",
29 }
30
31 last_response.status.wont_equal 200
32 end
33
34 it "should allow creating, updating, and deleting ciphers" do
35 post_json "/api/ciphers", {
36 :type => 1,
37 :folderId => nil,
38 :organizationId => nil,
39 :name => "2.d7MttWzJTSSKx1qXjHUxlQ==|01Ath5UqFZHk7csk5DVtkQ==|EMLoLREgCUP5Cu4HqIhcLqhiZHn+NsUDp8dAg1Xu0Io=",
40 :notes => nil,
41 :favorite => false,
42 :login => {
43 :uri => "2.T57BwAuV8ubIn/sZPbQC+A==|EhUSSpJWSzSYOdJ/AQzfXuUXxwzcs/6C4tOXqhWAqcM=|OWV2VIqLfoWPs9DiouXGUOtTEkVeklbtJQHkQFIXkC8=",
44 :username => "2.JbFkAEZPnuMm70cdP44wtA==|fsN6nbT+udGmOWv8K4otgw==|JbtwmNQa7/48KszT2hAdxpmJ6DRPZst0EDEZx5GzesI=",
45 :password => "2.e83hIsk6IRevSr/H1lvZhg==|48KNkSCoTacopXRmIZsbWg==|CIcWgNbaIN2ix2Fx1Gar6rWQeVeboehp4bioAwngr0o=",
46 :totp => nil
47 }
48 }, {
49 "HTTP_AUTHORIZATION" => "Bearer #{@access_token}",
50 }
51
52 last_response.status.must_equal 200
53 uuid = last_json_response["Id"]
54 uuid.to_s.wont_equal ""
55
56 c = Cipher.find_by_uuid(uuid)
57 c.wont_be_nil
58 c.uuid.must_equal uuid
59 c.name.must_equal "2.d7MttWzJTSSKx1qXjHUxlQ==|01Ath5UqFZHk7csk5DVtkQ==|EMLoLREgCUP5Cu4HqIhcLqhiZHn+NsUDp8dAg1Xu0Io="
60
61 # update
62
63 ik = Bitwarden.makeKey("asdf", "api@example.com",
64 User::DEFAULT_KDF_TYPE,
65 Bitwarden::KDF::DEFAULT_ITERATIONS[User::DEFAULT_KDF_TYPE])
66 ek = Bitwarden.makeEncKey(ik)
67 k = Bitwarden.decrypt(ek, ik)
68 new_name = Bitwarden.encrypt("some new name", k).to_s
69
70 put_json "/api/ciphers/#{uuid}", {
71 :type => 1,
72 :folderId => nil,
73 :organizationId => nil,
74 :name => new_name,
75 :notes => nil,
76 :favorite => false,
77 :login => {
78 :uri => "2.T57BwAuV8ubIn/sZPbQC+A==|EhUSSpJWSzSYOdJ/AQzfXuUXxwzcs/6C4tOXqhWAqcM=|OWV2VIqLfoWPs9DiouXGUOtTEkVeklbtJQHkQFIXkC8=",
79 :username => "2.JbFkAEZPnuMm70cdP44wtA==|fsN6nbT+udGmOWv8K4otgw==|JbtwmNQa7/48KszT2hAdxpmJ6DRPZst0EDEZx5GzesI=",
80 :password => "2.e83hIsk6IRevSr/H1lvZhg==|48KNkSCoTacopXRmIZsbWg==|CIcWgNbaIN2ix2Fx1Gar6rWQeVeboehp4bioAwngr0o=",
81 :totp => nil
82 }
83 }, {
84 "HTTP_AUTHORIZATION" => "Bearer #{@access_token}",
85 }
86
87 last_response.status.must_equal 200
88 last_json_response["Id"].to_s.wont_equal ""
89
90 c = Cipher.find_by_uuid(last_json_response["Id"])
91 c.name.must_equal new_name
92
93 uuid = c.uuid
94
95 # delete
96
97 delete_json "/api/ciphers/#{uuid}", {}, {
98 "HTTP_AUTHORIZATION" => "Bearer #{@access_token}",
99 }
100 last_response.status.must_equal 200
101
102 Cipher.find_by_uuid(uuid).must_be_nil
103 end
104
105 it "should not allow creating, updating, or deleting bogus ciphers" do
106 post_json "/api/ciphers", {
107 :type => -5,
108 }, {
109 "HTTP_AUTHORIZATION" => "Bearer #{@access_token}",
110 }
111
112 last_response.status.wont_equal 200
113
114 # create, then bogus update
115
116 post_json "/api/ciphers", {
117 :type => 1,
118 :folderId => nil,
119 :organizationId => nil,
120 :name => "2.d7MttWzJTSSKx1qXjHUxlQ==|01Ath5UqFZHk7csk5DVtkQ==|EMLoLREgCUP5Cu4HqIhcLqhiZHn+NsUDp8dAg1Xu0Io=",
121 :notes => nil,
122 :favorite => false,
123 :login => {
124 :uri => "2.T57BwAuV8ubIn/sZPbQC+A==|EhUSSpJWSzSYOdJ/AQzfXuUXxwzcs/6C4tOXqhWAqcM=|OWV2VIqLfoWPs9DiouXGUOtTEkVeklbtJQHkQFIXkC8=",
125 :username => "2.JbFkAEZPnuMm70cdP44wtA==|fsN6nbT+udGmOWv8K4otgw==|JbtwmNQa7/48KszT2hAdxpmJ6DRPZst0EDEZx5GzesI=",
126 :password => "2.e83hIsk6IRevSr/H1lvZhg==|48KNkSCoTacopXRmIZsbWg==|CIcWgNbaIN2ix2Fx1Gar6rWQeVeboehp4bioAwngr0o=",
127 :totp => nil
128 }
129 }, {
130 "HTTP_AUTHORIZATION" => "Bearer #{@access_token}",
131 }
132
133 last_response.status.must_equal 200
134 uuid = last_json_response["Id"]
135
136 put_json "/api/ciphers/#{uuid}", {
137 :type => -5,
138 }, {
139 "HTTP_AUTHORIZATION" => "Bearer #{@access_token}",
140 }
141
142 last_response.status.wont_equal 200
143
144 # bogus delete
145
146 delete_json "/api/ciphers/something-bogus", {}, {
147 "HTTP_AUTHORIZATION" => "Bearer #{@access_token}",
148 }
149 last_response.status.wont_equal 200
150 end
151
152 it "should allow assigning ciphers to valid folders" do
153 post_json "/api/ciphers", {
154 :type => 1,
155 :folderId => nil,
156 :organizationId => nil,
157 :name => "2.d7MttWzJTSSKx1qXjHUxlQ==|01Ath5UqFZHk7csk5DVtkQ==|EMLoLREgCUP5Cu4HqIhcLqhiZHn+NsUDp8dAg1Xu0Io=",
158 :notes => nil,
159 :favorite => false,
160 :login => {
161 :uri => "2.T57BwAuV8ubIn/sZPbQC+A==|EhUSSpJWSzSYOdJ/AQzfXuUXxwzcs/6C4tOXqhWAqcM=|OWV2VIqLfoWPs9DiouXGUOtTEkVeklbtJQHkQFIXkC8=",
162 :username => "2.JbFkAEZPnuMm70cdP44wtA==|fsN6nbT+udGmOWv8K4otgw==|JbtwmNQa7/48KszT2hAdxpmJ6DRPZst0EDEZx5GzesI=",
163 :password => "2.e83hIsk6IRevSr/H1lvZhg==|48KNkSCoTacopXRmIZsbWg==|CIcWgNbaIN2ix2Fx1Gar6rWQeVeboehp4bioAwngr0o=",
164 :totp => nil
165 }
166 }, {
167 "HTTP_AUTHORIZATION" => "Bearer #{@access_token}",
168 }
169
170 last_response.status.must_equal 200
171 uuid = last_json_response["Id"]
172
173 # create folder
174
175 post_json "/api/folders", {
176 :name => "2.tqb+y2z4ChCYHj4romVwGQ==|E8+D7aR5CNnd+jF7fdb9ow==|wELCxyy341G2F+w8bTb87PAUi6sdXeIFTFb4N8tk3E0=",
177 }, {
178 "HTTP_AUTHORIZATION" => "Bearer #{@access_token}",
179 }
180
181 last_response.status.must_equal 200
182 folder_uuid = last_json_response["Id"]
183
184 # update to put in valid folder
185
186 put_json "/api/ciphers/#{uuid}", {
187 :type => 1,
188 :folderId => folder_uuid,
189 :organizationId => nil,
190 :name => "2.d7MttWzJTSSKx1qXjHUxlQ==|01Ath5UqFZHk7csk5DVtkQ==|EMLoLREgCUP5Cu4HqIhcLqhiZHn+NsUDp8dAg1Xu0Io=",
191 :notes => nil,
192 :favorite => false,
193 :login => {
194 :uri => "2.T57BwAuV8ubIn/sZPbQC+A==|EhUSSpJWSzSYOdJ/AQzfXuUXxwzcs/6C4tOXqhWAqcM=|OWV2VIqLfoWPs9DiouXGUOtTEkVeklbtJQHkQFIXkC8=",
195 :username => "2.JbFkAEZPnuMm70cdP44wtA==|fsN6nbT+udGmOWv8K4otgw==|JbtwmNQa7/48KszT2hAdxpmJ6DRPZst0EDEZx5GzesI=",
196 :password => "2.e83hIsk6IRevSr/H1lvZhg==|48KNkSCoTacopXRmIZsbWg==|CIcWgNbaIN2ix2Fx1Gar6rWQeVeboehp4bioAwngr0o=",
197 :totp => nil
198 }
199 }, {
200 "HTTP_AUTHORIZATION" => "Bearer #{@access_token}",
201 }
202
203 last_response.status.must_equal 200
204
205 # now assign to bogus folder
206
207 put_json "/api/ciphers/#{uuid}", {
208 :type => 1,
209 :folderId => folder_uuid.reverse,
210 :organizationId => nil,
211 :name => "2.d7MttWzJTSSKx1qXjHUxlQ==|01Ath5UqFZHk7csk5DVtkQ==|EMLoLREgCUP5Cu4HqIhcLqhiZHn+NsUDp8dAg1Xu0Io=",
212 :notes => nil,
213 :favorite => false,
214 :login => {
215 :uri => "2.T57BwAuV8ubIn/sZPbQC+A==|EhUSSpJWSzSYOdJ/AQzfXuUXxwzcs/6C4tOXqhWAqcM=|OWV2VIqLfoWPs9DiouXGUOtTEkVeklbtJQHkQFIXkC8=",
216 :username => "2.JbFkAEZPnuMm70cdP44wtA==|fsN6nbT+udGmOWv8K4otgw==|JbtwmNQa7/48KszT2hAdxpmJ6DRPZst0EDEZx5GzesI=",
217 :password => "2.e83hIsk6IRevSr/H1lvZhg==|48KNkSCoTacopXRmIZsbWg==|CIcWgNbaIN2ix2Fx1Gar6rWQeVeboehp4bioAwngr0o=",
218 :totp => nil
219 }
220 }, {
221 "HTTP_AUTHORIZATION" => "Bearer #{@access_token}",
222 }
223
224 last_response.status.wont_equal 200
225 end
226end