metrics();
278 | }
279 |
--------------------------------------------------------------------------------
/src/main/java/com/sanctionco/opconnect/model/Category.java:
--------------------------------------------------------------------------------
1 | package com.sanctionco.opconnect.model;
2 |
3 | import com.fasterxml.jackson.annotation.JsonEnumDefaultValue;
4 |
5 | /**
6 | * Represents an item category.
7 | */
8 | public enum Category {
9 | /**
10 | * The login category.
11 | */
12 | LOGIN,
13 |
14 | /**
15 | * The password category.
16 | */
17 | PASSWORD,
18 |
19 | /**
20 | * The server category.
21 | */
22 | SERVER,
23 |
24 | /**
25 | * The database category.
26 | */
27 | DATABASE,
28 |
29 | /**
30 | * The credit card category.
31 | */
32 | CREDIT_CARD,
33 |
34 | /**
35 | * The membership category.
36 | */
37 | MEMBERSHIP,
38 |
39 | /**
40 | * The passport category.
41 | */
42 | PASSPORT,
43 |
44 | /**
45 | * The software license category.
46 | */
47 | SOFTWARE_LICENSE,
48 |
49 | /**
50 | * The outdoor license category.
51 | */
52 | OUTDOOR_LICENSE,
53 |
54 | /**
55 | * The secure note category.
56 | */
57 | SECURE_NOTE,
58 |
59 | /**
60 | * The wireless router category.
61 | */
62 | WIRELESS_ROUTER,
63 |
64 | /**
65 | * The bank account category.
66 | */
67 | BANK_ACCOUNT,
68 |
69 | /**
70 | * The driver license category.
71 | */
72 | DRIVER_LICENSE,
73 |
74 | /**
75 | * The identity category.
76 | */
77 | IDENTITY,
78 |
79 | /**
80 | * The reward program category.
81 | */
82 | REWARD_PROGRAM,
83 |
84 | /**
85 | * The document category.
86 | */
87 | DOCUMENT,
88 |
89 | /**
90 | * The email account category.
91 | */
92 | EMAIL_ACCOUNT,
93 |
94 | /**
95 | * The social security number category.
96 | */
97 | SOCIAL_SECURITY_NUMBER,
98 |
99 | /**
100 | * The API credential category.
101 | */
102 | API_CREDENTIAL,
103 |
104 | /**
105 | * The medical record category.
106 | */
107 | MEDICAL_RECORD,
108 |
109 | /**
110 | * The SSH key category.
111 | */
112 | SSH_KEY,
113 |
114 | /**
115 | * The custom category, used as the default for any unknown category.
116 | *
117 | * Note that you cannot create an item using the {@code CUSTOM} category.
118 | */
119 | @JsonEnumDefaultValue
120 | CUSTOM
121 | }
122 |
--------------------------------------------------------------------------------
/src/main/java/com/sanctionco/opconnect/model/CharacterSet.java:
--------------------------------------------------------------------------------
1 | package com.sanctionco.opconnect.model;
2 |
3 | import java.util.Arrays;
4 | import java.util.Collections;
5 | import java.util.List;
6 |
7 | /**
8 | * Represents all allowed types of character sets.
9 | */
10 | public enum CharacterSet {
11 | /**
12 | * The character set consisting of only letters.
13 | */
14 | LETTERS,
15 |
16 | /**
17 | * The character set consisting of only numerical digits.
18 | */
19 | DIGITS,
20 |
21 | /**
22 | * The character set consisting of only symbols.
23 | */
24 | SYMBOLS;
25 |
26 | /**
27 | * Returns a list of {@code CharacterSet} containing only letters.
28 | *
29 | * @return the new {@link List}
30 | */
31 | public static List letters() {
32 | return Collections.singletonList(LETTERS);
33 | }
34 |
35 | /**
36 | * Returns a list of {@code CharacterSet} containing only digits.
37 | *
38 | * @return the new {@link List}
39 | */
40 | public static List digits() {
41 | return Collections.singletonList(DIGITS);
42 | }
43 |
44 | /**
45 | * Returns a list of {@code CharacterSet} containing only symbols.
46 | *
47 | * @return the new {@link List}
48 | */
49 | public static List symbols() {
50 | return Collections.singletonList(SYMBOLS);
51 | }
52 |
53 | /**
54 | * Returns a list of {@code CharacterSet} containing letters and digits.
55 | *
56 | * @return the new {@link List}
57 | */
58 | public static List lettersAndDigits() {
59 | return Arrays.asList(LETTERS, DIGITS);
60 | }
61 |
62 | /**
63 | * Returns a list of {@code CharacterSet} containing letters and symbols.
64 | *
65 | * @return the new {@link List}
66 | */
67 | public static List lettersAndSymbols() {
68 | return Arrays.asList(LETTERS, SYMBOLS);
69 | }
70 |
71 | /**
72 | * Returns a list of {@code CharacterSet} containing digits and symbols.
73 | *
74 | * @return the new {@link List}
75 | */
76 | public static List digitsAndSymbols() {
77 | return Arrays.asList(DIGITS, SYMBOLS);
78 | }
79 |
80 | /**
81 | * Returns a list of {@code CharacterSet} containing all characters.
82 | *
83 | * @return the new {@link List}
84 | */
85 | public static List allCharacters() {
86 | return Arrays.asList(values());
87 | }
88 | }
89 |
--------------------------------------------------------------------------------
/src/main/java/com/sanctionco/opconnect/model/Field.java:
--------------------------------------------------------------------------------
1 | package com.sanctionco.opconnect.model;
2 |
3 | import com.fasterxml.jackson.annotation.JsonAlias;
4 | import com.fasterxml.jackson.annotation.JsonProperty;
5 | import com.fasterxml.jackson.databind.annotation.JsonDeserialize;
6 |
7 | import java.util.Objects;
8 | import java.util.StringJoiner;
9 |
10 | /**
11 | * Represents a field contained in an {@link Item}.
12 | */
13 | @JsonDeserialize(builder = Field.Builder.class)
14 | public class Field {
15 | private final String id;
16 | private final Purpose purpose;
17 | private final Type type;
18 | private final String label;
19 | private final String value;
20 | private final Boolean generate;
21 | private final GeneratorRecipe recipe;
22 | private final Section section;
23 | private final Double entropy;
24 | private final PasswordDetails passwordDetails;
25 | private final String totp;
26 |
27 | private Field(Builder builder) {
28 | this.id = builder.id;
29 | this.purpose = builder.purpose;
30 | this.type = builder.type;
31 | this.label = builder.label;
32 | this.value = builder.value;
33 | this.generate = builder.generate;
34 | this.recipe = builder.recipe;
35 | this.section = builder.section;
36 | this.entropy = builder.entropy;
37 | this.passwordDetails = builder.passwordDetails;
38 | this.totp = builder.totp;
39 | }
40 |
41 | /**
42 | * Get the ID of this field.
43 | *
44 | * @return the ID of the field
45 | */
46 | public String getId() {
47 | return id;
48 | }
49 |
50 | /**
51 | * Get the {@link Purpose} of this field.
52 | *
53 | * @return the purpose of the field
54 | */
55 | public Purpose getPurpose() {
56 | return purpose;
57 | }
58 |
59 | /**
60 | * Get the {@link Type} of this field.
61 | *
62 | * @return the type of the field
63 | */
64 | public Type getType() {
65 | return type;
66 | }
67 |
68 | /**
69 | * Get the label of this field.
70 | *
71 | * @return the label of this field
72 | */
73 | public String getLabel() {
74 | return label;
75 | }
76 |
77 | /**
78 | * Get the value of this field.
79 | *
80 | * @return the value of this field
81 | */
82 | public String getValue() {
83 | return value;
84 | }
85 |
86 | /**
87 | * Get whether this field should have a generated value. This will not
88 | * be set for fields that are returned from 1Password Connect, as the
89 | * {@code generate} option is only used when creating a field.
90 | *
91 | * @return true if the value should be generated, false otherwise
92 | */
93 | public Boolean getGenerate() {
94 | return generate;
95 | }
96 |
97 | /**
98 | * Get the {@link GeneratorRecipe} to use when generating the value, if {@link #getGenerate()}
99 | * is set to {@code true}. This will not be set for fields that are returned from 1Password
100 | * Connect, as the {@code generate} option is only used when creating a field.
101 | *
102 | * @return the {@link GeneratorRecipe} to use when generating the value
103 | */
104 | public GeneratorRecipe getRecipe() {
105 | return recipe;
106 | }
107 |
108 | /**
109 | * Get the {@link Section} that this field is contained in.
110 | *
111 | * @return the section this field is contained in
112 | */
113 | public Section getSection() {
114 | return section;
115 | }
116 |
117 | /**
118 | * Get the entropy of the generated field value.
119 | *
120 | * @return the entropy of the generated field value
121 | */
122 | public Double getEntropy() {
123 | return entropy;
124 | }
125 |
126 | /**
127 | * Get the password details for this field if it is a password field.
128 | *
129 | * @return the password details for this field if it is a password field, or null otherwise
130 | */
131 | @JsonProperty("password_details")
132 | public PasswordDetails getPasswordDetails() {
133 | return passwordDetails;
134 | }
135 |
136 | /**
137 | * Get the TOTP value for this field if it is an OTP field.
138 | *
139 | * @return the current TOTP value for this field if it is an OTP field, or null otherwise
140 | */
141 | public String getTotp() {
142 | return totp;
143 | }
144 |
145 | @Override
146 | public boolean equals(Object o) {
147 | if (this == o) return true;
148 | if (o == null || getClass() != o.getClass()) return false;
149 | Field field = (Field) o;
150 | return Objects.equals(id, field.id);
151 | }
152 |
153 | @Override
154 | public int hashCode() {
155 | return Objects.hash(id);
156 | }
157 |
158 | @Override
159 | public String toString() {
160 | return new StringJoiner(", ", Field.class.getSimpleName() + "[", "]")
161 | .add("id='" + id + "'")
162 | .add("purpose=" + purpose)
163 | .add("type=" + type)
164 | .add("label='" + label + "'")
165 | .add("value='" + value + "'")
166 | .add("generate=" + generate)
167 | .add("recipe=" + recipe)
168 | .add("section=" + section)
169 | .add("entropy=" + entropy)
170 | .add("passwordDetails=" + passwordDetails)
171 | .add("totp=" + totp)
172 | .toString();
173 | }
174 |
175 | /**
176 | * Create a new {@link Field.Builder} for a username field.
177 | *
178 | * @param username the value of the username to set
179 | * @return a new builder instance used to build a {@link Field}
180 | */
181 | public static Builder username(String username) {
182 | return builder().withPurpose(Purpose.USERNAME).withValue(username);
183 | }
184 |
185 | /**
186 | * Create a new {@link Field.Builder} for a password field.
187 | *
188 | * @param password the value of the password to set
189 | * @return a new builder instance used to build a {@link Field}
190 | */
191 | public static Builder password(String password) {
192 | return builder().withPurpose(Purpose.PASSWORD).withValue(password);
193 | }
194 |
195 | /**
196 | * Create a new {@link Field.Builder} for a generated password field.
197 | *
198 | * @return a new builder instance used to build a {@link Field}
199 | */
200 | public static Builder generatedPassword() {
201 | return builder().withPurpose(Purpose.PASSWORD).withGenerate(true);
202 | }
203 |
204 | /**
205 | * Create a new {@link Field.Builder} for a generated password field.
206 | *
207 | * @param recipe the {@link GeneratorRecipe} to use when generating the password value
208 | * @return a new builder instance used to build a {@link Field}
209 | */
210 | public static Builder generatedPassword(GeneratorRecipe recipe) {
211 | return builder().withPurpose(Purpose.PASSWORD).withGenerate(true)
212 | .withRecipe(recipe);
213 | }
214 |
215 | /**
216 | * Create a new {@link Field.Builder} for a note field.
217 | *
218 | * @param note the value of the note to set
219 | * @return a new builder instance used to build a {@link Field}
220 | */
221 | public static Builder note(String note) {
222 | return builder().withPurpose(Purpose.NOTES).withValue(note);
223 | }
224 |
225 | /**
226 | * Create a new {@link Field.Builder} for a field with the given label.
227 | *
228 | * @param label the label to use for the field
229 | * @return a new builder instance used to build a {@link Field}
230 | */
231 | public static Builder labeled(String label) {
232 | return builder().withLabel(label);
233 | }
234 |
235 | /**
236 | * Create a new {@link Field.Builder} with no properties set.
237 | *
238 | * @return a new builder instance used to build a {@link Field}
239 | */
240 | public static Builder builder() {
241 | return new Builder();
242 | }
243 |
244 | /**
245 | * The builder class used to build a new {@link Field}.
246 | */
247 | public static class Builder {
248 | private String id;
249 | private Purpose purpose;
250 | private Type type;
251 | private String label;
252 | private String value;
253 | private Boolean generate;
254 | private GeneratorRecipe recipe;
255 | private Section section;
256 | private Double entropy;
257 | private PasswordDetails passwordDetails;
258 | private String totp;
259 |
260 | /**
261 | * Set the ID of the field.
262 | *
263 | * @param id the ID of the field
264 | * @return this
265 | */
266 | public Builder withId(String id) {
267 | this.id = id;
268 | return this;
269 | }
270 |
271 | /**
272 | * Set the {@link Purpose} of the field.
273 | *
274 | * @param purpose the purpose of the field
275 | * @return this
276 | */
277 | public Builder withPurpose(Purpose purpose) {
278 | this.purpose = purpose;
279 | return this;
280 | }
281 |
282 | /**
283 | * Set the {@link Type} of the field.
284 | *
285 | * @param type the type of the field
286 | * @return this
287 | */
288 | public Builder withType(Type type) {
289 | this.type = type;
290 | return this;
291 | }
292 |
293 | /**
294 | * Set the label for the field.
295 | *
296 | * @param label the label of the field
297 | * @return this
298 | */
299 | public Builder withLabel(String label) {
300 | this.label = label;
301 | return this;
302 | }
303 |
304 | /**
305 | * Set the value of the field.
306 | *
307 | * @param value the value of the field
308 | * @return this
309 | */
310 | public Builder withValue(String value) {
311 | this.value = value;
312 | return this;
313 | }
314 |
315 | /**
316 | * Set to true in order to generate the value of the field.
317 | *
318 | * @param generate true to generate the value, or false otherwise
319 | * @return this
320 | */
321 | public Builder withGenerate(Boolean generate) {
322 | this.generate = generate;
323 | return this;
324 | }
325 |
326 | /**
327 | * Set that the value of the field should be generated.
328 | *
329 | * @return this
330 | */
331 | public Builder generate() {
332 | return withGenerate(true);
333 | }
334 |
335 | /**
336 | * Set the {@link GeneratorRecipe} to use when generating the value of the field.
337 | *
338 | * @param recipe the recipe to use when generating the value
339 | * @return this
340 | */
341 | public Builder withRecipe(GeneratorRecipe recipe) {
342 | this.recipe = recipe;
343 | return this;
344 | }
345 |
346 | /**
347 | * Set the {@link Section} that this field should be a part of.
348 | *
349 | * @param section the section that the field belongs to
350 | * @return this
351 | */
352 | public Builder withSection(Section section) {
353 | this.section = section;
354 | return this;
355 | }
356 |
357 | /**
358 | * Set the entropy of the generated value.
359 | *
360 | * @param entropy the entropy of the generated value
361 | * @return this
362 | */
363 | public Builder withEntropy(Double entropy) {
364 | this.entropy = entropy;
365 | return this;
366 | }
367 |
368 | /**
369 | * Set the {@link PasswordDetails} when this field is a password field.
370 | *
371 | * @param passwordDetails the password details
372 | * @return this
373 | */
374 | @JsonProperty("password_details")
375 | @JsonAlias("passwordDetails")
376 | public Builder withPasswordDetails(PasswordDetails passwordDetails) {
377 | this.passwordDetails = passwordDetails;
378 | return this;
379 | }
380 |
381 | /**
382 | * Set the current TOTP value when this field is an OTP type field.
383 | *
384 | * @param totp the current TOTP value
385 | * @return this
386 | */
387 | public Builder withTotp(String totp) {
388 | this.totp = totp;
389 | return this;
390 | }
391 |
392 | /**
393 | * Build a new {@link Field} instance based on the current configuration of
394 | * the builder.
395 | *
396 | * @return a new {@link Field} instance
397 | */
398 | public Field build() {
399 | return new Field(this);
400 | }
401 | }
402 | }
403 |
--------------------------------------------------------------------------------
/src/main/java/com/sanctionco/opconnect/model/File.java:
--------------------------------------------------------------------------------
1 | package com.sanctionco.opconnect.model;
2 |
3 | import com.fasterxml.jackson.annotation.JsonAlias;
4 | import com.fasterxml.jackson.annotation.JsonProperty;
5 | import com.fasterxml.jackson.databind.annotation.JsonDeserialize;
6 |
7 | import java.nio.charset.StandardCharsets;
8 | import java.util.Base64;
9 | import java.util.Objects;
10 | import java.util.StringJoiner;
11 |
12 | /**
13 | * Represents a file that is stored alongside an {@link Item}.
14 | */
15 | @JsonDeserialize(builder = File.Builder.class)
16 | public class File {
17 | private final String id;
18 | private final String name;
19 | private final int size;
20 | private final String contentPath;
21 | private final String content;
22 | private final Section section;
23 |
24 | private File(Builder builder) {
25 | this.id = builder.id;
26 | this.name = builder.name;
27 | this.size = builder.size;
28 | this.contentPath = builder.contentPath;
29 | this.content = builder.content;
30 | this.section = builder.section;
31 | }
32 |
33 | /**
34 | * Get the unique ID of the file.
35 | *
36 | * @return the id of this file
37 | */
38 | public String getId() {
39 | return id;
40 | }
41 |
42 | /**
43 | * Get the name of the file.
44 | *
45 | * @return the name of this file
46 | */
47 | public String getName() {
48 | return name;
49 | }
50 |
51 | /**
52 | * Get the size of the file in bytes.
53 | *
54 | * @return the size of the file in bytes
55 | */
56 | public int getSize() {
57 | return size;
58 | }
59 |
60 | /**
61 | * Get the URL path that the content of the file can be accessed at.
62 | *
63 | * @return the path to get the content
64 | */
65 | @JsonProperty("content_path")
66 | public String getContentPath() {
67 | return contentPath;
68 | }
69 |
70 | /**
71 | * Get the Base64-encoded content of this file, if {@code inlineContent} was set to true
72 | * when getting the file details.
73 | *
74 | * @return the base64-encoded content of the file if requested, or null if not
75 | */
76 | public String getContent() {
77 | return content;
78 | }
79 |
80 | /**
81 | * Get the decoded plaintext content of this file, if {@code inlineContent} was set to true
82 | * when getting the file details.
83 | *
84 | * @return the plaintext content of the file if requested, or null if not
85 | */
86 | public String getDecodedContent() {
87 | return content == null
88 | ? null
89 | : new String(Base64.getDecoder().decode(content), StandardCharsets.UTF_8);
90 | }
91 |
92 | /**
93 | * Get the {@link Section} that this file belongs to within its {@link Item}.
94 | *
95 | * @return the section that the file belongs to
96 | */
97 | public Section getSection() {
98 | return section;
99 | }
100 |
101 | @Override
102 | public boolean equals(Object o) {
103 | if (this == o) return true;
104 | if (o == null || getClass() != o.getClass()) return false;
105 | File file = (File) o;
106 | return Objects.equals(id, file.id);
107 | }
108 |
109 | @Override
110 | public int hashCode() {
111 | return Objects.hash(id);
112 | }
113 |
114 | @Override
115 | public String toString() {
116 | return new StringJoiner(", ", File.class.getSimpleName() + "[", "]")
117 | .add("id='" + id + "'")
118 | .add("name='" + name + "'")
119 | .add("size=" + size)
120 | .add("contentPath='" + contentPath + "'")
121 | .add("content='" + content + "'")
122 | .add("section=" + section)
123 | .toString();
124 | }
125 |
126 | public static Builder builder() {
127 | return new Builder();
128 | }
129 |
130 | public static class Builder {
131 | private String id;
132 | private String name;
133 | private int size;
134 | private String contentPath;
135 | private String content;
136 | private Section section;
137 |
138 | public Builder withId(String id) {
139 | this.id = id;
140 | return this;
141 | }
142 |
143 | public Builder withName(String name) {
144 | this.name = name;
145 | return this;
146 | }
147 |
148 | public Builder withSize(int size) {
149 | this.size = size;
150 | return this;
151 | }
152 |
153 | @JsonProperty("content_path")
154 | @JsonAlias("contentPath")
155 | public Builder withContentPath(String contentPath) {
156 | this.contentPath = contentPath;
157 | return this;
158 | }
159 |
160 | public Builder withContent(String content) {
161 | this.content = content;
162 | return this;
163 | }
164 |
165 | public Builder withSection(Section section) {
166 | this.section = section;
167 | return this;
168 | }
169 |
170 | public File build() {
171 | return new File(this);
172 | }
173 | }
174 | }
175 |
--------------------------------------------------------------------------------
/src/main/java/com/sanctionco/opconnect/model/Filter.java:
--------------------------------------------------------------------------------
1 | package com.sanctionco.opconnect.model;
2 |
3 | import java.util.Objects;
4 | import java.util.StringJoiner;
5 |
6 | /**
7 | * Represents SCIM-style filter that can be used to filter list requests server-side.
8 | */
9 | public class Filter {
10 | private final String filter;
11 |
12 | private Filter(Builder builder) {
13 | if (builder.operator.equals(Operator.PRESENT)) {
14 | filter = String.format("%s pr", builder.property);
15 | } else {
16 | filter = String.format("%s %s \"%s\"",
17 | builder.property, builder.operator.getOpText(), builder.value);
18 | }
19 | }
20 |
21 | private Filter(Filter other, Filter and, Filter or) {
22 | if (and == null && or == null) {
23 | filter = other.filter;
24 | } else if (and != null) {
25 | filter = String.format("(%s and %s)", other.filter, and.filter);
26 | } else {
27 | filter = String.format("(%s or %s)", other.filter, or.filter);
28 | }
29 | }
30 |
31 | /**
32 | * Get the string value of the filter.
33 | *
34 | * @return the string value of the filter
35 | */
36 | public String getFilter() {
37 | return filter;
38 | }
39 |
40 | /**
41 | * Create a new {@code Filter}, concatenating the provided
42 | * filter using the {@code and} operator.
43 | *
44 | * @param other the other filter to concatenate to this one
45 | * @return the new filter
46 | */
47 | public Filter and(Filter other) {
48 | return new Filter(this, other, null);
49 | }
50 |
51 | /**
52 | * Create a new {@code Filter}, concatenating the provided
53 | * filter using the {@code or} operator.
54 | *
55 | * @param other the other filter to concatenate to this one
56 | * @return the new filter
57 | */
58 | public Filter or(Filter other) {
59 | return new Filter(this, null, other);
60 | }
61 |
62 | @Override
63 | public boolean equals(Object o) {
64 | if (this == o) return true;
65 | if (o == null || getClass() != o.getClass()) return false;
66 | Filter filter1 = (Filter) o;
67 | return Objects.equals(filter, filter1.filter);
68 | }
69 |
70 | @Override
71 | public int hashCode() {
72 | return Objects.hash(filter);
73 | }
74 |
75 | @Override
76 | public String toString() {
77 | return new StringJoiner(", ", Filter.class.getSimpleName() + "[", "]")
78 | .add("filter='" + filter + "'")
79 | .toString();
80 | }
81 |
82 | /**
83 | * Create a new title Filter builder.
84 | *
85 | * @return a new {@code Filter.Builder}
86 | */
87 | public static Builder title() {
88 | return new Builder("title");
89 | }
90 |
91 | /**
92 | * Create a new name Filter builder.
93 | *
94 | * @return a new {@code Filter.Builder}
95 | */
96 | public static Builder name() {
97 | return new Builder("name");
98 | }
99 |
100 | /**
101 | * Create a new Filter builder on the given property.
102 | *
103 | * @param property the property to filter on
104 | * @return a new {@code Filter.Builder}
105 | */
106 | public static Builder onProperty(String property) {
107 | return new Builder(property);
108 | }
109 |
110 | /**
111 | * The builder class used to build a new {@link Filter}.
112 | */
113 | public static class Builder {
114 | private final String property;
115 | private Operator operator;
116 | private String value;
117 |
118 | private Builder(String property) {
119 | this.property = property;
120 | }
121 |
122 | private Filter withOpAndValue(Operator op, String value) {
123 | this.operator = op;
124 | this.value = value;
125 | return new Filter(this);
126 | }
127 |
128 | /**
129 | * Builds a new {@code Filter} with the 'eq' operator.
130 | * Filters based on the property exactly matching the given value.
131 | *
132 | * @param value the value that the property should be equal to
133 | * @return the new {@code Filter}
134 | */
135 | public Filter equals(String value) {
136 | return withOpAndValue(Operator.EQUALS, value);
137 | }
138 |
139 | /**
140 | * Builds a new {@code Filter} with the 'co' operator.
141 | * Filters based on the property containing the given value.
142 | *
143 | * @param value the value that the property should contain
144 | * @return the new {@code Filter}
145 | */
146 | public Filter contains(String value) {
147 | return withOpAndValue(Operator.CONTAINS, value);
148 | }
149 |
150 | /**
151 | * Builds a new {@code Filter} with the 'sw' operator.
152 | * Filters based on the property starting with the given value.
153 | *
154 | * @param value the value that the property should start with
155 | * @return the new {@code Filter}
156 | */
157 | public Filter startsWith(String value) {
158 | return withOpAndValue(Operator.STARTS_WITH, value);
159 | }
160 |
161 | /**
162 | * Builds a new {@code Filter} with the 'pr' operator.
163 | * Filters based on the property being present.
164 | *
165 | * @return the new {@code Filter}
166 | */
167 | public Filter present() {
168 | return withOpAndValue(Operator.PRESENT, "");
169 | }
170 |
171 | /**
172 | * Builds a new {@code Filter} with the 'gt' operator.
173 | * Filters based on the property being alphanumerically greater than
174 | * the given value.
175 | *
176 | * @param value the value that the property should be greater than
177 | * @return the new {@code Filter}
178 | */
179 | public Filter greaterThan(String value) {
180 | return withOpAndValue(Operator.GREATER_THAN, value);
181 | }
182 |
183 | /**
184 | * Builds a new {@code Filter} with the 'ge' operator.
185 | * Filters based on the property being alphanumerically greater than
186 | * or equal to the given value.
187 | *
188 | * @param value the value that the property should be greater than or equal to
189 | * @return the new {@code Filter}
190 | */
191 | public Filter greaterThanOrEqual(String value) {
192 | return withOpAndValue(Operator.GREATER_THAN_OR_EQUAL, value);
193 | }
194 |
195 | /**
196 | * Builds a new {@code Filter} with the 'lt' operator.
197 | * Filters based on the property being alphanumerically less than
198 | * the given value.
199 | *
200 | * @param value the value that the property should be less than
201 | * @return the new {@code Filter}
202 | */
203 | public Filter lessThan(String value) {
204 | return withOpAndValue(Operator.LESS_THAN, value);
205 | }
206 |
207 | /**
208 | * Builds a new {@code Filter} with the 'le' operator.
209 | * Filters based on the property being alphanumerically less than
210 | * or equal to the given value.
211 | *
212 | * @param value the value that the property should be less than or equal to
213 | * @return the new {@code Filter}
214 | */
215 | public Filter lessThanOrEqual(String value) {
216 | return withOpAndValue(Operator.LESS_THAN_OR_EQUAL, value);
217 | }
218 | }
219 |
220 | private enum Operator {
221 | EQUALS("eq"),
222 | CONTAINS("co"),
223 | STARTS_WITH("sw"),
224 | PRESENT("pr"),
225 | GREATER_THAN("gt"),
226 | GREATER_THAN_OR_EQUAL("ge"),
227 | LESS_THAN("lt"),
228 | LESS_THAN_OR_EQUAL("le");
229 |
230 | private final String opText;
231 |
232 | Operator(String opText) {
233 | this.opText = opText;
234 | }
235 |
236 | String getOpText() {
237 | return opText;
238 | }
239 | }
240 | }
241 |
--------------------------------------------------------------------------------
/src/main/java/com/sanctionco/opconnect/model/GeneratorRecipe.java:
--------------------------------------------------------------------------------
1 | package com.sanctionco.opconnect.model;
2 |
3 | import com.fasterxml.jackson.annotation.JsonCreator;
4 | import com.fasterxml.jackson.annotation.JsonProperty;
5 |
6 | import java.util.Collections;
7 | import java.util.List;
8 | import java.util.Objects;
9 | import java.util.StringJoiner;
10 |
11 | /**
12 | * Represents a recipe for generating a password.
13 | */
14 | public class GeneratorRecipe {
15 | private final Integer length;
16 | private final List characterSets;
17 |
18 | @JsonCreator
19 | GeneratorRecipe(@JsonProperty("length") Integer length,
20 | @JsonProperty("characterSets") List characterSets) {
21 | this.length = length;
22 | this.characterSets = Collections.unmodifiableList(characterSets);
23 | }
24 |
25 | /**
26 | * Get the length of the recipe.
27 | *
28 | * @return the length
29 | */
30 | public Integer getLength() {
31 | return length;
32 | }
33 |
34 | /**
35 | * Get the list of allowed characters.
36 | *
37 | * @return the list of allowed characters
38 | */
39 | public List getCharacterSets() {
40 | return characterSets;
41 | }
42 |
43 | /**
44 | * Create a new {@code GeneratorRecipe.Builder} with the given list of characters.
45 | *
46 | * @param characters the characters to include in generated passwords
47 | * @return the new Builder
48 | */
49 | public static Builder withAllowedCharacters(List characters) {
50 | return new Builder(characters);
51 | }
52 |
53 | /**
54 | * Create a new {@code GeneratorRecipe.Builder} with only letter characters allowed.
55 | *
56 | * @return the new Builder
57 | */
58 | public static Builder letters() {
59 | return new Builder(CharacterSet.letters());
60 | }
61 |
62 | /**
63 | * Create a new {@code GeneratorRecipe.Builder} with only digit characters allowed.
64 | *
65 | * @return the new Builder
66 | */
67 | public static Builder digits() {
68 | return new Builder(CharacterSet.digits());
69 | }
70 |
71 | /**
72 | * Create a new {@code GeneratorRecipe.Builder} with only symbol characters allowed.
73 | *
74 | * @return the new Builder
75 | */
76 | public static Builder symbols() {
77 | return new Builder(CharacterSet.symbols());
78 | }
79 |
80 | /**
81 | * Create a new {@code GeneratorRecipe.Builder} with letters and digits allowed.
82 | *
83 | * @return the new Builder
84 | */
85 | public static Builder lettersAndDigits() {
86 | return new Builder(CharacterSet.lettersAndDigits());
87 | }
88 |
89 | /**
90 | * Create a new {@code GeneratorRecipe.Builder} with letters and symbols allowed.
91 | *
92 | * @return the new Builder
93 | */
94 | public static Builder lettersAndSymbols() {
95 | return new Builder(CharacterSet.lettersAndSymbols());
96 | }
97 |
98 | /**
99 | * Create a new {@code GeneratorRecipe.Builder} with digits and symbols allowed.
100 | *
101 | * @return the new Builder
102 | */
103 | public static Builder digitsAndSymbols() {
104 | return new Builder(CharacterSet.digitsAndSymbols());
105 | }
106 |
107 | /**
108 | * Create a new {@code GeneratorRecipe.Builder} with all characters allowed.
109 | *
110 | * @return the new Builder
111 | */
112 | public static Builder allCharacters() {
113 | return new Builder(CharacterSet.allCharacters());
114 | }
115 |
116 | @Override
117 | public boolean equals(Object o) {
118 | if (this == o) return true;
119 | if (o == null || getClass() != o.getClass()) return false;
120 | GeneratorRecipe that = (GeneratorRecipe) o;
121 | return Objects.equals(length, that.length)
122 | && Objects.equals(characterSets, that.characterSets);
123 | }
124 |
125 | @Override
126 | public int hashCode() {
127 | return Objects.hash(length, characterSets);
128 | }
129 |
130 | @Override
131 | public String toString() {
132 | return new StringJoiner(", ", GeneratorRecipe.class.getSimpleName() + "[", "]")
133 | .add("length=" + length)
134 | .add("characterSets=" + characterSets)
135 | .toString();
136 | }
137 |
138 | /**
139 | * The builder class used to build a new {@link GeneratorRecipe}.
140 | */
141 | public static class Builder {
142 | private final List characters;
143 |
144 | Builder(List characters) {
145 | this.characters = characters;
146 | }
147 |
148 | /**
149 | * Create a new {@code GeneratorRecipe} with the given length.
150 | *
151 | * @param length the required length for generated passwords
152 | * @return a new {@code GeneratorRecipe} instance
153 | */
154 | public GeneratorRecipe ofLength(int length) {
155 | return new GeneratorRecipe(length, characters);
156 | }
157 | }
158 | }
159 |
--------------------------------------------------------------------------------
/src/main/java/com/sanctionco/opconnect/model/Id.java:
--------------------------------------------------------------------------------
1 | package com.sanctionco.opconnect.model;
2 |
3 | import com.fasterxml.jackson.annotation.JsonCreator;
4 | import com.fasterxml.jackson.annotation.JsonProperty;
5 |
6 | import java.util.Objects;
7 | import java.util.StringJoiner;
8 |
9 | public class Id {
10 | private final String id;
11 | private final String name;
12 |
13 | @JsonCreator
14 | public Id(@JsonProperty("id") String id,
15 | @JsonProperty("name") String name) {
16 | this.id = id;
17 | this.name = name;
18 | }
19 |
20 | public String getId() {
21 | return id;
22 | }
23 |
24 | @Override
25 | public boolean equals(Object o) {
26 | if (this == o) return true;
27 | if (o == null || getClass() != o.getClass()) return false;
28 | Id id = (Id) o;
29 | return Objects.equals(this.id, id.id) && Objects.equals(this.name, id.name);
30 | }
31 |
32 | @Override
33 | public int hashCode() {
34 | return Objects.hash(id, name);
35 | }
36 |
37 | @Override
38 | public String toString() {
39 | return new StringJoiner(", ", Id.class.getSimpleName() + "[", "]")
40 | .add("id='" + id + "'")
41 | .add("name='" + name + "'")
42 | .toString();
43 | }
44 | }
45 |
--------------------------------------------------------------------------------
/src/main/java/com/sanctionco/opconnect/model/Item.java:
--------------------------------------------------------------------------------
1 | package com.sanctionco.opconnect.model;
2 |
3 | import com.fasterxml.jackson.annotation.JsonAlias;
4 | import com.fasterxml.jackson.annotation.JsonProperty;
5 | import com.fasterxml.jackson.databind.annotation.JsonDeserialize;
6 |
7 | import java.time.Instant;
8 | import java.util.ArrayList;
9 | import java.util.List;
10 | import java.util.Objects;
11 | import java.util.StringJoiner;
12 |
13 | /**
14 | * Represents an item that is stored in a {@link Vault}.
15 | */
16 | @JsonDeserialize(builder = Item.Builder.class)
17 | public class Item {
18 | private final String id;
19 | private final String title;
20 | private final Id vaultId;
21 | private final Category category;
22 | private final List urls;
23 | private final Boolean favorite;
24 | private final List tags;
25 | private final Integer version;
26 | private final Boolean trashed;
27 | private final Instant createdAt;
28 | private final Instant updatedAt;
29 | private final String lastEditedBy;
30 | private final List sections;
31 | private final List fields;
32 | private final List files;
33 | private final String additionalInformation;
34 |
35 | private Item(Builder builder) {
36 | this.id = builder.id;
37 | this.title = builder.title;
38 | this.vaultId = builder.vaultId;
39 | this.category = builder.category;
40 | this.urls = builder.urls;
41 | this.favorite = builder.favorite;
42 | this.tags = builder.tags;
43 | this.version = builder.version;
44 | this.trashed = builder.trashed;
45 | this.createdAt = builder.createdAt;
46 | this.updatedAt = builder.updatedAt;
47 | this.lastEditedBy = builder.lastEditedBy;
48 | this.sections = builder.sections;
49 | this.fields = builder.fields;
50 | this.files = builder.files;
51 | this.additionalInformation = builder.additionalInformation;
52 | }
53 |
54 | /**
55 | * Get the unique ID of the item.
56 | *
57 | * @return the id of this item
58 | */
59 | public String getId() {
60 | return id;
61 | }
62 |
63 | /**
64 | * Get the title of the item.
65 | *
66 | * @return the title of this item
67 | */
68 | public String getTitle() {
69 | return title;
70 | }
71 |
72 | /**
73 | * Get the vault {@link Id} indicating the vault that this item belongs to.
74 | *
75 | * @return the vault id that this item belongs to
76 | */
77 | @JsonProperty("vault")
78 | public Id getVaultId() {
79 | return vaultId;
80 | }
81 |
82 | /**
83 | * Get the category of the item.
84 | *
85 | * @return the category of this item
86 | */
87 | public Category getCategory() {
88 | return category;
89 | }
90 |
91 | /**
92 | * Get the list of URLs associated with the item.
93 | *
94 | * @return the list of URLs associated with this item
95 | */
96 | public List getUrls() {
97 | return urls;
98 | }
99 |
100 | /**
101 | * Get whether or not the item has been marked as a favorite.
102 | *
103 | * @return true is this item is a favorite, false otherwise
104 | */
105 | public Boolean getFavorite() {
106 | return favorite;
107 | }
108 |
109 | /**
110 | * Get the list of tags associated with the item.
111 | *
112 | * @return the list of tags associated with this item
113 | */
114 | public List getTags() {
115 | return tags;
116 | }
117 |
118 | /**
119 | * Get the version of the item.
120 | *
121 | * @return the version of this item
122 | */
123 | public Integer getVersion() {
124 | return version;
125 | }
126 |
127 | /**
128 | * Get whether this item is in the trash.
129 | *
130 | * @return true if this item is in the trash, false otherwise
131 | */
132 | public Boolean getTrashed() {
133 | return trashed;
134 | }
135 |
136 | /**
137 | * Ge the {@link Instant} this item was created at.
138 | *
139 | * @return the time the item was created
140 | */
141 | @JsonProperty("created_at")
142 | public Instant getCreatedAt() {
143 | return createdAt;
144 | }
145 |
146 | /**
147 | * Ge the {@link Instant} this item was last updated.
148 | *
149 | * @return the time the item was last updated
150 | */
151 | @JsonProperty("updated_at")
152 | public Instant getUpdatedAt() {
153 | return updatedAt;
154 | }
155 |
156 | /**
157 | * Get the ID of the actor that this item was last edited by.
158 | *
159 | * @return the id of the actor this item was last editied by
160 | */
161 | @JsonProperty("last_edited_by")
162 | public String getLastEditedBy() {
163 | return lastEditedBy;
164 | }
165 |
166 | /**
167 | * Get the list of sections contained in this item.
168 | *
169 | * @return the list of sections contained in this item
170 | */
171 | public List getSections() {
172 | return sections;
173 | }
174 |
175 | /**
176 | * Get the list of fields contained in this item.
177 | *
178 | * @return the list of fields contained in this item
179 | */
180 | public List getFields() {
181 | return fields;
182 | }
183 |
184 | /**
185 | * Get the list of files attached to this item.
186 | *
187 | * @return the list of files attached to this item
188 | */
189 | public List getFiles() {
190 | return files;
191 | }
192 |
193 | /**
194 | * Get any additional information for this item.
195 | *
196 | * @return the item's additional information
197 | */
198 | @JsonProperty("additional_information")
199 | public String getAdditionalInformation() {
200 | return additionalInformation;
201 | }
202 |
203 | @Override
204 | public boolean equals(Object o) {
205 | if (this == o) return true;
206 | if (o == null || getClass() != o.getClass()) return false;
207 | Item item = (Item) o;
208 | return Objects.equals(id, item.id);
209 | }
210 |
211 | @Override
212 | public int hashCode() {
213 | return Objects.hash(id);
214 | }
215 |
216 | @Override
217 | public String toString() {
218 | return new StringJoiner(", ", Item.class.getSimpleName() + "[", "]")
219 | .add("id='" + id + "'")
220 | .add("title='" + title + "'")
221 | .add("vaultId=" + vaultId)
222 | .add("category=" + category)
223 | .add("urls=" + urls)
224 | .add("favorite=" + favorite)
225 | .add("tags=" + tags)
226 | .add("version=" + version)
227 | .add("trashed=" + trashed)
228 | .add("createdAt=" + createdAt)
229 | .add("updatedAt=" + updatedAt)
230 | .add("lastEditedBy='" + lastEditedBy + "'")
231 | .add("sections=" + sections)
232 | .add("fields=" + fields)
233 | .add("files=" + files)
234 | .add("additionalInformation='" + additionalInformation + "'")
235 | .toString();
236 | }
237 |
238 | public static Builder builder() {
239 | return new Builder();
240 | }
241 |
242 | public static Builder login() {
243 | return builder().withCategory(Category.LOGIN);
244 | }
245 |
246 | public static Builder password() {
247 | return builder().withCategory(Category.PASSWORD);
248 | }
249 |
250 | public static class Builder {
251 | private String id;
252 | private String title;
253 | private Id vaultId;
254 | private Category category;
255 | private List urls = new ArrayList<>();
256 | private Boolean favorite = false;
257 | private List tags = new ArrayList<>();
258 | private Integer version;
259 | private Boolean trashed = false;
260 | private Instant createdAt;
261 | private Instant updatedAt;
262 | private String lastEditedBy;
263 | private List sections = new ArrayList<>();
264 | private List fields = new ArrayList<>();
265 | private List files = new ArrayList<>();
266 | private String additionalInformation;
267 |
268 | public Builder fromItem(Item item) {
269 | this.id = item.id;
270 | this.title = item.title;
271 | this.vaultId = item.vaultId;
272 | this.category = item.category;
273 | this.urls = item.urls;
274 | this.favorite = item.favorite;
275 | this.tags = item.tags;
276 | this.version = item.version;
277 | this.trashed = item.trashed;
278 | this.createdAt = item.createdAt;
279 | this.updatedAt = item.updatedAt;
280 | this.lastEditedBy = item.lastEditedBy;
281 | this.sections = item.sections;
282 | this.fields = item.fields;
283 | this.files = item.files;
284 | this.additionalInformation = item.additionalInformation;
285 |
286 | return this;
287 | }
288 |
289 | public Builder withId(String id) {
290 | this.id = id;
291 | return this;
292 | }
293 |
294 | public Builder withTitle(String title) {
295 | this.title = title;
296 | return this;
297 | }
298 |
299 | public Builder withVault(Vault vault) {
300 | this.vaultId = new Id(vault.getId(), "");
301 | return this;
302 | }
303 |
304 | @JsonProperty("vault")
305 | public Builder withVaultId(Id vaultId) {
306 | this.vaultId = vaultId;
307 | return this;
308 | }
309 |
310 | public Builder withVaultId(String id) {
311 | this.vaultId = new Id(id, "");
312 | return this;
313 | }
314 |
315 | public Builder withCategory(Category category) {
316 | this.category = category;
317 | return this;
318 | }
319 |
320 | public Builder withUrls(List urls) {
321 | this.urls.addAll(urls);
322 | return this;
323 | }
324 |
325 | public Builder withUrl(URL url) {
326 | this.urls.add(url);
327 | return this;
328 | }
329 |
330 | public Builder withFavorite(Boolean favorite) {
331 | this.favorite = favorite;
332 | return this;
333 | }
334 |
335 | public Builder withTags(List tags) {
336 | this.tags.addAll(tags);
337 | return this;
338 | }
339 |
340 | public Builder withTag(String tag) {
341 | this.tags.add(tag);
342 | return this;
343 | }
344 |
345 | public Builder withVersion(Integer version) {
346 | this.version = version;
347 | return this;
348 | }
349 |
350 | public Builder withTrashed(Boolean trashed) {
351 | this.trashed = trashed;
352 | return this;
353 | }
354 |
355 | @JsonProperty("created_at")
356 | @JsonAlias("createdAt")
357 | public Builder withCreatedAt(Instant createdAt) {
358 | this.createdAt = createdAt;
359 | return this;
360 | }
361 |
362 | @JsonProperty("updated_at")
363 | @JsonAlias("updatedAt")
364 | public Builder withUpdatedAt(Instant updatedAt) {
365 | this.updatedAt = updatedAt;
366 | return this;
367 | }
368 |
369 | @JsonProperty("last_edited_by")
370 | @JsonAlias("lastEditedBy")
371 | public Builder withLastEditedBy(String lastEditedBy) {
372 | this.lastEditedBy = lastEditedBy;
373 | return this;
374 | }
375 |
376 | public Builder withSections(List sections) {
377 | this.sections.addAll(sections);
378 | return this;
379 | }
380 |
381 | public Builder withSection(Section section) {
382 | this.sections.add(section);
383 | return this;
384 | }
385 |
386 | public Builder withFields(List fields) {
387 | this.fields.addAll(fields);
388 | return this;
389 | }
390 |
391 | public Builder withField(Field field) {
392 | this.fields.add(field);
393 | return this;
394 | }
395 |
396 | public Builder withFiles(List files) {
397 | this.files.addAll(files);
398 | return this;
399 | }
400 |
401 | public Builder withFile(File file) {
402 | this.files.add(file);
403 | return this;
404 | }
405 |
406 | @JsonProperty("additional_information")
407 | @JsonAlias("additionalInformation")
408 | public Builder withAdditionalInformation(String additionalInformation) {
409 | this.additionalInformation = additionalInformation;
410 | return this;
411 | }
412 |
413 | public Item build() {
414 | return new Item(this);
415 | }
416 | }
417 | }
418 |
--------------------------------------------------------------------------------
/src/main/java/com/sanctionco/opconnect/model/PasswordDetails.java:
--------------------------------------------------------------------------------
1 | package com.sanctionco.opconnect.model;
2 |
3 | import com.fasterxml.jackson.annotation.JsonCreator;
4 | import com.fasterxml.jackson.annotation.JsonProperty;
5 |
6 | import java.util.List;
7 | import java.util.Objects;
8 | import java.util.StringJoiner;
9 |
10 | /**
11 | * Contains the password details for a password {@link Field}.
12 | */
13 | public class PasswordDetails {
14 | private final Double entropy;
15 | private final Boolean generated;
16 | private final String strength; // TERRIBLE, WEAK, FAIR, GOOD, VERY_GOOD, EXCELLENT, FANTASTIC
17 | private final List history;
18 |
19 | @JsonCreator
20 | public PasswordDetails(@JsonProperty("entropy") Double entropy,
21 | @JsonProperty("generated") Boolean generated,
22 | @JsonProperty("strength") String strength,
23 | @JsonProperty("history") List history) {
24 | this.entropy = entropy;
25 | this.generated = generated;
26 | this.strength = strength;
27 | this.history = history;
28 | }
29 |
30 | /**
31 | * Get the entropy of the password if generated.
32 | *
33 | * @return the entropy of the password if generated
34 | */
35 | public Double getEntropy() {
36 | return entropy;
37 | }
38 |
39 | /**
40 | * Get weather the password was generated or not.
41 | *
42 | * @return true if the password was generated, false otherwise
43 | */
44 | public Boolean getGenerated() {
45 | return generated;
46 | }
47 |
48 | /**
49 | * Get the strength of the password.
50 | *
51 | * @return the strength of the password
52 | */
53 | public String getStrength() {
54 | return strength;
55 | }
56 |
57 | /**
58 | * Get the historical values of the password.
59 | *
60 | * @return the historical values of the password
61 | */
62 | public List getHistory() {
63 | return history;
64 | }
65 |
66 | @Override
67 | public boolean equals(Object o) {
68 | if (this == o) return true;
69 | if (o == null || getClass() != o.getClass()) return false;
70 | PasswordDetails that = (PasswordDetails) o;
71 | return Objects.equals(strength, that.strength);
72 | }
73 |
74 | @Override
75 | public int hashCode() {
76 | return Objects.hash(strength);
77 | }
78 |
79 | @Override
80 | public String toString() {
81 | return new StringJoiner(", ", PasswordDetails.class.getSimpleName() + "[", "]")
82 | .add("entropy=" + entropy)
83 | .add("generated=" + generated)
84 | .add("strength='" + strength + "'")
85 | .add("history=" + history)
86 | .toString();
87 | }
88 | }
89 |
--------------------------------------------------------------------------------
/src/main/java/com/sanctionco/opconnect/model/Patch.java:
--------------------------------------------------------------------------------
1 | package com.sanctionco.opconnect.model;
2 |
3 | import com.fasterxml.jackson.databind.annotation.JsonDeserialize;
4 |
5 | import java.util.Objects;
6 | import java.util.StringJoiner;
7 |
8 | @JsonDeserialize(builder = Patch.Builder.class)
9 | public class Patch {
10 | private final PatchOperation op;
11 | private final String path;
12 | private final Object value;
13 |
14 | private Patch(PatchOperation op, String path, Object value) {
15 | this.op = op;
16 | this.path = path;
17 | this.value = value;
18 | }
19 |
20 | public PatchOperation getOp() {
21 | return op;
22 | }
23 |
24 | public String getPath() {
25 | return path;
26 | }
27 |
28 | public Object getValue() {
29 | return value;
30 | }
31 |
32 | @Override
33 | public boolean equals(Object o) {
34 | if (this == o) return true;
35 | if (o == null || getClass() != o.getClass()) return false;
36 | Patch patch = (Patch) o;
37 | return op == patch.op
38 | && Objects.equals(path, patch.path)
39 | && Objects.equals(value, patch.value);
40 | }
41 |
42 | @Override
43 | public int hashCode() {
44 | return Objects.hash(op, path, value);
45 | }
46 |
47 | @Override
48 | public String toString() {
49 | return new StringJoiner(", ", Patch.class.getSimpleName() + "[", "]")
50 | .add("op=" + op)
51 | .add("path='" + path + "'")
52 | .add("value=" + value)
53 | .toString();
54 | }
55 |
56 | public static Builder builder() {
57 | return new Builder();
58 | }
59 |
60 | public static Builder add() {
61 | return builder().withOp(PatchOperation.ADD);
62 | }
63 |
64 | public static Builder remove() {
65 | return builder().withOp(PatchOperation.REMOVE);
66 | }
67 |
68 | public static Builder replace() {
69 | return builder().withOp(PatchOperation.REPLACE);
70 | }
71 |
72 | public static class Builder {
73 | private PatchOperation op;
74 | private String path;
75 | private Object value;
76 |
77 | public Builder withOp(PatchOperation op) {
78 | this.op = op;
79 | return this;
80 | }
81 |
82 | public Builder withPath(String path) {
83 | this.path = path;
84 | return this;
85 | }
86 |
87 | public Builder withValue(Object value) {
88 | this.value = value;
89 | return this;
90 | }
91 |
92 | public Patch build() {
93 | return new Patch(op, path, value);
94 | }
95 | }
96 | }
97 |
--------------------------------------------------------------------------------
/src/main/java/com/sanctionco/opconnect/model/PatchOperation.java:
--------------------------------------------------------------------------------
1 | package com.sanctionco.opconnect.model;
2 |
3 | /**
4 | * Represents all possible patch operations that can be used when
5 | * updating an item's details in
6 | * {@link com.sanctionco.opconnect.OPConnectClient#patchItem(String, String, Patch...)}.
7 | */
8 | public enum PatchOperation {
9 | /**
10 | * The "add" operation. Used to add a value at a path.
11 | */
12 | ADD("add"),
13 |
14 | /**
15 | * The "remove" operation. Used to remove a value at a path.
16 | */
17 | REMOVE("remove"),
18 |
19 | /**
20 | * The "replace" operation. Used to replace the value at a path.
21 | */
22 | REPLACE("replace");
23 |
24 | private final String value;
25 |
26 | PatchOperation(String value) {
27 | this.value = value;
28 | }
29 |
30 | @Override
31 | public String toString() {
32 | return value;
33 | }
34 | }
35 |
--------------------------------------------------------------------------------
/src/main/java/com/sanctionco/opconnect/model/Purpose.java:
--------------------------------------------------------------------------------
1 | package com.sanctionco.opconnect.model;
2 |
3 | /**
4 | * Describes the purpose of a {@link Field}.
5 | */
6 | public enum Purpose {
7 | /**
8 | * A field that holds a username.
9 | */
10 | USERNAME,
11 |
12 | /**
13 | * A field that holds a password.
14 | */
15 | PASSWORD,
16 |
17 | /**
18 | * A field that holds notes.
19 | */
20 | NOTES
21 | }
22 |
--------------------------------------------------------------------------------
/src/main/java/com/sanctionco/opconnect/model/Section.java:
--------------------------------------------------------------------------------
1 | package com.sanctionco.opconnect.model;
2 |
3 | import com.fasterxml.jackson.annotation.JsonCreator;
4 | import com.fasterxml.jackson.annotation.JsonProperty;
5 |
6 | import java.util.Objects;
7 | import java.util.StringJoiner;
8 |
9 | /**
10 | * Represents a section within an {@link Item}.
11 | */
12 | public class Section {
13 | private final String id;
14 | private final String label;
15 |
16 | @JsonCreator
17 | public Section(@JsonProperty("id") String id,
18 | @JsonProperty("label") String label) {
19 | this.id = id;
20 | this.label = label;
21 | }
22 |
23 | /**
24 | * Get the ID of this section.
25 | *
26 | * @return the ID of this section
27 | */
28 | public String getId() {
29 | return id;
30 | }
31 |
32 | /**
33 | * Get the label of this section.
34 | *
35 | * @return the label of this section
36 | */
37 | public String getLabel() {
38 | return label;
39 | }
40 |
41 | @Override
42 | public boolean equals(Object o) {
43 | if (this == o) return true;
44 | if (o == null || getClass() != o.getClass()) return false;
45 | Section section = (Section) o;
46 | return id.equals(section.id);
47 | }
48 |
49 | @Override
50 | public int hashCode() {
51 | return Objects.hash(id);
52 | }
53 |
54 | @Override
55 | public String toString() {
56 | return new StringJoiner(", ", Section.class.getSimpleName() + "[", "]")
57 | .add("id='" + id + "'")
58 | .add("label='" + label + "'")
59 | .toString();
60 | }
61 | }
62 |
--------------------------------------------------------------------------------
/src/main/java/com/sanctionco/opconnect/model/Type.java:
--------------------------------------------------------------------------------
1 | package com.sanctionco.opconnect.model;
2 |
3 | import com.fasterxml.jackson.annotation.JsonEnumDefaultValue;
4 |
5 | public enum Type {
6 | STRING,
7 | EMAIL,
8 | CONCEALED,
9 | URL,
10 | OTP,
11 | DATE,
12 | MONTH_YEAR,
13 | MENU,
14 | CREDIT_CARD_TYPE,
15 | CREDIT_CARD_NUMBER,
16 | PHONE,
17 | ADDRESS,
18 | GENDER,
19 |
20 | @JsonEnumDefaultValue
21 | UNKNOWN
22 | }
23 |
--------------------------------------------------------------------------------
/src/main/java/com/sanctionco/opconnect/model/URL.java:
--------------------------------------------------------------------------------
1 | package com.sanctionco.opconnect.model;
2 |
3 | import com.fasterxml.jackson.annotation.JsonCreator;
4 | import com.fasterxml.jackson.annotation.JsonProperty;
5 |
6 | import java.util.Objects;
7 | import java.util.StringJoiner;
8 |
9 | /**
10 | * Represents a URL contained in an item.
11 | */
12 | public class URL {
13 | private final String label;
14 | private final String url;
15 | private final Boolean primary;
16 |
17 | @JsonCreator
18 | URL(@JsonProperty("label") String label,
19 | @JsonProperty("href") String url,
20 | @JsonProperty("primary") Boolean primary) {
21 | this.label = label;
22 | this.url = url;
23 | this.primary = primary;
24 | }
25 |
26 | /**
27 | * Get the label associated with this URL.
28 | *
29 | * @return the label of the URL
30 | */
31 | public String getLabel() {
32 | return label;
33 | }
34 |
35 | /**
36 | * Get the actual string URL.
37 | *
38 | * @return the string URL
39 | */
40 | @JsonProperty("href")
41 | public String getUrl() {
42 | return url;
43 | }
44 |
45 | /**
46 | * Get whether this URL is a primary URL address or not.
47 | *
48 | * @return true if this URL is primary, false otherwise
49 | */
50 | public Boolean getPrimary() {
51 | return primary;
52 | }
53 |
54 | @Override
55 | public boolean equals(Object o) {
56 | if (this == o) return true;
57 | if (o == null || getClass() != o.getClass()) return false;
58 | URL url1 = (URL) o;
59 | return Objects.equals(url, url1.url)
60 | && Objects.equals(primary, url1.primary)
61 | && Objects.equals(label, url1.label);
62 | }
63 |
64 | @Override
65 | public int hashCode() {
66 | return Objects.hash(label, url, primary);
67 | }
68 |
69 | @Override
70 | public String toString() {
71 | return new StringJoiner(", ", URL.class.getSimpleName() + "[", "]")
72 | .add("label='" + label + "'")
73 | .add("url='" + url + "'")
74 | .add("primary=" + primary)
75 | .toString();
76 | }
77 |
78 | /**
79 | * Create a new primary URL from the given string.
80 | *
81 | * @param url the string URL
82 | * @return a new instance of {@code URL}
83 | */
84 | public static URL primary(String url) {
85 | return new URL("", url, true);
86 | }
87 |
88 | /**
89 | * Create a new non-primary URL from the given string.
90 | *
91 | * @param url the string URL
92 | * @return a new instance of {@code URL}
93 | */
94 | public static URL standard(String url) {
95 | return new URL("", url, false);
96 | }
97 | }
98 |
--------------------------------------------------------------------------------
/src/main/java/com/sanctionco/opconnect/model/Vault.java:
--------------------------------------------------------------------------------
1 | package com.sanctionco.opconnect.model;
2 |
3 | import com.fasterxml.jackson.annotation.JsonAlias;
4 | import com.fasterxml.jackson.annotation.JsonProperty;
5 | import com.fasterxml.jackson.databind.annotation.JsonDeserialize;
6 |
7 | import java.time.Instant;
8 | import java.util.Objects;
9 | import java.util.StringJoiner;
10 |
11 | /**
12 | * Represents a Vault in 1Password. See the
13 | * documentation
14 | * for more details.
15 | */
16 | @JsonDeserialize(builder = Vault.Builder.class)
17 | public class Vault {
18 | private final String id;
19 | private final String name;
20 | private final String description;
21 | private final Integer attributeVersion;
22 | private final Integer contentVersion;
23 | private final Integer items;
24 | private final String type;
25 | private final Instant createdAt;
26 | private final Instant updatedAt;
27 |
28 | Vault(Builder builder) {
29 | this.id = builder.id;
30 | this.name = builder.name;
31 | this.description = builder.description;
32 | this.attributeVersion = builder.attributeVersion;
33 | this.contentVersion = builder.contentVersion;
34 | this.items = builder.items;
35 | this.type = builder.type;
36 | this.createdAt = builder.createdAt;
37 | this.updatedAt = builder.updatedAt;
38 | }
39 |
40 | /**
41 | * Get the ID of the vault.
42 | *
43 | * @return the ID of the vault
44 | */
45 | public String getId() {
46 | return id;
47 | }
48 |
49 | /**
50 | * Get the name of the vault.
51 | *
52 | * @return the name of the vault
53 | */
54 | public String getName() {
55 | return name;
56 | }
57 |
58 | /**
59 | * Get the description of the vault.
60 | *
61 | * @return the description of the vault
62 | */
63 | public String getDescription() {
64 | return description;
65 | }
66 |
67 | /**
68 | * Get the version of the vault metadata.
69 | *
70 | * @return the version of the vault metadata
71 | */
72 | @JsonProperty("attribute_version")
73 | public Integer getAttributeVersion() {
74 | return attributeVersion;
75 | }
76 |
77 | /**
78 | * Get the version of the vault contents.
79 | *
80 | * @return the version of the vault contents
81 | */
82 | @JsonProperty("content_version")
83 | public Integer getContentVersion() {
84 | return contentVersion;
85 | }
86 |
87 | /**
88 | * Get the number of active items in the vault.
89 | *
90 | * @return the number of active items in the vault
91 | */
92 | public Integer getItems() {
93 | return items;
94 | }
95 |
96 | /**
97 | * The type of vault. One of {@code EVERYONE} (the team shared vault), {@code PERSONAL}
98 | * (the private vault for the Connect server), or {@code USER_CREATED} (a vault created
99 | * by a user).
100 | *
101 | * @return the type of the vault
102 | */
103 | public String getType() {
104 | return type;
105 | }
106 |
107 | /**
108 | * Get the {@link Instant} that the vault was created.
109 | *
110 | * @return the time that the vault was created
111 | */
112 | @JsonProperty("created_at")
113 | public Instant getCreatedAt() {
114 | return createdAt;
115 | }
116 |
117 | /**
118 | * Get the {@link Instant} that the vault was last updated.
119 | *
120 | * @return the time that the vault was last updated
121 | */
122 | @JsonProperty("updated_at")
123 | public Instant getUpdatedAt() {
124 | return updatedAt;
125 | }
126 |
127 | @Override
128 | public boolean equals(Object o) {
129 | if (this == o) return true;
130 | if (o == null || getClass() != o.getClass()) return false;
131 | Vault vault = (Vault) o;
132 | return id.equals(vault.id);
133 | }
134 |
135 | @Override
136 | public int hashCode() {
137 | return Objects.hash(id);
138 | }
139 |
140 | @Override
141 | public String toString() {
142 | return new StringJoiner(", ", Vault.class.getSimpleName() + "[", "]")
143 | .add("id='" + id + "'")
144 | .add("name='" + name + "'")
145 | .add("description='" + description + "'")
146 | .add("attributeVersion=" + attributeVersion)
147 | .add("contentVersion=" + contentVersion)
148 | .add("items=" + items)
149 | .add("type='" + type + "'")
150 | .add("createdAt=" + createdAt)
151 | .add("updatedAt=" + updatedAt)
152 | .toString();
153 | }
154 |
155 | public static Builder builder() {
156 | return new Builder();
157 | }
158 |
159 | public static class Builder {
160 | private String id;
161 | private String name;
162 | private String description;
163 | private Integer attributeVersion;
164 | private Integer contentVersion;
165 | private Integer items;
166 | private String type;
167 | private Instant createdAt;
168 | private Instant updatedAt;
169 |
170 | public Builder withId(String id) {
171 | this.id = id;
172 | return this;
173 | }
174 |
175 | public Builder withName(String name) {
176 | this.name = name;
177 | return this;
178 | }
179 |
180 | public Builder withDescription(String description) {
181 | this.description = description;
182 | return this;
183 | }
184 |
185 | @JsonProperty("attribute_version")
186 | @JsonAlias("attributeVersion")
187 | public Builder withAttributeVersion(Integer attributeVersion) {
188 | this.attributeVersion = attributeVersion;
189 | return this;
190 | }
191 |
192 | @JsonProperty("content_version")
193 | @JsonAlias("contentVersion")
194 | public Builder withContentVersion(Integer contentVersion) {
195 | this.contentVersion = contentVersion;
196 | return this;
197 | }
198 |
199 | public Builder withItems(Integer items) {
200 | this.items = items;
201 | return this;
202 | }
203 |
204 | public Builder withType(String type) {
205 | this.type = type;
206 | return this;
207 | }
208 |
209 | @JsonProperty("created_at")
210 | @JsonAlias("createdAt")
211 | public Builder withCreatedAt(Instant createdAt) {
212 | this.createdAt = createdAt;
213 | return this;
214 | }
215 |
216 | @JsonProperty("updated_at")
217 | @JsonAlias("updatedAt")
218 | public Builder withUpdatedAt(Instant updatedAt) {
219 | this.updatedAt = updatedAt;
220 | return this;
221 | }
222 |
223 | public Vault build() {
224 | return new Vault(this);
225 | }
226 | }
227 | }
228 |
--------------------------------------------------------------------------------
/src/main/java/com/sanctionco/opconnect/model/apiactivity/APIRequest.java:
--------------------------------------------------------------------------------
1 | package com.sanctionco.opconnect.model.apiactivity;
2 |
3 | import com.fasterxml.jackson.annotation.JsonCreator;
4 | import com.fasterxml.jackson.annotation.JsonProperty;
5 |
6 | import java.time.Instant;
7 | import java.util.Objects;
8 | import java.util.StringJoiner;
9 |
10 | /**
11 | * Represents an {@code APIRequest} made to 1Password.
12 | */
13 | public class APIRequest {
14 | private final String requestId;
15 | private final Instant timestamp;
16 | private final APIRequestAction action;
17 | private final APIRequestResult result;
18 | private final Actor actor;
19 | private final Resource resource;
20 |
21 | @JsonCreator
22 | APIRequest(@JsonProperty("requestId") String requestId,
23 | @JsonProperty("timestamp") Instant timestamp,
24 | @JsonProperty("action") APIRequestAction action,
25 | @JsonProperty("result") APIRequestResult result,
26 | @JsonProperty("actor") Actor actor,
27 | @JsonProperty("resource") Resource resource) {
28 | this.requestId = requestId;
29 | this.timestamp = timestamp;
30 | this.action = action;
31 | this.result = result;
32 | this.actor = actor;
33 | this.resource = resource;
34 | }
35 |
36 | /**
37 | * Get the id associated with this request.
38 | *
39 | * @return the id for the request
40 | */
41 | public String getRequestId() {
42 | return requestId;
43 | }
44 |
45 | /**
46 | * Get the time this request was made.
47 | *
48 | * @return the time the request was made
49 | */
50 | public Instant getTimestamp() {
51 | return timestamp;
52 | }
53 |
54 | /**
55 | * Get the action requested.
56 | *
57 | * @return the type of action requested
58 | */
59 | public APIRequestAction getAction() {
60 | return action;
61 | }
62 |
63 | /**
64 | * Get the result of the request.
65 | *
66 | * @return the result of the request
67 | */
68 | public APIRequestResult getResult() {
69 | return result;
70 | }
71 |
72 | /**
73 | * Get the actor who made the request.
74 | *
75 | * @return the {@link Actor} that made the request
76 | */
77 | public Actor getActor() {
78 | return actor;
79 | }
80 |
81 | /**
82 | * Get the resource requested.
83 | *
84 | * @return the {@link Resource requested}
85 | */
86 | public Resource getResource() {
87 | return resource;
88 | }
89 |
90 | @Override
91 | public boolean equals(Object o) {
92 | if (this == o) return true;
93 | if (o == null || getClass() != o.getClass()) return false;
94 | APIRequest that = (APIRequest) o;
95 | return Objects.equals(requestId, that.requestId)
96 | && Objects.equals(timestamp, that.timestamp)
97 | && action == that.action
98 | && result == that.result
99 | && Objects.equals(actor, that.actor)
100 | && Objects.equals(resource, that.resource);
101 | }
102 |
103 | @Override
104 | public int hashCode() {
105 | return Objects.hash(requestId, timestamp, action, result, actor, resource);
106 | }
107 |
108 | @Override
109 | public String toString() {
110 | return new StringJoiner(", ", APIRequest.class.getSimpleName() + "[", "]")
111 | .add("requestID='" + requestId + "'")
112 | .add("timestamp=" + timestamp)
113 | .add("action=" + action)
114 | .add("result=" + result)
115 | .add("actor=" + actor)
116 | .add("resource=" + resource)
117 | .toString();
118 | }
119 | }
120 |
--------------------------------------------------------------------------------
/src/main/java/com/sanctionco/opconnect/model/apiactivity/APIRequestAction.java:
--------------------------------------------------------------------------------
1 | package com.sanctionco.opconnect.model.apiactivity;
2 |
3 | /**
4 | * Represents an action that occurred from an {@link APIRequest}.
5 | */
6 | public enum APIRequestAction {
7 | /**
8 | * Represents a READ (i.e. GET) API request action.
9 | */
10 | READ,
11 |
12 | /**
13 | * Represents a CREATE (i.e. POST) API request action.
14 | */
15 | CREATE,
16 |
17 | /**
18 | * Represents an UPDATE (i.e. PUT or PATCH) API request action.
19 | */
20 | UPDATE,
21 |
22 | /**
23 | * Represents a DELETE (i.e. DELETE) API request action.
24 | */
25 | DELETE
26 | }
27 |
--------------------------------------------------------------------------------
/src/main/java/com/sanctionco/opconnect/model/apiactivity/APIRequestResult.java:
--------------------------------------------------------------------------------
1 | package com.sanctionco.opconnect.model.apiactivity;
2 |
3 | /**
4 | * Represents a result of an {@link APIRequest}.
5 | */
6 | public enum APIRequestResult {
7 | /**
8 | * Represents a successful API request.
9 | */
10 | SUCCESS,
11 |
12 | /**
13 | * Represents an API request that was denied.
14 | */
15 | DENY
16 | }
17 |
--------------------------------------------------------------------------------
/src/main/java/com/sanctionco/opconnect/model/apiactivity/Actor.java:
--------------------------------------------------------------------------------
1 | package com.sanctionco.opconnect.model.apiactivity;
2 |
3 | import com.fasterxml.jackson.annotation.JsonCreator;
4 | import com.fasterxml.jackson.annotation.JsonProperty;
5 |
6 | import java.util.Objects;
7 | import java.util.StringJoiner;
8 |
9 | /**
10 | * Represents an actor (1Password connect server) that performed an {@link APIRequest}.
11 | *
12 | * See the
13 | * APIRequest documentation for more details.
14 | */
15 | public class Actor {
16 | private final String id;
17 | private final String account;
18 | private final String jti;
19 | private final String userAgent;
20 | private final String ip;
21 |
22 | @JsonCreator
23 | Actor(@JsonProperty("id") String id,
24 | @JsonProperty("account") String account,
25 | @JsonProperty("jti") String jti,
26 | @JsonProperty("userAgent") String userAgent,
27 | @JsonProperty("ip") String ip) {
28 | this.id = id;
29 | this.account = account;
30 | this.jti = jti;
31 | this.userAgent = userAgent;
32 | this.ip = ip;
33 | }
34 |
35 | /**
36 | * Get the ID of the {@code Actor}.
37 | *
38 | * @return the id of the actor (connect sever)
39 | */
40 | public String getId() {
41 | return id;
42 | }
43 |
44 | /**
45 | * Get the 1Password account ID.
46 | *
47 | * @return the id of the 1Password account the actor belongs to
48 | */
49 | public String getAccount() {
50 | return account;
51 | }
52 |
53 | /**
54 | * Get the Access Token ID.
55 | *
56 | * @return the id of the access token used to authenticate the request
57 | */
58 | public String getJti() {
59 | return jti;
60 | }
61 |
62 | /**
63 | * Get the user-agent string.
64 | *
65 | * @return the user agent string specified in the request
66 | */
67 | public String getUserAgent() {
68 | return userAgent;
69 | }
70 |
71 | /**
72 | * Get the IP address.
73 | *
74 | * @return the ip address the request originated from
75 | */
76 | public String getIp() {
77 | return ip;
78 | }
79 |
80 | @Override
81 | public boolean equals(Object o) {
82 | if (this == o) return true;
83 | if (o == null || getClass() != o.getClass()) return false;
84 | Actor actor = (Actor) o;
85 | return Objects.equals(id, actor.id)
86 | && Objects.equals(account, actor.account)
87 | && Objects.equals(jti, actor.jti)
88 | && Objects.equals(userAgent, actor.userAgent)
89 | && Objects.equals(ip, actor.ip);
90 | }
91 |
92 | @Override
93 | public int hashCode() {
94 | return Objects.hash(id, account, jti, userAgent, ip);
95 | }
96 |
97 | @Override
98 | public String toString() {
99 | return new StringJoiner(", ", Actor.class.getSimpleName() + "[", "]")
100 | .add("id='" + id + "'")
101 | .add("account='" + account + "'")
102 | .add("jti='" + jti + "'")
103 | .add("userAgent='" + userAgent + "'")
104 | .add("ip='" + ip + "'")
105 | .toString();
106 | }
107 | }
108 |
--------------------------------------------------------------------------------
/src/main/java/com/sanctionco/opconnect/model/apiactivity/Resource.java:
--------------------------------------------------------------------------------
1 | package com.sanctionco.opconnect.model.apiactivity;
2 |
3 | import com.fasterxml.jackson.annotation.JsonCreator;
4 | import com.fasterxml.jackson.annotation.JsonProperty;
5 | import com.sanctionco.opconnect.model.Id;
6 |
7 | import java.util.Objects;
8 | import java.util.StringJoiner;
9 |
10 | /**
11 | * Represents a resource that was specified in an {@link APIRequest}.
12 | */
13 | public class Resource {
14 | private final ResourceType type;
15 | private final Id vaultId;
16 | private final Id itemId;
17 | private final Integer itemVersion;
18 |
19 | @JsonCreator
20 | Resource(@JsonProperty("type") ResourceType type,
21 | @JsonProperty("vault") Id vaultId,
22 | @JsonProperty("item") Id itemId,
23 | @JsonProperty("itemVersion") Integer itemVersion) {
24 | this.type = type;
25 | this.vaultId = vaultId;
26 | this.itemId = itemId;
27 | this.itemVersion = itemVersion;
28 | }
29 |
30 | /**
31 | * Get the type of the resource.
32 | *
33 | * @return the type of the resource requested
34 | */
35 | public ResourceType getType() {
36 | return type;
37 | }
38 |
39 | /**
40 | * Get the ID of the of the vault requested.
41 | *
42 | * @return an object containing the ID of the vault requested
43 | */
44 | public Id getVaultId() {
45 | return vaultId;
46 | }
47 |
48 | /**
49 | * Get the ID of the item requested.
50 | *
51 | * @return an object containing the ID of the item requested
52 | */
53 | public Id getItemId() {
54 | return itemId;
55 | }
56 |
57 | /**
58 | * Get the version of the item requested.
59 | *
60 | * @return the version of the item requested
61 | */
62 | public Integer getItemVersion() {
63 | return itemVersion;
64 | }
65 |
66 | @Override
67 | public boolean equals(Object o) {
68 | if (this == o) return true;
69 | if (o == null || getClass() != o.getClass()) return false;
70 | Resource resource = (Resource) o;
71 | return type == resource.type
72 | && Objects.equals(vaultId, resource.vaultId)
73 | && Objects.equals(itemId, resource.itemId)
74 | && Objects.equals(itemVersion, resource.itemVersion);
75 | }
76 |
77 | @Override
78 | public int hashCode() {
79 | return Objects.hash(type, vaultId, itemId, itemVersion);
80 | }
81 |
82 | @Override
83 | public String toString() {
84 | return new StringJoiner(", ", Resource.class.getSimpleName() + "[", "]")
85 | .add("type=" + type)
86 | .add("vaultId=" + vaultId)
87 | .add("itemId=" + itemId)
88 | .add("itemVersion=" + itemVersion)
89 | .toString();
90 | }
91 | }
92 |
--------------------------------------------------------------------------------
/src/main/java/com/sanctionco/opconnect/model/apiactivity/ResourceType.java:
--------------------------------------------------------------------------------
1 | package com.sanctionco.opconnect.model.apiactivity;
2 |
3 | /**
4 | * Represents a type of resource involved in an {@link APIRequest}.
5 | */
6 | public enum ResourceType {
7 | /**
8 | * Represents the {@link com.sanctionco.opconnect.model.Item} resource.
9 | */
10 | ITEM,
11 |
12 | /**
13 | * Represents the {@link com.sanctionco.opconnect.model.Vault} resource.
14 | */
15 | VAULT
16 | }
17 |
--------------------------------------------------------------------------------
/src/main/java/com/sanctionco/opconnect/model/health/ConnectServer.java:
--------------------------------------------------------------------------------
1 | package com.sanctionco.opconnect.model.health;
2 |
3 | import com.fasterxml.jackson.annotation.JsonCreator;
4 | import com.fasterxml.jackson.annotation.JsonProperty;
5 |
6 | import java.util.List;
7 | import java.util.Objects;
8 | import java.util.StringJoiner;
9 |
10 | /**
11 | * Represents details on the 1Password Connect Server, including
12 | * its dependencies.
13 | */
14 | public class ConnectServer {
15 | private final String name;
16 | private final String version;
17 | private final List dependencies;
18 |
19 | @JsonCreator
20 | ConnectServer(@JsonProperty("name") String name,
21 | @JsonProperty("version") String version,
22 | @JsonProperty("dependencies") List dependencies) {
23 | this.name = name;
24 | this.version = version;
25 | this.dependencies = dependencies;
26 | }
27 |
28 | /**
29 | * The name of the Connect server.
30 | *
31 | * @return the name
32 | */
33 | public String getName() {
34 | return name;
35 | }
36 |
37 | /**
38 | * The current version of the Connect server.
39 | *
40 | * @return the current version
41 | */
42 | public String getVersion() {
43 | return version;
44 | }
45 |
46 | /**
47 | * The list of {@link Dependency} objects that the Connect server depends on.
48 | *
49 | * @return the list of {@link Dependency} objects
50 | */
51 | public List getDependencies() {
52 | return dependencies;
53 | }
54 |
55 | @Override
56 | public boolean equals(Object o) {
57 | if (this == o) return true;
58 | if (o == null || getClass() != o.getClass()) return false;
59 | ConnectServer that = (ConnectServer) o;
60 | return Objects.equals(name, that.name)
61 | && Objects.equals(version, that.version)
62 | && Objects.equals(dependencies, that.dependencies);
63 | }
64 |
65 | @Override
66 | public int hashCode() {
67 | return Objects.hash(name, version, dependencies);
68 | }
69 |
70 | @Override
71 | public String toString() {
72 | return new StringJoiner(", ", ConnectServer.class.getSimpleName() + "[", "]")
73 | .add("name='" + name + "'")
74 | .add("version='" + version + "'")
75 | .add("dependencies=" + dependencies)
76 | .toString();
77 | }
78 | }
79 |
--------------------------------------------------------------------------------
/src/main/java/com/sanctionco/opconnect/model/health/Dependency.java:
--------------------------------------------------------------------------------
1 | package com.sanctionco.opconnect.model.health;
2 |
3 | import com.fasterxml.jackson.annotation.JsonCreator;
4 | import com.fasterxml.jackson.annotation.JsonProperty;
5 |
6 | import java.util.Objects;
7 | import java.util.StringJoiner;
8 |
9 | /**
10 | * Represents a 1Password Connect Server dependency.
11 | */
12 | public class Dependency {
13 | private final String service;
14 | private final String status;
15 | private final String message;
16 |
17 | @JsonCreator
18 | Dependency(@JsonProperty("service") String service,
19 | @JsonProperty("status") String status,
20 | @JsonProperty("message") String message) {
21 | this.service = service;
22 | this.status = status;
23 | this.message = message;
24 | }
25 |
26 | /**
27 | * The name of the dependency service.
28 | *
29 | * @return the name
30 | */
31 | public String getService() {
32 | return service;
33 | }
34 |
35 | /**
36 | * The current status of the dependency.
37 | *
38 | * @return the status
39 | */
40 | public String getStatus() {
41 | return status;
42 | }
43 |
44 | /**
45 | * The latest message that describes the status of the dependency.
46 | *
47 | * @return the message description
48 | */
49 | public String getMessage() {
50 | return message;
51 | }
52 |
53 | @Override
54 | public boolean equals(Object o) {
55 | if (this == o) return true;
56 | if (o == null || getClass() != o.getClass()) return false;
57 | Dependency that = (Dependency) o;
58 | return Objects.equals(service, that.service);
59 | }
60 |
61 | @Override
62 | public int hashCode() {
63 | return Objects.hash(service);
64 | }
65 |
66 | @Override
67 | public String toString() {
68 | return new StringJoiner(", ", Dependency.class.getSimpleName() + "[", "]")
69 | .add("service='" + service + "'")
70 | .add("status='" + status + "'")
71 | .add("message='" + message + "'")
72 | .toString();
73 | }
74 | }
75 |
--------------------------------------------------------------------------------
/src/test/java/com/sanctionco/opconnect/IntegrationTest.java:
--------------------------------------------------------------------------------
1 | package com.sanctionco.opconnect;
2 |
3 | import com.sanctionco.opconnect.model.Category;
4 | import com.sanctionco.opconnect.model.Field;
5 | import com.sanctionco.opconnect.model.File;
6 | import com.sanctionco.opconnect.model.Filter;
7 | import com.sanctionco.opconnect.model.GeneratorRecipe;
8 | import com.sanctionco.opconnect.model.Id;
9 | import com.sanctionco.opconnect.model.Item;
10 | import com.sanctionco.opconnect.model.Patch;
11 | import com.sanctionco.opconnect.model.Purpose;
12 | import com.sanctionco.opconnect.model.Section;
13 | import com.sanctionco.opconnect.model.Type;
14 | import com.sanctionco.opconnect.model.URL;
15 | import com.sanctionco.opconnect.model.Vault;
16 | import com.sanctionco.opconnect.model.apiactivity.APIRequest;
17 | import com.sanctionco.opconnect.model.apiactivity.APIRequestResult;
18 | import com.sanctionco.opconnect.model.health.ConnectServer;
19 |
20 | import java.time.Instant;
21 | import java.util.Arrays;
22 | import java.util.List;
23 | import java.util.Set;
24 | import java.util.concurrent.CompletionException;
25 | import java.util.stream.Collectors;
26 |
27 | import org.junit.jupiter.api.Assertions;
28 | import org.junit.jupiter.api.DisplayName;
29 | import org.junit.jupiter.api.MethodOrderer;
30 | import org.junit.jupiter.api.Order;
31 | import org.junit.jupiter.api.Test;
32 | import org.junit.jupiter.api.TestInstance;
33 | import org.junit.jupiter.api.TestMethodOrder;
34 | import org.junit.jupiter.api.condition.EnabledIfEnvironmentVariable;
35 | import org.junit.jupiter.params.ParameterizedTest;
36 | import org.junit.jupiter.params.provider.EnumSource;
37 |
38 | import retrofit2.HttpException;
39 |
40 | import static org.junit.jupiter.api.Assertions.assertAll;
41 | import static org.junit.jupiter.api.Assertions.assertDoesNotThrow;
42 | import static org.junit.jupiter.api.Assertions.assertEquals;
43 | import static org.junit.jupiter.api.Assertions.assertFalse;
44 | import static org.junit.jupiter.api.Assertions.assertNotEquals;
45 | import static org.junit.jupiter.api.Assertions.assertNotNull;
46 | import static org.junit.jupiter.api.Assertions.assertThrows;
47 | import static org.junit.jupiter.api.Assertions.assertTrue;
48 | import static org.junit.jupiter.api.Assertions.fail;
49 |
50 | @DisplayName("OPConnectClient")
51 | @TestInstance(TestInstance.Lifecycle.PER_CLASS)
52 | @TestMethodOrder(MethodOrderer.OrderAnnotation.class)
53 | @EnabledIfEnvironmentVariable(named = "OP_ACCESS_TOKEN", matches = ".*")
54 | class IntegrationTest {
55 | private static final String TOKEN = System.getenv("OP_ACCESS_TOKEN");
56 | private static final OPConnectClient CLIENT = OPConnectClient.builder()
57 | .withEndpoint("http://localhost:8080/")
58 | .withAccessToken(TOKEN)
59 | .build();
60 |
61 | private static final String VAULT_ID = "5ve5wfpdu2kxxhj2jdozmes5re";
62 | private static final String LOGIN_ITEM_ID = "piy7k3izsuzafhypw6iddpwhqe";
63 | private static final String DOCUMENT_ITEM_ID = "ukg5hwis76syhwdgc6jqcyx4vq";
64 | private static final String DOCUMENT_FILE_ID = "tf5sqssrufeevojd4urpmf4n3u";
65 | private static final Integer CATEGORY_COUNT = Category.values().length - 1;
66 | private static final List- ALL_ITEMS = CLIENT.listItems(VAULT_ID).join();
67 |
68 | private String createdItemId;
69 |
70 | @Test
71 | void shouldListSingleVault() {
72 | List vaults = CLIENT.listVaults().join();
73 |
74 | assertEquals(1, vaults.size());
75 |
76 | Vault vault = vaults.get(0);
77 |
78 | assertAll("The vault properties are as expected",
79 | () -> assertEquals(VAULT_ID, vault.getId()),
80 | () -> assertEquals("Integration Test", vault.getName()),
81 | () -> assertEquals("Java SDK Integration Tests", vault.getDescription()),
82 | () -> assertTrue(vault.getCreatedAt().isBefore(Instant.now())));
83 | }
84 |
85 | @Test
86 | void shouldListVaultsWithStringFilter() {
87 | List vaults = CLIENT.listVaults("name eq \"Integration Test\"").join();
88 |
89 | assertEquals(1, vaults.size());
90 |
91 | Vault vault = vaults.get(0);
92 |
93 | assertAll("The vault properties are as expected",
94 | () -> assertEquals(VAULT_ID, vault.getId()),
95 | () -> assertEquals("Integration Test", vault.getName()),
96 | () -> assertEquals("Java SDK Integration Tests", vault.getDescription()),
97 | () -> assertTrue(vault.getCreatedAt().isBefore(Instant.now())));
98 |
99 | List noVaults = CLIENT.listVaults("name eq \"Nonexistent\"").join();
100 |
101 | assertEquals(0, noVaults.size());
102 | }
103 |
104 | @Test
105 | void shouldListVaultsWithFilterObject() {
106 | List vaults = CLIENT.listVaults(Filter.name().equals("Integration Test")).join();
107 |
108 | assertEquals(1, vaults.size());
109 |
110 | Vault vault = vaults.get(0);
111 |
112 | assertAll("The vault properties are as expected",
113 | () -> assertEquals(VAULT_ID, vault.getId()),
114 | () -> assertEquals("Integration Test", vault.getName()),
115 | () -> assertEquals("Java SDK Integration Tests", vault.getDescription()),
116 | () -> assertTrue(vault.getCreatedAt().isBefore(Instant.now())));
117 |
118 | List noVaults = CLIENT.listVaults(Filter.name().equals("Nonexistent")).join();
119 |
120 | assertEquals(0, noVaults.size());
121 | }
122 |
123 | @Test
124 | void shouldFailToReadUnknownVaultId() {
125 | CompletionException e = assertThrows(CompletionException.class,
126 | () -> CLIENT.getVault(LOGIN_ITEM_ID).join());
127 |
128 | assertTrue(e.getCause() instanceof HttpException);
129 |
130 | HttpException httpResponse = (HttpException) e.getCause();
131 |
132 | assertEquals(403, httpResponse.code());
133 | }
134 |
135 | @Test
136 | void shouldGetVaultDetails() {
137 | Vault vault = CLIENT.getVault(VAULT_ID).join();
138 |
139 | assertAll("The vault properties are as expected",
140 | () -> assertEquals(VAULT_ID, vault.getId()),
141 | () -> assertEquals("Integration Test", vault.getName()),
142 | () -> assertEquals("Java SDK Integration Tests", vault.getDescription()),
143 | () -> assertTrue(vault.getCreatedAt().isBefore(Instant.now())));
144 | }
145 |
146 | @Test
147 | @Order(1)
148 | void shouldListItems() {
149 | List
- items = CLIENT.listItems(VAULT_ID).join();
150 |
151 | // CATEGORY_COUNT sample items, each of a different category
152 | assertEquals(CATEGORY_COUNT, items.size());
153 | items.forEach(item -> assertEquals(VAULT_ID, item.getVaultId().getId()));
154 |
155 | Set categories = items.stream().map(Item::getCategory).collect(Collectors.toSet());
156 |
157 | assertEquals(CATEGORY_COUNT, categories.size());
158 |
159 | Arrays.stream(Category.values())
160 | .forEach(category -> {
161 | // Skip CUSTOM as we don't have that item in the vault
162 | if (Category.CUSTOM.equals(category)) return;
163 |
164 | assertTrue(categories.contains(category));
165 | });
166 | }
167 |
168 | @Test
169 | @Order(1)
170 | void shouldListTitleFilteredItemsUsingString() {
171 | List
- sampleItems = CLIENT.listItems(VAULT_ID, "title co \"Sample\"").join();
172 | assertEquals(CATEGORY_COUNT, sampleItems.size());
173 |
174 | List
- passwordItems = CLIENT.listItems(VAULT_ID, "title eq \"Sample Password\"").join();
175 | assertEquals(1, passwordItems.size());
176 |
177 | List
- passwordAndCreditCard = CLIENT
178 | .listItems(VAULT_ID, "title eq \"Sample Password\" or title co \"Credit\"").join();
179 | assertEquals(2, passwordAndCreditCard.size());
180 |
181 | List
- noItems = CLIENT.listItems(VAULT_ID, "title eq \"Not Exist\"").join();
182 | assertEquals(0, noItems.size());
183 | }
184 |
185 | @Test
186 | @Order(1)
187 | void shouldListTitleFilteredItemsUsingFilter() {
188 | List
- sampleItems = CLIENT
189 | .listItems(VAULT_ID, Filter.title().contains("Sample")).join();
190 | assertEquals(CATEGORY_COUNT, sampleItems.size());
191 |
192 | List
- passwordItems = CLIENT
193 | .listItems(VAULT_ID, Filter.title().equals("Sample Password")).join();
194 | assertEquals(1, passwordItems.size());
195 |
196 | List
- passwordAndCreditCard = CLIENT
197 | .listItems(VAULT_ID, Filter.title()
198 | .equals("Sample Password")
199 | .or(Filter.title().contains("Credit")))
200 | .join();
201 | assertEquals(2, passwordAndCreditCard.size());
202 |
203 | List
- noItems = CLIENT
204 | .listItems(VAULT_ID, Filter.title().equals("Not Exist")).join();
205 | assertEquals(0, noItems.size());
206 | }
207 |
208 | @Test
209 | void shouldFailToReadUnknownItem() {
210 | CompletionException e = assertThrows(CompletionException.class,
211 | () -> CLIENT.getItem(VAULT_ID, VAULT_ID).join());
212 |
213 | assertTrue(e.getCause() instanceof HttpException);
214 |
215 | HttpException httpResponse = (HttpException) e.getCause();
216 |
217 | assertEquals(404, httpResponse.code());
218 | }
219 |
220 | @Test
221 | void shouldGetLoginItemDetails() {
222 | Item item = CLIENT.getItem(VAULT_ID, LOGIN_ITEM_ID).join();
223 |
224 | assertAll("The item properties are as expected",
225 | () -> assertEquals("Sample Login", item.getTitle()),
226 | () -> assertEquals(Category.LOGIN, item.getCategory()),
227 | () -> assertEquals(1, item.getUrls().size()),
228 | () -> assertEquals("https://www.example.com", item.getUrls().get(0).getUrl()),
229 | () -> assertTrue(item.getUrls().get(0).getPrimary()),
230 | () -> assertTrue(item.getFavorite()),
231 | () -> assertEquals(2, item.getTags().size()),
232 | () -> assertFalse(item.getTrashed()),
233 | () -> assertEquals(4, item.getSections().size()),
234 | () -> assertTrue(item.getSections().contains(
235 | new Section("Section_vdb57dmcdx6mej4wpu632j6pru", "Test Section One"))),
236 | () -> assertEquals(6, item.getFields().size())
237 | );
238 | }
239 |
240 | @Test
241 | void shouldListFiles() {
242 | List files = CLIENT.listFiles(VAULT_ID, DOCUMENT_ITEM_ID).join();
243 |
244 | assertEquals(1, files.size());
245 | assertEquals("test.txt", files.get(0).getName());
246 |
247 | // Also be able to get content
248 | files = CLIENT.listFiles(VAULT_ID, DOCUMENT_ITEM_ID, true).join();
249 |
250 | assertEquals(1, files.size());
251 | assertEquals("test.txt", files.get(0).getName());
252 | assertNotNull(files.get(0).getContent());
253 | assertEquals("Test\n", files.get(0).getDecodedContent());
254 | }
255 |
256 | @Test
257 | void shouldGetFile() {
258 | File file = CLIENT.getFile(VAULT_ID, DOCUMENT_ITEM_ID, DOCUMENT_FILE_ID).join();
259 |
260 | assertEquals("test.txt", file.getName());
261 |
262 | // Also be able to get content
263 | File contentFile = CLIENT.getFile(VAULT_ID, DOCUMENT_ITEM_ID, DOCUMENT_FILE_ID, true).join();
264 |
265 | assertEquals("test.txt", contentFile.getName());
266 | assertNotNull(contentFile.getContent());
267 | assertEquals("Test\n", contentFile.getDecodedContent());
268 | }
269 |
270 | @Test
271 | void shouldGetFileContent() {
272 | String content = CLIENT.getFileContent(VAULT_ID, DOCUMENT_ITEM_ID, DOCUMENT_FILE_ID).join();
273 |
274 | assertEquals("Test\n", content);
275 | }
276 |
277 | @ParameterizedTest
278 | @EnumSource(mode = EnumSource.Mode.EXCLUDE, names = { "CUSTOM" })
279 | void shouldGetItemDetailsForEachCategory(Category category) {
280 | String id = ALL_ITEMS.stream()
281 | .filter(item -> category.equals(item.getCategory()))
282 | .findAny()
283 | .orElseGet(Assertions::fail)
284 | .getId();
285 |
286 | Item item = CLIENT.getItem(VAULT_ID, id).join();
287 |
288 | assertAll(
289 | () -> assertEquals(id, item.getId()),
290 | () -> assertEquals(category, item.getCategory()));
291 | }
292 |
293 | @Test
294 | @Order(2)
295 | void shouldCreateItem() {
296 | Item item = Item.login().withTitle("Integration Test Created Login")
297 | .withVaultId(VAULT_ID)
298 | .withField(Field.username("testuser").build())
299 | .withField(Field.generatedPassword(GeneratorRecipe.letters().ofLength(30)).build())
300 | .withUrl(URL.primary("https://www.test.com"))
301 | .build();
302 |
303 | Item created = CLIENT.createItem(VAULT_ID, item).join();
304 |
305 | this.createdItemId = created.getId();
306 |
307 | assertAll("Created Item is as expected",
308 | () -> assertEquals("Integration Test Created Login", created.getTitle()),
309 | () -> assertEquals(Category.LOGIN, created.getCategory()),
310 | () -> assertEquals(3, created.getFields().size()),
311 | () -> assertEquals(Purpose.USERNAME, created.getFields().get(0).getPurpose()),
312 | () -> assertEquals("testuser", created.getFields().get(0).getValue()),
313 | () -> assertEquals(1, created.getUrls().size()),
314 | () -> assertEquals("https://www.test.com", created.getUrls().get(0).getUrl())
315 | );
316 | }
317 |
318 | @Test
319 | @Order(3)
320 | void shouldPatchItem() throws Exception {
321 | if (createdItemId == null) fail("The createItem test needs to run before patchItem");
322 |
323 | // Wait for 1 second in order to make sure the created item exists
324 | Thread.sleep(1000);
325 |
326 | // Get the item first
327 | Item created = CLIENT.getItem(VAULT_ID, createdItemId).join();
328 | String usernameFieldId = created.getFields().get(0).getId();
329 | Field updatedField = Field.username("patchOne").build();
330 |
331 | Item patched = CLIENT.patchItem(VAULT_ID, createdItemId,
332 | Patch.replace()
333 | .withValue(updatedField)
334 | .withPath("/fields/" + usernameFieldId)
335 | .build()).join();
336 |
337 | assertAll(
338 | () -> assertEquals("Integration Test Created Login", patched.getTitle()),
339 | () -> assertEquals(Purpose.USERNAME, patched.getFields().get(0).getPurpose()),
340 | () -> assertEquals("patchOne", patched.getFields().get(0).getValue()));
341 | }
342 |
343 | @Test
344 | @Order(4)
345 | void shouldPatchWithMultipleChanges() throws Exception {
346 | if (createdItemId == null) fail("The createItem test needs to run before patchItem");
347 |
348 | // Wait in order to make sure the created item exists
349 | Thread.sleep(400L);
350 |
351 | // Get the item first
352 | Item created = CLIENT.getItem(VAULT_ID, createdItemId).join();
353 |
354 | String usernameFieldId = created.getFields().get(0).getId();
355 | Field updatedUsername = Field.username("patchTwo").build();
356 |
357 | Field newField = Field.labeled("multiPatchLabel")
358 | .withType(Type.STRING)
359 | .withValue("patching")
360 | .build();
361 |
362 | Item patched = CLIENT.patchItem(VAULT_ID, createdItemId,
363 | Patch.add()
364 | .withValue(newField)
365 | .withPath("/fields").build(),
366 | Patch.replace()
367 | .withValue(updatedUsername)
368 | .withPath("/fields/" + usernameFieldId).build())
369 | .join();
370 |
371 | assertAll(
372 | () -> assertEquals("Integration Test Created Login", patched.getTitle()),
373 | () -> assertEquals(Purpose.USERNAME, patched.getFields().get(0).getPurpose()),
374 | () -> assertEquals("patchTwo", patched.getFields().get(0).getValue()),
375 | () -> assertEquals(created.getFields().size() + 1, patched.getFields().size()));
376 | }
377 |
378 | @Test
379 | @Order(5)
380 | void shouldReplaceItem() throws Exception {
381 | if (createdItemId == null) fail("The createItem test needs to run before replaceItem");
382 |
383 | Thread.sleep(400L);
384 |
385 | Item replacement = Item.login().withTitle("Replaced Integration Test Created Login")
386 | .withId(createdItemId)
387 | .withVaultId(VAULT_ID)
388 | .withField(Field.username("replacementuser").build())
389 | .withField(Field.generatedPassword(GeneratorRecipe.letters().ofLength(30)).build())
390 | .withUrl(URL.primary("https://www.test.com"))
391 | .build();
392 |
393 | Item replaced = CLIENT.replaceItem(VAULT_ID, createdItemId, replacement).join();
394 |
395 | assertAll("Replaced Item is as expected",
396 | () -> assertEquals("Replaced Integration Test Created Login", replaced.getTitle()),
397 | () -> assertEquals(createdItemId, replaced.getId()),
398 | () -> assertEquals(Category.LOGIN, replaced.getCategory()),
399 | () -> assertEquals(3, replaced.getFields().size()),
400 | () -> assertEquals(Purpose.USERNAME, replaced.getFields().get(0).getPurpose()),
401 | () -> assertEquals("replacementuser", replaced.getFields().get(0).getValue()),
402 | () -> assertEquals(1, replaced.getUrls().size()),
403 | () -> assertEquals("https://www.test.com", replaced.getUrls().get(0).getUrl())
404 | );
405 | }
406 |
407 | @Test
408 | @Order(6)
409 | void shouldDeleteItem() throws Exception {
410 | if (createdItemId == null) fail("The createItem test needs to run before deleteItem");
411 |
412 | // Deleting too soon after creation/update can fail
413 | Thread.sleep(400L);
414 |
415 | assertDoesNotThrow(() -> CLIENT.deleteItem(VAULT_ID, createdItemId).join());
416 | }
417 |
418 | @Test
419 | void shouldListApiActivity() {
420 | List requests = CLIENT.listAPIActivity().join();
421 |
422 | assertAll("Returned APIRequest list is reasonable",
423 | () -> assertNotNull(requests),
424 | () -> assertNotEquals(0, requests.size()),
425 | () -> assertEquals("HJGVEL46XVGGJFJQXYCADPF5RM", requests.get(0).getActor().getId()),
426 | () -> assertEquals("5R6XDPQ2B5GW3GLDTNKVH7BN6E", requests.get(0).getActor().getAccount()),
427 | () -> assertEquals(APIRequestResult.SUCCESS, requests.get(0).getResult()),
428 | () -> assertEquals(new Id(VAULT_ID, ""), requests.get(0).getResource().getVaultId()));
429 |
430 | // Limit to last 5
431 | List limitedRequests = CLIENT.listAPIActivity(5).join();
432 |
433 | assertAll("Returned limited APIRequest list is reasonable",
434 | () -> assertNotNull(limitedRequests),
435 | () -> assertEquals(5, limitedRequests.size()),
436 | () -> assertEquals("HJGVEL46XVGGJFJQXYCADPF5RM",
437 | limitedRequests.get(0).getActor().getId()),
438 | () -> assertEquals("5R6XDPQ2B5GW3GLDTNKVH7BN6E",
439 | limitedRequests.get(0).getActor().getAccount()));
440 |
441 | List limitedOffsetRequests = CLIENT.listAPIActivity(6, 2).join();
442 |
443 | assertAll("Returned limited APIRequest list is reasonable",
444 | () -> assertNotNull(limitedOffsetRequests),
445 | () -> assertEquals(6, limitedOffsetRequests.size()),
446 | () -> assertNotEquals(
447 | limitedRequests.get(0).getRequestId(),
448 | limitedOffsetRequests.get(0).getRequestId()),
449 | () -> assertEquals(
450 | limitedRequests.get(2).getRequestId(),
451 | limitedOffsetRequests.get(0).getRequestId()),
452 | () -> assertEquals(
453 | limitedRequests.get(3).getRequestId(),
454 | limitedOffsetRequests.get(1).getRequestId()));
455 | }
456 |
457 | @Test
458 | void shouldGetHealthStatus() {
459 | ConnectServer server = CLIENT.health().join();
460 |
461 | assertNotNull(server);
462 | assertEquals("1Password Connect API", server.getName());
463 | }
464 |
465 | @Test
466 | void shouldHeartbeat() {
467 | assertDoesNotThrow(() -> CLIENT.heartbeat().join());
468 | }
469 |
470 | @Test
471 | void shouldGetMetrics() {
472 | String metrics = CLIENT.metrics().join();
473 |
474 | assertNotNull(metrics);
475 | }
476 | }
477 |
--------------------------------------------------------------------------------
/src/test/java/com/sanctionco/opconnect/OPConnectClientBuilderTest.java:
--------------------------------------------------------------------------------
1 | package com.sanctionco.opconnect;
2 |
3 | import org.junit.jupiter.api.Test;
4 |
5 | import static org.junit.jupiter.api.Assertions.assertEquals;
6 | import static org.junit.jupiter.api.Assertions.assertNotEquals;
7 | import static org.junit.jupiter.api.Assertions.assertThrows;
8 | import static org.junit.jupiter.api.Assertions.assertTrue;
9 |
10 | class OPConnectClientBuilderTest {
11 |
12 | @Test
13 | void buildShouldThrowWithoutSettingEndpoint() {
14 | NullPointerException e = assertThrows(NullPointerException.class,
15 | () -> OPConnectClientBuilder.builder().build());
16 |
17 | assertTrue(e.getMessage().startsWith("You must provide an endpoint"));
18 | }
19 |
20 | @Test
21 | void buildShouldThrowWithoutSettingAccessToken() {
22 | NullPointerException e = assertThrows(NullPointerException.class,
23 | () -> OPConnectClientBuilder.builder().withEndpoint("test").build());
24 |
25 | assertTrue(e.getMessage().startsWith("You must provide an access token"));
26 | }
27 |
28 | @Test
29 | void shouldBuild() {
30 | OPConnectClientBuilder.builder()
31 | .withEndpoint("https://endpoint")
32 | .withAccessToken("token")
33 | .build();
34 | }
35 |
36 | @Test
37 | void shouldBuildWithTimeout() {
38 | OPConnectClientBuilder.builder()
39 | .withEndpoint("https://endpoint")
40 | .withAccessToken("token")
41 | .withTimeoutInMilliseconds(5000L)
42 | .build();
43 | }
44 |
45 | @Test
46 | void testEnsureTrailingSlashExistsNoChange() {
47 | String url = "https://www.sanctionco.com/";
48 | String result = OPConnectClientBuilder.ensureTrailingSlashExists(url);
49 |
50 | assertEquals(url, result);
51 | }
52 |
53 | @Test
54 | void testEnsureTrailingSlashExistsNoSlash() {
55 | String url = "https://www.sanctionco.com";
56 | String result = OPConnectClientBuilder.ensureTrailingSlashExists(url);
57 |
58 | assertNotEquals(url, result);
59 | assertEquals("https://www.sanctionco.com/", result);
60 | }
61 | }
62 |
--------------------------------------------------------------------------------
/src/test/java/com/sanctionco/opconnect/OPConnectVaultClientTest.java:
--------------------------------------------------------------------------------
1 | package com.sanctionco.opconnect;
2 |
3 | import com.sanctionco.opconnect.model.Filter;
4 | import com.sanctionco.opconnect.model.Item;
5 | import com.sanctionco.opconnect.model.Patch;
6 |
7 | import java.util.Collections;
8 |
9 | import org.junit.jupiter.api.Test;
10 |
11 | import static org.mockito.ArgumentMatchers.eq;
12 | import static org.mockito.ArgumentMatchers.same;
13 | import static org.mockito.Mockito.mock;
14 | import static org.mockito.Mockito.verify;
15 |
16 | class OPConnectVaultClientTest {
17 |
18 | @Test
19 | void vaultClientPassesCallsThrough() {
20 | final OPConnectClient client = mock(OPConnectClient.class);
21 | final Item item = Item.builder().build();
22 | final Patch patch = Patch.builder().build();
23 |
24 | OPConnectVaultClient vaultClient = new OPConnectVaultClient(client, "testId");
25 |
26 | vaultClient.getVault();
27 | verify(client).getVault(eq("testId"));
28 |
29 | vaultClient.listItems();
30 | verify(client).listItems(eq("testId"));
31 |
32 | vaultClient.listItems("filter");
33 | verify(client).listItems(eq("testId"), eq("filter"));
34 |
35 | vaultClient.listItems(Filter.title().present());
36 | verify(client).listItems(eq("testId"), eq("title pr"));
37 |
38 | vaultClient.getItem("testItemId");
39 | verify(client).getItem(eq("testId"), eq("testItemId"));
40 |
41 | vaultClient.createItem(item);
42 | verify(client).createItem(eq("testId"), same(item));
43 |
44 | vaultClient.replaceItem("itemId", item);
45 | verify(client).replaceItem(eq("testId"), eq("itemId"), same(item));
46 |
47 | vaultClient.patchItem("itemId", Collections.singletonList(patch));
48 | verify(client)
49 | .patchItem(eq("testId"), eq("itemId"), eq(Collections.singletonList(patch)));
50 |
51 | vaultClient.patchItem("itemId", patch);
52 | verify(client).patchItem(eq("testId"), eq("itemId"), same(patch));
53 |
54 | vaultClient.deleteItem("itemId");
55 | verify(client).deleteItem(eq("testId"), eq("itemId"));
56 |
57 | vaultClient.listFiles("itemId");
58 | verify(client).listFiles(eq("testId"), eq("itemId"));
59 |
60 | vaultClient.listFiles("itemId", true);
61 | verify(client).listFiles(eq("testId"), eq("itemId"), eq(true));
62 |
63 | vaultClient.getFile("itemId", "fileId");
64 | verify(client).getFile(eq("testId"), eq("itemId"), eq("fileId"));
65 |
66 | vaultClient.getFile("itemId", "fileId", true);
67 | verify(client).getFile(eq("testId"), eq("itemId"), eq("fileId"), eq(true));
68 |
69 | vaultClient.getFileContent("itemId", "fileId");
70 | verify(client).getFileContent(eq("testId"), eq("itemId"), eq("fileId"));
71 | }
72 | }
73 |
--------------------------------------------------------------------------------
/src/test/java/com/sanctionco/opconnect/model/CharacterSetTest.java:
--------------------------------------------------------------------------------
1 | package com.sanctionco.opconnect.model;
2 |
3 | import java.util.Arrays;
4 | import java.util.Collections;
5 | import java.util.List;
6 | import java.util.stream.Stream;
7 |
8 | import org.junit.jupiter.params.ParameterizedTest;
9 | import org.junit.jupiter.params.provider.Arguments;
10 | import org.junit.jupiter.params.provider.MethodSource;
11 |
12 | import static org.junit.jupiter.api.Assertions.assertEquals;
13 | import static org.junit.jupiter.api.Assertions.assertTrue;
14 |
15 | class CharacterSetTest {
16 |
17 | @ParameterizedTest(name = "{index} List of {1}")
18 | @MethodSource("provider")
19 | void listsShouldBeCorrect(List created, List expected) {
20 | assertEquals(expected.size(), created.size());
21 |
22 | expected.forEach(set -> assertTrue(created.contains(set)));
23 | }
24 |
25 | @SuppressWarnings("unused")
26 | private static Stream provider() {
27 | return Stream.of(
28 | Arguments.of(CharacterSet.letters(), Collections.singletonList(CharacterSet.LETTERS)),
29 | Arguments.of(CharacterSet.digits(), Collections.singletonList(CharacterSet.DIGITS)),
30 | Arguments.of(CharacterSet.symbols(), Collections.singletonList(CharacterSet.SYMBOLS)),
31 | Arguments.of(
32 | CharacterSet.lettersAndDigits(),
33 | Arrays.asList(CharacterSet.LETTERS, CharacterSet.DIGITS)),
34 | Arguments.of(
35 | CharacterSet.lettersAndSymbols(),
36 | Arrays.asList(CharacterSet.LETTERS, CharacterSet.SYMBOLS)),
37 | Arguments.of(
38 | CharacterSet.digitsAndSymbols(),
39 | Arrays.asList(CharacterSet.DIGITS, CharacterSet.SYMBOLS)),
40 | Arguments.of(
41 | CharacterSet.allCharacters(),
42 | Arrays.asList(CharacterSet.LETTERS, CharacterSet.DIGITS, CharacterSet.SYMBOLS)));
43 | }
44 | }
45 |
--------------------------------------------------------------------------------
/src/test/java/com/sanctionco/opconnect/model/FieldTest.java:
--------------------------------------------------------------------------------
1 | package com.sanctionco.opconnect.model;
2 |
3 | import org.junit.jupiter.api.Test;
4 |
5 | import static org.junit.jupiter.api.Assertions.assertAll;
6 | import static org.junit.jupiter.api.Assertions.assertEquals;
7 | import static org.junit.jupiter.api.Assertions.assertTrue;
8 |
9 | class FieldTest {
10 |
11 | @Test
12 | void shouldBuildUsername() {
13 | Field field = Field.username("testname").withLabel("username").build();
14 |
15 | assertAll("Field properties are correct",
16 | () -> assertEquals(Purpose.USERNAME, field.getPurpose()),
17 | () -> assertEquals("testname", field.getValue()),
18 | () -> assertEquals("username", field.getLabel()));
19 | }
20 |
21 | @Test
22 | void shouldBuildPassword() {
23 | Field field = Field.password("pass").withLabel("password").build();
24 |
25 | assertAll("Field properties are correct",
26 | () -> assertEquals(Purpose.PASSWORD, field.getPurpose()),
27 | () -> assertEquals("pass", field.getValue()),
28 | () -> assertEquals("password", field.getLabel()));
29 | }
30 |
31 | @Test
32 | void shouldBuildGeneratedPassword() {
33 | Field field = Field.generatedPassword().withLabel("password").build();
34 |
35 | assertAll("Field properties are correct",
36 | () -> assertEquals(Purpose.PASSWORD, field.getPurpose()),
37 | () -> assertTrue(field.getGenerate()),
38 | () -> assertEquals("password", field.getLabel()));
39 | }
40 |
41 | @Test
42 | void shouldBuildGeneratedPasswordWithRecipe() {
43 | Field field = Field.generatedPassword(GeneratorRecipe.letters().ofLength(30))
44 | .withLabel("password")
45 | .build();
46 |
47 | assertAll("Field properties are correct",
48 | () -> assertEquals(Purpose.PASSWORD, field.getPurpose()),
49 | () -> assertTrue(field.getGenerate()),
50 | () -> assertEquals(GeneratorRecipe.letters().ofLength(30), field.getRecipe()),
51 | () -> assertEquals("password", field.getLabel()));
52 | }
53 |
54 | @Test
55 | void shouldBuildNote() {
56 | Field field = Field.note("My Note Contents").withLabel("note").build();
57 |
58 | assertAll("Field properties are correct",
59 | () -> assertEquals(Purpose.NOTES, field.getPurpose()),
60 | () -> assertEquals("My Note Contents", field.getValue()),
61 | () -> assertEquals("note", field.getLabel()));
62 | }
63 | }
64 |
--------------------------------------------------------------------------------
/src/test/java/com/sanctionco/opconnect/model/FilterTest.java:
--------------------------------------------------------------------------------
1 | package com.sanctionco.opconnect.model;
2 |
3 | import org.junit.jupiter.api.Test;
4 |
5 | import static org.junit.jupiter.api.Assertions.assertAll;
6 | import static org.junit.jupiter.api.Assertions.assertEquals;
7 | import static org.junit.jupiter.api.Assertions.assertNotEquals;
8 |
9 | class FilterTest {
10 |
11 | @Test
12 | void shouldBuildContainsFilter() {
13 | Filter filter = Filter.title().contains("test");
14 |
15 | assertEquals("title co \"test\"", filter.getFilter());
16 | }
17 |
18 | @Test
19 | void shouldBuildEqualsFilter() {
20 | Filter filter = Filter.title().equals("test");
21 |
22 | assertEquals("title eq \"test\"", filter.getFilter());
23 | }
24 |
25 | @Test
26 | void shouldBuildStartsWithFilter() {
27 | Filter filter = Filter.title().startsWith("test");
28 |
29 | assertEquals("title sw \"test\"", filter.getFilter());
30 | }
31 |
32 | @Test
33 | void shouldBuildPresentFilter() {
34 | Filter filter = Filter.title().present();
35 |
36 | assertEquals("title pr", filter.getFilter());
37 | }
38 |
39 | @Test
40 | void shouldBuildGreaterThanFilter() {
41 | Filter filter = Filter.title().greaterThan("a");
42 |
43 | assertEquals("title gt \"a\"", filter.getFilter());
44 | }
45 |
46 | @Test
47 | void shouldBuildGreaterThanOrEqualFilter() {
48 | Filter filter = Filter.title().greaterThanOrEqual("a");
49 |
50 | assertEquals("title ge \"a\"", filter.getFilter());
51 | }
52 |
53 | @Test
54 | void shouldBuildLessThanFilter() {
55 | Filter filter = Filter.title().lessThan("a");
56 |
57 | assertEquals("title lt \"a\"", filter.getFilter());
58 | }
59 |
60 | @Test
61 | void shouldBuildLessThanOrEqualFilter() {
62 | Filter filter = Filter.title().lessThanOrEqual("a");
63 |
64 | assertEquals("title le \"a\"", filter.getFilter());
65 | }
66 |
67 | @Test
68 | void shouldBuildFilterWithAnd() {
69 | Filter filter = Filter.title().contains("test")
70 | .and(Filter.title().equals("other"));
71 |
72 | assertEquals("(title co \"test\" and title eq \"other\")", filter.getFilter());
73 | }
74 |
75 | @Test
76 | void shouldBuildFilterWithOr() {
77 | Filter filter = Filter.title().contains("test")
78 | .or(Filter.title().equals("other"));
79 |
80 | assertEquals("(title co \"test\" or title eq \"other\")", filter.getFilter());
81 | }
82 |
83 | @Test
84 | void shouldBuildFilterWithAndOr() {
85 | Filter filter = Filter.title().contains("test")
86 | .and(Filter.title().equals("other")
87 | .or(Filter.title().startsWith("te")));
88 |
89 | assertEquals("(title co \"test\" and (title eq \"other\" or title sw \"te\"))",
90 | filter.getFilter());
91 | }
92 |
93 | @Test
94 | void shouldBuildNameFilter() {
95 | Filter filter = Filter.name().equals("test");
96 |
97 | assertEquals("name eq \"test\"", filter.getFilter());
98 | }
99 |
100 | @Test
101 | void shouldBuildAnyFilter() {
102 | Filter filter = Filter.onProperty("label").equals("test");
103 |
104 | assertEquals("label eq \"test\"", filter.getFilter());
105 | }
106 |
107 | @Test
108 | void hashCodeAndEqualsShouldWork() {
109 | Filter filter = Filter.title().equals("test");
110 | Filter sameFilter = Filter.title().equals("test");
111 | Filter diffOperation = Filter.title().contains("test");
112 | Filter diffValue = Filter.title().equals("diff");
113 |
114 | assertAll("Equals and hashcode works for same properties",
115 | () -> assertEquals(filter.hashCode(), sameFilter.hashCode()),
116 | () -> assertEquals(filter, sameFilter),
117 | () -> assertEquals(filter.toString(), sameFilter.toString()));
118 |
119 | assertAll("Equals and hashcode works for different operation property",
120 | () -> assertNotEquals(filter.hashCode(), diffOperation.hashCode()),
121 | () -> assertNotEquals(filter, diffOperation),
122 | () -> assertNotEquals(filter.toString(), diffOperation.toString()));
123 |
124 | assertAll("Equals and hashcode works for different value property",
125 | () -> assertNotEquals(filter.hashCode(), diffValue.hashCode()),
126 | () -> assertNotEquals(filter, diffValue),
127 | () -> assertNotEquals(filter.toString(), diffValue.toString()));
128 | }
129 | }
130 |
--------------------------------------------------------------------------------
/src/test/java/com/sanctionco/opconnect/model/GeneratorRecipeTest.java:
--------------------------------------------------------------------------------
1 | package com.sanctionco.opconnect.model;
2 |
3 | import java.util.List;
4 | import java.util.stream.Stream;
5 |
6 | import org.junit.jupiter.api.Test;
7 | import org.junit.jupiter.params.ParameterizedTest;
8 | import org.junit.jupiter.params.provider.Arguments;
9 | import org.junit.jupiter.params.provider.MethodSource;
10 |
11 | import static org.junit.jupiter.api.Assertions.assertAll;
12 | import static org.junit.jupiter.api.Assertions.assertEquals;
13 | import static org.junit.jupiter.api.Assertions.assertNotEquals;
14 | import static org.junit.jupiter.api.Assertions.assertTrue;
15 |
16 | class GeneratorRecipeTest {
17 |
18 | @ParameterizedTest(name = "{index} Recipe of length 12 and characters {1}")
19 | @MethodSource("provider")
20 | void shouldBuild(GeneratorRecipe recipe, List expectedCharacters) {
21 | assertEquals(12, recipe.getLength());
22 | assertEquals(expectedCharacters.size(), recipe.getCharacterSets().size());
23 |
24 | expectedCharacters.forEach(set -> assertTrue(recipe.getCharacterSets().contains(set)));
25 | }
26 |
27 | @SuppressWarnings("unused")
28 | private static Stream provider() {
29 | return Stream.of(
30 | Arguments.of(GeneratorRecipe.letters().ofLength(12), CharacterSet.letters()),
31 | Arguments.of(GeneratorRecipe.digits().ofLength(12), CharacterSet.digits()),
32 | Arguments.of(GeneratorRecipe.symbols().ofLength(12), CharacterSet.symbols()),
33 | Arguments.of(
34 | GeneratorRecipe.lettersAndDigits().ofLength(12),
35 | CharacterSet.lettersAndDigits()),
36 | Arguments.of(
37 | GeneratorRecipe.lettersAndSymbols().ofLength(12),
38 | CharacterSet.lettersAndSymbols()),
39 | Arguments.of(
40 | GeneratorRecipe.digitsAndSymbols().ofLength(12),
41 | CharacterSet.digitsAndSymbols()),
42 | Arguments.of(
43 | GeneratorRecipe.allCharacters().ofLength(12),
44 | CharacterSet.allCharacters()),
45 | Arguments.of(
46 | GeneratorRecipe.withAllowedCharacters(CharacterSet.digitsAndSymbols()).ofLength(12),
47 | CharacterSet.digitsAndSymbols()));
48 | }
49 |
50 | @Test
51 | void hashCodeAndEqualsShouldWork() {
52 | GeneratorRecipe recipe = GeneratorRecipe.letters().ofLength(10);
53 | GeneratorRecipe sameRecipe = GeneratorRecipe.letters().ofLength(10);
54 | GeneratorRecipe diffLength = GeneratorRecipe.letters().ofLength(15);
55 | GeneratorRecipe diffCharacters = GeneratorRecipe.symbols().ofLength(10);
56 |
57 | assertAll("Equals and hashcode works for same properties",
58 | () -> assertEquals(recipe.hashCode(), sameRecipe.hashCode()),
59 | () -> assertEquals(recipe, sameRecipe),
60 | () -> assertEquals(recipe.toString(), sameRecipe.toString()));
61 |
62 | assertAll("Equals and hashcode works for different length property",
63 | () -> assertNotEquals(recipe.hashCode(), diffLength.hashCode()),
64 | () -> assertNotEquals(recipe, diffLength),
65 | () -> assertNotEquals(recipe.toString(), diffLength.toString()));
66 |
67 | assertAll("Equals and hashcode works for different characterSet property",
68 | () -> assertNotEquals(recipe.hashCode(), diffCharacters.hashCode()),
69 | () -> assertNotEquals(recipe, diffCharacters),
70 | () -> assertNotEquals(recipe.toString(), diffCharacters.toString()));
71 | }
72 | }
73 |
--------------------------------------------------------------------------------
/src/test/java/com/sanctionco/opconnect/model/URLTest.java:
--------------------------------------------------------------------------------
1 | package com.sanctionco.opconnect.model;
2 |
3 | import org.junit.jupiter.api.Test;
4 |
5 | import static org.junit.jupiter.api.Assertions.assertAll;
6 | import static org.junit.jupiter.api.Assertions.assertEquals;
7 | import static org.junit.jupiter.api.Assertions.assertFalse;
8 | import static org.junit.jupiter.api.Assertions.assertNotEquals;
9 | import static org.junit.jupiter.api.Assertions.assertTrue;
10 |
11 | class URLTest {
12 |
13 | @Test
14 | void shouldBuildPrimaryUrl() {
15 | URL url = URL.primary("https://www.test.com");
16 |
17 | assertTrue(url.getPrimary());
18 | assertEquals("https://www.test.com", url.getUrl());
19 | }
20 |
21 | @Test
22 | void shouldBuildNonPrimaryUrl() {
23 | URL url = URL.standard("https://www.test.com");
24 |
25 | assertFalse(url.getPrimary());
26 | assertEquals("https://www.test.com", url.getUrl());
27 | }
28 |
29 | @Test
30 | void hashCodeAndEqualsShouldWork() {
31 | URL url = URL.primary("https://www.test.com");
32 | URL sameUrl = URL.primary("https://www.test.com");
33 | URL diffStringUrl = URL.primary("https://www.diff.com");
34 | URL diffPrimaryUrl = URL.standard("https://www.test.com");
35 |
36 | assertAll("Equals and hashcode works for same properties",
37 | () -> assertEquals(url.hashCode(), sameUrl.hashCode()),
38 | () -> assertEquals(url, sameUrl),
39 | () -> assertEquals(url.toString(), sameUrl.toString()));
40 |
41 | assertAll("Equals and hashcode works for different url property",
42 | () -> assertNotEquals(url.hashCode(), diffStringUrl.hashCode()),
43 | () -> assertNotEquals(url, diffStringUrl),
44 | () -> assertNotEquals(url.toString(), diffStringUrl.toString()));
45 |
46 | assertAll("Equals and hashcode works for different primary property",
47 | () -> assertNotEquals(url.hashCode(), diffPrimaryUrl.hashCode()),
48 | () -> assertNotEquals(url, diffPrimaryUrl),
49 | () -> assertNotEquals(url.toString(), diffPrimaryUrl.toString()));
50 | }
51 | }
52 |
--------------------------------------------------------------------------------
/src/test/java/com/sanctionco/opconnect/model/apiactivity/ActorTest.java:
--------------------------------------------------------------------------------
1 | package com.sanctionco.opconnect.model.apiactivity;
2 |
3 | import com.fasterxml.jackson.databind.ObjectMapper;
4 |
5 | import org.junit.jupiter.api.Test;
6 |
7 | import static org.junit.jupiter.api.Assertions.assertEquals;
8 |
9 | class ActorTest {
10 | private static final ObjectMapper MAPPER = new ObjectMapper();
11 | private static final String JSON_PATH = "/fixtures/apirequest/actor.json";
12 |
13 | @Test
14 | void shouldDeserialize() throws Exception {
15 | Actor expected = new Actor("test-id", "test-account", "test-jti", "test-useragent", "test-ip");
16 | Actor actual = MAPPER.readValue(getClass().getResourceAsStream(JSON_PATH), Actor.class);
17 |
18 | assertEquals(expected, actual);
19 | }
20 | }
21 |
--------------------------------------------------------------------------------
/src/test/resources/fixtures/apirequest/actor.json:
--------------------------------------------------------------------------------
1 | {
2 | "id": "test-id",
3 | "account": "test-account",
4 | "jti": "test-jti",
5 | "userAgent": "test-useragent",
6 | "ip": "test-ip"
7 | }
8 |
--------------------------------------------------------------------------------