Giter VIP home page Giter VIP logo

hashids-java's People

Contributors

0x3333 avatar christoribeiro avatar dakshsrivastava avatar dependabot[bot] avatar fanweixiao avatar jitpack-io avatar kenumir avatar milosonator avatar mlichtsinn avatar nusco avatar shannonchou avatar sharebear avatar srstsavage avatar theconstructor avatar tyf0x avatar waffle-iron avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

hashids-java's Issues

ArrayIndexOutOfBoundsException

From issue Issue 43 - kmandeville:

I have found two other occurrences where I get ArrayIndexOutOfBoundsException from deep in the HashIds code.
Hashids hashids = new Hashids("this is my salt"); long[] numbers = hashids.decode("[]");

and

Hashids hashids = new Hashids("this is my salt"); long[] numbers = hashids.decode("()");

Like the original submitter above, these aren't valid hashes, but I'm running into these errors in my web app because someone COULD put these characters in as an ID in a URL accidentally or on purpose. My app is just passing in these characters directly into HashIds. I would expect something other than ArrayIndexOutOfBoundsExceptions.

diffrent results in python and java with same alphabet and salt

Python(2.7 hashids version=1.0.2):

from hashids import Hashids
hashids = Hashids(salt='this is my salt',alphabet='0123456789abcdefghijklmnopqrstuvwx')
print hashids.encode(654321) # print gr9gdg

java (hashids version=1.0.2):

Hashids hashids = new Hashids("this is my salt", 0, "0123456789abcdefghijklmnopqrstuvwx");
System.out.println(hashids.encode(654321)); # print wwp5p6

if alphabet='0123456789abcdefghijklmnopqrstuvwxyz', the result is nice.

It's a bug?

Should we throw an exception for negative numbers as well?

When encoding a number the library throw an exception if the number is loo long (greater than MAX_NUMBER) but return an empty string for negative numbers. IMHO this is a little unexpected, using two different behaviours for the same thing, input validation.

Since negative numbers are also illegal arguments, shouldn't it throw a IllegalArgumentException?

Question about the output

Sorry for maybe naive question but....
Assuming that my alphabet is complete i.e. contains all characters and digits.
I wonder if there is a possibility that encode method would return a hash which contains only digits?
Other words is there a string which can be encoded and the result contains only digits?
Is it guaranteed that at leat one letter is present in the output?

Please add Automatic-Module-Name

Hi,

Hashids can be use in modularized project with the unstable jar name.

Can you add the following into the pom.xml file :

	<build>
		<plugins>
			<plugin>
				<groupId>org.apache.maven.plugins</groupId>
				<artifactId>maven-jar-plugin</artifactId>
				<configuration>
					<archive>
						<manifestEntries>
							<Automatic-Module-Name>org.hashids</Automatic-Module-Name>
						</manifestEntries>
					</archive>
				</configuration>
			</plugin>		
		</plugins>
	</build>
	

So that it will be exported as a constant 'org.hashids' module name ?

Thanks a lot.

StringIndexOutOfBoundsException when decoding a guard and minHashLength >= 3

I got this exception when trying to decode some bad data. This test case illustrates the exception.

public class TestClass
{
    @Test
    public void test()
    {
        Hashids hasher = new Hashids("this is my salt", 3);
        long[] numbers = hasher.decode("A");
    }
}

And it throws this exception.

java.lang.StringIndexOutOfBoundsException: String index out of range: 2
	at java.lang.String.charAt(String.java:658)
	at org.hashids.Hashids._encode(Hashids.java:292)
	at org.hashids.Hashids._decode(Hashids.java:350)
	at org.hashids.Hashids.decode(Hashids.java:194)
	at TestClass.test(TestClass.java:15)

Looks like any character that is in HashIds.guards will throw this exception.
Other input like "asdf" or any other character not in HashIds.guards seem to work ok.

Debugging, I noticed that on the call to _encode, usually an array with 0L is passed, but when one of those chars is used, the call is made with an empty array.

Specifying custom hash alphabet

I have extracted the below extract from your main page

Here we set the alphabet to consist of only four letters: "0123456789abcdef"
Hashids hashids = new Hashids("this is my salt", 0, "0123456789abcdef"); String hash = hashids.encode(1234567L);

hash is now going to be:
b332db5

the alphabet consists of 6 letters! a,b,c,d,e,f

Confusion about supported integer range

The doc says:

decodable hashes from unsigned (long) integers

but then it says

All (long) integers need to be greater than or equal to zero

And the implementation caps the max number to 2^53 (0-9,007,199,254,740,992)

https://github.com/10cella/hashids-java/blob/162a263c8007652472bf1821a26d33190730f8a5/src/main/java/org/hashids/Hashids.java#L24


  • IF unsigned 64-bit integer was support, it would accept: 2^64 or 0 - 18,446,744,073,709,551,616 (1.8x10^19)
  • IF signed 64-bit integer was support from zero up, it would accept: 2^63 or 0 - 9,223,372,036,854,775,807 (9.2x10^18)

You currently support 53 bit long integers - I can only assume that is a bug? Java's primitives are always signed, so you have about 2^63 values in the plus and minus range. The most logical range would be 2^63 if you only want to support from 0 up and not make the caller convert to unsigned longs?

Remove unnecessary dependencies

The Log4j dependency in pom.xml is not really necessary for this project since no Logger is ever used in the code and it ends up adding "mail-1.4.jar" and "activation-1.1.jar" both also unnecessary.

In any case if a logging dependency is necessary, it would be better to use SLF4J, so this library can be used in projects with Logback or any other logging implementation.

Thanks.

Hashids doesn't respect alphabet

Try this (it takes a while):

final String ALPHABET = "ABCDEFGHIJKLMNOPQRSTUVWXYZ";
final String SALT = "Encode all the things";
final Hashids hashids = new Hashids(SALT, 0, ALPHABET);

final Set<Character> codesCharacters = new HashSet<>();
for (int i = 0; i <= 10_000_000; i += 1) {
  String code = hashids.encode(i);
  for (char c : code.toCharArray()) {
    codesCharacters.add(c);
  }
}
final LinkedList<Character> list = new LinkedList<>(codesCharacters);
Collections.sort(list);
System.out.println(list);

Output:

[A, B, D, E, J, K, L, M, N, P, Q, R, V, W, X, Y, Z]

Why do 9 characters out of 26 never appear? That looks like a bug.

It might also be a side effect of the algorithm, and these characters might finally appear when you encode extremely large numbers. But doesn't that behavior result in hashes that are generally longer than they could be? I would expect that the algorithm tries to make good use of the entire alphabet.

For the record, this is not a nice-to-have for us - it's a necessity. We'd like to use Hashids to generate user account codes for a system with potentially hundreds of thousands of users. Users will punch these codes into kiosks, read them to operator, etc. So the candidate alphabet has to be small (no confusing letters like "1", "l", "0" and "O", no lowercase letters which make it harder to spell the code...), and at the same time we need to keep codes short to make the system more user-friendly.

Human Readable UUID

Hashids hashids = new Hashids("this is my salt"); String id = hashids.encodeHex("586e8cc62663421eadf9d4efa2bd19f4");

This gives yNZEZnb9oDTmEvJpLDqxhw9MQeZ. Can it be shorter at all ?

Update documentation regarding "Encryption"

Hashids.java uses the term Encrypt and Decrypt when the website explicitly says this does not provide encryption. Can you update the documentation? It's easy enough to simply refer to it what it is actually doing Encode and Decode.

  /**
   * Encrypt numbers to string
   *
   * @param numbers
   *          the numbers to encrypt
   * @return the encrypt string
   */
  public String encode(long... numbers) {

base58 alphabet

Hi,

What do you think about adding a constant(public final static string BASE_58 = ...) with base58(https://en.wikipedia.org/wiki/Base58) alphabet right into Hashids class?

Base58 alphabet looks very well to be used in url paths because it excludes many confusions when letters are different but seem similar visually(0 (zero), O (capital o), I (capital i) and l (lower case L) )

If you like this idea, I can prepare small a PR. THanks

Thread Safety

Could you please document the javadoc if Hashids class is thread safe or not?

Thanks

ArrayIndexOutOfBoundsException from encode(long... numbers)

Problem:
If the list of longs passed to the method public String encode(long... numbers) contains a negative value, it may result in a java.lang.ArrayIndexOutOfBoundsException being thrown. Here is the offending code snippet (see added inline comments.

  private String _encode(long... numbers){
    int numberHashInt = 0;
    for(int i = 0; i < numbers.length; i++){
      numberHashInt += (numbers[i] % (i+100));  // If numbers contains a negative long value then numberHashInt could be negative
    }
    String alphabet = this.alphabet;
    char ret = alphabet.toCharArray()[numberHashInt % alphabet.length()]; // if numberHashInt is negative, an ArrayIndexOutOfBoundsException will be thrown

Possible Solutions:

  1. In the method public String encode(long... numbers) replace the following line

if (number > 9007199254740992L) {

with

if (number > 9007199254740992L || number < 0) {

  1. In the method private String _encode(long... numbers) use the absolute value of the long values in numbers when computing the hash:
int numberHashInt = 0;
for(int i = 0; i < numbers.length; i++){
  numberHashInt += (Math.abs(numbers[i]) % (i+100));
}

Not Able to use BigInteger

Hi Team,

I have Big Integer which I convert from Hexadecimal. As by default function only take the long but I want to pass the BigInteger.Can you provide me any solution with reference to BigInteger.

Non compatible output when alphabet has no O and no 0

Both this Java implementation and @newhoggy's hashids-scala output a wrong value while using the following alphabet: ABCDEFGHIJKLMNPQRSTUVWXYZ123456789. It's comprised of all capital case letters except O plus all digits except 0. Adding either O or 0 makes it work again. Something is wrong in your code when both are missing.

Here are my test results:

JavaScript (reference) implementation: hashids.js 1.0.2
var hashids = new Hashids("MyCamelCaseSalt", 10, "ABCDEFGHIJKLMNPQRSTUVWXYZ123456789");
console.log(hashids.encode(1145));

9Q7MJ3LVGW

Python implementation: hashids-python 1.1.0.egg-info (from pip repos)
import sys, getopt
from hashids import Hashids

hashids = Hashids(salt="MyCamelCaseSalt", min_length=10, alphabet="ABCDEFGHIJKLMNPQRSTUVWXYZ123456789")
print hashids.encode(1145)

9Q7MJ3LVGW

Java implementation: hashids-java 1.0.1 (from Maven Central)
import org.hashids.*;

public class Test {
    public static void main(String[] args) {
        Hashids hashids = new Hashids("MyCamelCaseSalt", 10, "ABCDEFGHIJKLMNPQRSTUVWXYZ123456789");
        System.out.println(hashids.encode(1145));
    }
}

9E85K9Q623

Scala implementation: hashids-scala 1.1.0-448df98 (from io.john-ky)
import org.hashids._

object Test extends App {
  val hashids = Hashids("MyCamelCaseSalt", 10, "ABCDEFGHIJKLMNPQRSTUVWXYZ123456789")
  println(hashids.encode(1145))
}

9E85K9Q623

Data lost when using decodeHex

In our project we wanted to identify if a given string was a valid
HashId. The first version of this utilised decodeHex and then tested
to see if the resulting string was empty or not. This validation did
not work for values under 16 thus leading me in the direction of this
strange behaviour of decodeHex.

Looking at the implementation the problem seems to be this call to substring https://github.com/sharebear/hashids-java/blob/master/src/main/java/org/hashids/Hashids.java#L209

As far as I can tell this has been this way since it was introduced in
43b258a what is it's intended usage?

PR with failing test incoming in case my description wasn't clear.

I'm happy to follow up with a docs-pr / impl. pr to change or document the behaviour as necessary.

Why hashids has MAX_NUMBER limitation

Hello,

I was looking into this great library for my project, but I quickly found undocumented limitation that this library doesn't support any number > 9007199254740992L.
Could you please explain the reasoning behind this limitation?

ids.encode(new Random().nextLong()

Exception in thread "main" java.lang.IllegalArgumentException: number can not be greater than 9007199254740992L
at org.hashids.Hashids.encode(Hashids.java:178)
at io.remotable.experiments.ids.IdsExperiment.main(IdsExperiment.java:21)

Relax MAX_NUMBER restriction

I understand the desire to be completely compatible with the Javascript implementation/limitiations, as explained in #47 and in the docs, but is it possible to provide a toggle that disables this functionality?

This would ensure backward compatibility with Javascript's limitations, but would allow this library to make use of the full potential that the Java platform provides.

Other implementations (such as Scala and .Net) don't impose these restrictions and allow the library to be used with the native implementation of the number.

Performance Issues

I ran a quick stress test on this library and I'm seeing very poor and unpredictable performance. Generating 1,000,000 ids from the same Hashids instance (same salt) takes anywhere between 15 and 90 seconds on a 2.9GHz i7 CPU using 1.8 GB of RAM. There's also a strange stall somewhere between 30k and 60k in the test loop, after which the rest of the test runs quickly.

Here's my test case:

    // generates a random 32 character string
    Hashids h = new Hashids(RandomStringUtils.random(32));
    long start = System.currentTimeMillis();
    for (int i = 0; i < 1000000; i++) {
      h.encode(i);
    }
    long end = System.currentTimeMillis();
    long duration = end - start;
    System.out.println("time taken: " + duration/1000 + " seconds");
    System.out.println("hashes per second: " + 1000000/(duration/1000.0));

Same hash output for different input

Hi,

I have a problem with my code generating the same hash for two separate inputs.

Heres my code:

Hashids bookingHashIds = new Hashids("Booking Salt", 8);
System.out.println(bookingHashIds.encode(8250));
System.out.println(bookingHashIds.encode(8294));

Output is:

RqkpK7mW
Rqkpk7mW

This doesn't seem quite right?

Thread safe?

Is using once created new Hashids("this is my salt") (probably, as a static variable) is thread safe? or do we've to synchronize it manually?

Thanks.

V2 Proposal

Version 2.0 Proposal

This issue will be a discussion point to exchange ideas about version 2.0.

Big picture

The community is urging for a more java idiom version, and the current version can't handle these changes, that's why I'm proposing a new version, incorporating all the needs from the community in a broad discussion.

What about v2?

The new version must be compatible with original implementation as much as it can, without sacrificing java idiom. We will discuss how it will be implemented and the design considerations will be made here.

@cazacugmihai Proposal

  • Use of char arrays and StringBuilder instead of Strings
  • Precompute and cache recurrent operations
  • Helper class (CharUtils) for working with char arrays

@iggymoran Proposal

  • [] Relax MAX_NUMBER restriction

@KangoV Proposal

  • [] BigInteger as input/output

Reference implementation PR #53.

ArrayIndexOutOfBoundsException issues

Both:

Hashids hashids = new Hashids("this is my salt");
long[] numbers = hashids.decode("0");

and:

Hashids hashids = new Hashids("this is my salt");
long[] numbers = hashids.decode("test.txt");

are causing exceptions in various places.

I realize that they are not valid hashes, but the exception should either be declared or handled.

Hope this helps.

hash collision

Hi, I'm using hashids to encode internal ids in our system, however I noticed a few collisions:

Hashids hashids = new Hashids( salt, 8, "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ1234567890" );
System.out.println(hashids.encode( 5551008 ));
System.out.println(hashids.encode( 5552196 ));

Returns:

mnbgLzGm
mnbgLZGm

Any ideas as to how this can happen? From the documentation, it seems this should be impossible. We're using the latest version (1.0.3)

Create a new Release

@fanweixiao what do you think about creating a new release?

We have some bug fixes that would be nice to release.

I already asked Nexus for permission to release new artifacts.

Let me know if you agree, then I'll do it.

array index out of bound bug

if you call the encode(number) with a random large number.
then numberHashInt += (numbers[i] % (i+100)) has a chance to return a negative number, in my case -35.
the next calculation use alphabet.toCharArray()[numberHashInt % alphabet.length()] could thow an ArrayIndexOutOfBoundsException.

ArrayIndexOutOfBoundsException

Hashids hashids = new Hashids("this is my salt");
hashids.encrypt(75527867232l);

Above call giving ArrayIndexOutOfBoundsException. I think if the value is long, this exception is coming. For int values, working fine.

Add additonal prefix/suffix for salt version

Since we are using a salt, it might be a good idea to have a version as part of the actual id.
That will allow us to change the salt later if we need to.
I'm not sure if this is out of scope for this library or maybe should be added as a best practice.
What do you guys think?

Cheers,
Itay

Removal of deprecated methods

Deprecated methods:

public String encrypt(long... numbers)
public long[] decrypt(String hash)
public String encryptHex(String hexa)
public String decryptHex(String hash)

have been deprecated since Sep 15, 2014, I think we should remove them in the next release.

@fanweixiao

different salt can give random number or crash

Hi,
When using different salt it should return empty array. But I recognized the behavior is quite unpredictable, there is a probability that it decodes to a wrong number instead or crashes with an ArrayIndexOutOfBoundsException.

Here and example that will decode to a wrong number:

    @Test
    public void encodeAndDecodeTokenWithWrongKey() {
        Hashids a = new Hashids("supersecret",4);
        Hashids b = new Hashids("differentsupersecret",4);

        long sampleId = 123l;
        String token = a.encode(sampleId);

        long[] ids = b.decode(token); // []long id = { 81143 }
        assertEquals(0, ids.length);
    }

assertion will fail, id[0] will be 81143

Same test with sampleId = 37l will cause "ArrayIndexOutOfBoundsException"

Failing for very large numbers?

When running some random data through Hashids I found this failure:

@Test
public void test_issue11() throws Exception
{
    final Hashids hashIds = new Hashids("Fd2s3lDF1l39PDybtiZI", 5);
    final long id = 3945448269169105809L;
    assertThat(id, equalTo(hashIds.decrypt(hashIds.encrypt(id))[0]));
}

java.lang.AssertionError:
Expected: 3945448269169105408L
but: was 3945448269169105809L

Disable encoding after decoding.

The very end of _decode performs a this.encode and compares it with the original.

  • Can you make it configurable if someone wants this type of redundancy check (via some constructor flag) or just altogether remove it. I haven't measured performance but this seems like it will affect performance.

  • It also seems arbitrary to encode at the end of _decode to perform the check. You could have arbitrarily decoded at the end of _encode, but if you did it would become recursive...

  • Returning a simple long[0] does not help much as it is silent and preferably to make it explicit with an exception.

Talking out loud here, but perhaps the right solution is to allow the developer to perform the encode/decode checking in their own code if they desire that level of verification and allow the library to optimize its performance?.

Wrong salt doesn't work as advertised in documentation

scala> val hashids = new Hashids("this is my pepper")
hashids: fm.jiecao.lib.Hashids = fm.jiecao.lib.Hashids@490a94ee

scala> val numbers = hashids.decrypt("NkK9")
warning: there were 1 deprecation warning(s); re-run with -deprecation for details
numbers: Array[Long] = Array(25264)

Documentation says it should be [], which is Array() but Array(25264) was the result.

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    ๐Ÿ–– Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. ๐Ÿ“Š๐Ÿ“ˆ๐ŸŽ‰

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google โค๏ธ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.