Skip to content

Commit 1a08268

Browse files
Remove (curse word) separator incompatibility
The curse word protection of the original algorithm implementation does not allow to modify the separators. This API provided methods to customize those causing invalid and inconsistent hash- and numbers values. GH-9
1 parent 8e21e96 commit 1a08268

File tree

2 files changed

+18
-82
lines changed

2 files changed

+18
-82
lines changed

src/main/java/com/arcticicestudio/icecore/hashids/Hashids.java

Lines changed: 18 additions & 59 deletions
Original file line numberDiff line numberDiff line change
@@ -16,8 +16,7 @@
1616
* Generated strings can have a {@code minHashLength}.
1717
* </p>
1818
* <p>
19-
* If used to obfuscates identities, make sure to not expose your {@code salt}, {@code alphabet} nor
20-
* {@code separators} to a client, client-side is not safe.
19+
* If used to obfuscate identities make sure to not expose your {@code salt} or {@code alphabet}.
2120
* </p>
2221
* <p>
2322
* Only positive numbers are supported.
@@ -51,12 +50,12 @@ public final class Hashids {
5150
public static final String DEFAULT_ALPHABET = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ1234567890";
5251

5352
/**
54-
* Holds the default separators.
53+
* The default separators.
5554
* <p>
5655
* Used to prevent the generation of strings that contain bad, offensive and rude words.
5756
* </p>
5857
*/
59-
public static final String DEFAULT_SEPARATORS = "cfhistuCFHISTU";
58+
private static final String DEFAULT_SEPARATORS = "cfhistuCFHISTU";
6059

6160
/**
6261
* Holds the maximum number value.
@@ -90,7 +89,6 @@ public final class Hashids {
9089
private final String guards;
9190
private final int minHashLength;
9291
private final String salt;
93-
private final String separators;
9492

9593
/**
9694
* Constructs a new instance with all default values.
@@ -99,20 +97,18 @@ public final class Hashids {
9997
* <li>no salt</li>
10098
* <li>no minimal hash length</li>
10199
* <li>{@link #DEFAULT_ALPHABET}</li>
102-
* <li>{@link #DEFAULT_SEPARATORS}</li>
103100
* </ul>
104101
*/
105102
public Hashids() {
106103
this("", 0);
107104
}
108105

109106
/**
110-
* Constructs a new instance with the specified salt and the default minimal hash length, alphabet and separators.
107+
* Constructs a new instance with the specified salt, the minimal hash length and default alphabet.
111108
* <p>
112109
* <ul>
113110
* <li>no minimal hash length</li>
114111
* <li>{@link #DEFAULT_ALPHABET}</li>
115-
* <li>{@link #DEFAULT_SEPARATORS}</li>
116112
* </ul>
117113
*
118114
* @param salt the salt value
@@ -122,12 +118,10 @@ public Hashids(String salt) {
122118
}
123119

124120
/**
125-
* Constructs a new instance with the specified salt and the minimal hash length and the default alphabet and
126-
* separators.
121+
* Constructs a new instance with the specified salt and hash length and the default alphabet.
127122
* <p>
128123
* <ul>
129124
* <li>{@link #DEFAULT_ALPHABET}</li>
130-
* <li>{@link #DEFAULT_SEPARATORS}</li>
131125
* </ul>
132126
*
133127
* @param salt the salt value
@@ -138,11 +132,10 @@ public Hashids(String salt, int minHashLength) {
138132
}
139133

140134
/**
141-
* Constructs a new instance with the specified salt and alphabet and the default minimal hash length and separators.
135+
* Constructs a new instance with the specified salt and alphabet and the minimal hash length.
142136
* <p>
143137
* <ul>
144138
* <li>no minimal hash length</li>
145-
* <li>{@link #DEFAULT_SEPARATORS}</li>
146139
* </ul>
147140
*
148141
* @param salt the salt value
@@ -153,29 +146,13 @@ public Hashids(String salt, String alphabet) {
153146
}
154147

155148
/**
156-
* Constructs a new instance with the specified salt, minimal hash length and alphabet and the default separators.
157-
* <p>
158-
* <ul>
159-
* <li>{@link #DEFAULT_SEPARATORS}</li>
160-
* </ul>
149+
* Constructs a new instance with the specified salt, minimal hash length and alphabet.
161150
*
162151
* @param salt the salt value
163152
* @param minHashLength the minimal length of the hash
164153
* @param alphabet the alphabet value
165154
*/
166155
public Hashids(String salt, int minHashLength, String alphabet) {
167-
this(salt, minHashLength, alphabet, DEFAULT_SEPARATORS);
168-
}
169-
170-
/**
171-
* Constructs a new instance with the specified salt, minimal hash length, alphabet and separators.
172-
*
173-
* @param salt the salt value
174-
* @param minHashLength the minimal length of the hash
175-
* @param alphabet the alphabet value
176-
* @param separators the chained separators
177-
*/
178-
public Hashids(String salt, int minHashLength, String alphabet, String separators) {
179156
if (alphabet == null) {
180157
throw new IllegalArgumentException("alphabet was null");
181158
}
@@ -203,11 +180,8 @@ public Hashids(String salt, int minHashLength, String alphabet, String separator
203180
throw new IllegalArgumentException("Alphabet cannot contains spaces");
204181
}
205182

206-
/*
207-
* Separators should contain only characters present in alphabet.
208-
* Alphabet should not contain separators.
209-
*/
210-
StringBuilder seps = new StringBuilder(separators == null ? "" : separators);
183+
// Alphabet should not contain separators.
184+
StringBuilder seps = new StringBuilder(DEFAULT_SEPARATORS);
211185
for (int sepIdx = 0; sepIdx < seps.length(); sepIdx++) {
212186
int alphaIdx = uniqueAlphabet.indexOf(String.valueOf(seps.charAt(sepIdx)));
213187
if (alphaIdx == -1) {
@@ -247,7 +221,6 @@ public Hashids(String salt, int minHashLength, String alphabet, String separator
247221
}
248222

249223
this.alphabet = uniqueAlphabet.toString();
250-
this.separators = seps.toString();
251224
}
252225

253226
/**
@@ -261,14 +234,12 @@ public Hashids(String salt, int minHashLength, String alphabet, String separator
261234
* <li>no salt</li>
262235
* <li>no minimum hash length</li>
263236
* <li>{@link #DEFAULT_ALPHABET}</li>
264-
* <li>{@link #DEFAULT_SEPARATORS}</li>
265237
* </ul>
266238
*/
267239
public static final class Builder {
268240

269241
private final String salt;
270242
private final String alphabet;
271-
private final String separators;
272243
private final int minHashLength;
273244

274245
/**
@@ -277,15 +248,13 @@ public static final class Builder {
277248
public Builder() {
278249
this.salt = "";
279250
this.alphabet = DEFAULT_ALPHABET;
280-
this.separators = DEFAULT_SEPARATORS;
281251
this.minHashLength = 0;
282252
}
283253

284-
private Builder(String salt, String alphabet, String separators, int minHashLength) {
254+
private Builder(String salt, int minHashLength, String alphabet) {
285255
this.salt = salt;
286-
this.alphabet = alphabet;
287-
this.separators = separators;
288256
this.minHashLength = minHashLength;
257+
this.alphabet = alphabet;
289258
}
290259

291260
/**
@@ -295,7 +264,7 @@ private Builder(String salt, String alphabet, String separators, int minHashLeng
295264
* @return The builder instance with the specified salt
296265
*/
297266
public Builder salt(String salt) {
298-
return new Builder(salt, alphabet, separators, minHashLength);
267+
return new Builder(salt, minHashLength, alphabet);
299268
}
300269

301270
/**
@@ -305,17 +274,7 @@ public Builder salt(String salt) {
305274
* @return The builder instance with the specified custom alphabet
306275
*/
307276
public Builder alphabet(String alphabet) {
308-
return new Builder(salt, alphabet, separators, minHashLength);
309-
}
310-
311-
/**
312-
* Sets the custom separators string.
313-
*
314-
* @param separators The string to use as custom alphabet
315-
* @return The builder instance with the specified custom separators
316-
*/
317-
public Builder separators(String separators) {
318-
return new Builder(salt, alphabet, separators, minHashLength);
277+
return new Builder(salt, minHashLength, alphabet);
319278
}
320279

321280
/**
@@ -325,7 +284,7 @@ public Builder separators(String separators) {
325284
* @return The builder instance with the minimum hash length
326285
*/
327286
public Builder minHashLength(int minHashLength) {
328-
return new Builder(salt, alphabet, separators, minHashLength);
287+
return new Builder(salt, minHashLength, alphabet);
329288
}
330289

331290
/**
@@ -334,7 +293,7 @@ public Builder minHashLength(int minHashLength) {
334293
* @return The {@link Hashids} instance
335294
*/
336295
public Hashids build() {
337-
return new Hashids(salt, minHashLength, alphabet, separators);
296+
return new Hashids(salt, minHashLength, alphabet);
338297
}
339298
}
340299

@@ -421,8 +380,8 @@ private String doEncode(long... numbers) {
421380

422381
if (idx + 1 < numbers.length) {
423382
num %= ((int) last.charAt(0) + idx);
424-
sepsIdx = (int) (num % separators.length());
425-
result.append(separators.charAt(sepsIdx));
383+
sepsIdx = (int) (num % DEFAULT_SEPARATORS.length());
384+
result.append(DEFAULT_SEPARATORS.charAt(sepsIdx));
426385
}
427386
}
428387

@@ -463,7 +422,7 @@ private long[] doDecode(String hash, String alphabet) {
463422
if (!hashBreakdown.isEmpty()) {
464423
final char lottery = hashBreakdown.charAt(0);
465424
hashBreakdown = hashBreakdown.substring(1);
466-
hashBreakdown = hashBreakdown.replaceAll("[" + separators + "]", " ");
425+
hashBreakdown = Pattern.compile("[" + DEFAULT_SEPARATORS + "]").matcher(hashBreakdown).replaceAll(" ");
467426
hashArray = hashBreakdown.split(" ");
468427

469428
String buffer;

src/test/java/com/arcticicestudio/icecore/hashids/HashidsTest.java

Lines changed: 0 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -64,28 +64,6 @@ public void oneNumberWithCustomMinimumHashLength() {
6464
assertEquals(decoded[0], number);
6565
}
6666

67-
@Test
68-
public void oneNumberWithoutSeparators() {
69-
Hashids hashids = new Hashids("salt", 0, Hashids.DEFAULT_ALPHABET, null);
70-
long number = 12_345L;
71-
String hash = hashids.encode(number);
72-
long[] decoded = hashids.decode(hash);
73-
74-
assertEquals(1, decoded.length);
75-
assertEquals(number, decoded[0]);
76-
}
77-
78-
@Test
79-
public void oneNumberWithCustomSeparators() {
80-
Hashids hashids = new Hashids("salt", 0, Hashids.DEFAULT_ALPHABET, "abcdefgABCDEFG1234567");
81-
long number = 12_345L;
82-
String hash = hashids.encode(number);
83-
long[] decoded = hashids.decode(hash);
84-
85-
assertEquals(1, decoded.length);
86-
assertEquals(number, decoded[0]);
87-
}
88-
8967
@Test
9068
public void oneNumberWithLargeCustomMinimumHashLength() {
9169
Hashids hashids = new Hashids("salt", 1000);
@@ -229,7 +207,6 @@ public void hashidsBuilder() {
229207
.salt("salt")
230208
.minHashLength(16)
231209
.alphabet(Hashids.DEFAULT_ALPHABET)
232-
.separators(Hashids.DEFAULT_SEPARATORS)
233210
.build();
234211
long number = 12_345L;
235212
long[] decoded = hashids.decode(hashids.encode(number));

0 commit comments

Comments
 (0)