Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
1 parent
8c644c5
commit 2e2158c
Showing
23 changed files
with
513 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,7 @@ | ||
To install: | ||
|
||
`$ python setup.py install` | ||
|
||
To configure, make sure to put ID_OBFUSCATOR_KEY in the settings. You can generate a key by running id_obfuscator.utils.generate_secret_key() | ||
|
||
Unlike a simple base conversion like Base58, id_obfuscator also uses an obfuscator key which ensures that adjacent ids are not simply off by one letter or number. Note that it is not secure and with enough ids with corresponding numbers, a hacker could figure out the correct ID. This is therefore recommended for lower security use. |
Empty file.
Empty file.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,57 @@ | ||
#!/usr/bin/env python | ||
## | ||
## Copyright 2009 Adriana Lukas & Alec Muffett | ||
## | ||
## Licensed under the Apache License, Version 2.0 (the "License"); you | ||
## may not use this file except in compliance with the License. You | ||
## may obtain a copy of the License at | ||
## | ||
## http://www.apache.org/licenses/LICENSE-2.0 | ||
## | ||
## Unless required by applicable law or agreed to in writing, software | ||
## distributed under the License is distributed on an "AS IS" BASIS, | ||
## WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or | ||
## implied. See the License for the specific language governing | ||
## permissions and limitations under the License. | ||
## | ||
|
||
"""docstring goes here""" # :-) | ||
|
||
# spec: http://www.flickr.com/groups/api/discuss/72157616713786392/ | ||
|
||
__b58chars = '123456789abcdefghijkmnopqrstuvwxyzABCDEFGHJKLMNPQRSTUVWXYZ' | ||
__b58base = len(__b58chars) # let's not bother hard-coding | ||
|
||
def b58encode(value): | ||
""" | ||
encode integer 'value' as a base58 string; returns string | ||
""" | ||
|
||
encoded = '' | ||
while value >= __b58base: | ||
div, mod = divmod(value, __b58base) | ||
encoded = __b58chars[mod] + encoded # add to left | ||
value = div | ||
encoded = __b58chars[value] + encoded # most significant remainder | ||
return encoded | ||
|
||
def b58decode(encoded): | ||
""" | ||
decodes base58 string 'encoded' to return integer | ||
""" | ||
|
||
value = 0 | ||
column_multiplier = 1; | ||
for c in encoded[::-1]: | ||
column = __b58chars.index(c) | ||
value += column * column_multiplier | ||
column_multiplier *= __b58base | ||
return value | ||
|
||
if __name__ == '__main__': | ||
x = b58encode(12345678) | ||
print x, '26gWw' | ||
print b58decode(x), 12345678 | ||
|
||
characters = __b58chars | ||
base = __b58base |
Empty file.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,39 @@ | ||
""" | ||
This file demonstrates writing tests using the unittest module. These will pass | ||
when you run "manage.py test". | ||
Replace this with more appropriate tests for your application. | ||
""" | ||
|
||
import sys | ||
from django.test import TestCase | ||
from utils import obfuscate, deobfuscate | ||
|
||
class SimpleTest(TestCase): | ||
|
||
def test_correctly_hashes(self): | ||
""" | ||
Tests that 1 + 1 always equals 2. | ||
""" | ||
seen_hashes = set() | ||
collisions = 0 | ||
max_num = 1000000 | ||
for k in range(0, max_num): | ||
o = obfuscate(k) | ||
d = deobfuscate(o) | ||
if d in seen_hashes: | ||
collisions += 1 | ||
seen_hashes.add(d) | ||
self.assertEquals(k, d, "Incorrect hash: %s -> %s -> %s " % (k, o, d)) | ||
self.assertEqual(collisions, 0, "There were %d collisions between 0 and %d" % (collisions, max_num)) | ||
|
||
for k in range(0, 4294967295, 1048576): | ||
o = obfuscate(k) | ||
d = deobfuscate(o) | ||
self.assertEquals(k, d, "Incorrect hash: %s -> %s -> %s " % (k, o, d)) | ||
|
||
def test_bad_inputs(self): | ||
self.assertRaises(ValueError, obfuscate, -1) | ||
self.assertRaises(ValueError, obfuscate, "noninteger") | ||
self.assertRaises(ValueError, deobfuscate, "!@#$%^") | ||
self.assertRaises(ValueError, deobfuscate, "Zd..4") |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,58 @@ | ||
from django.conf import settings | ||
import random, re | ||
from id_obfuscator import base58 | ||
|
||
def generate_secret_key(length=40): | ||
random.sample(base58.characters, length) | ||
|
||
def obfuscate(i, length=8, key=settings.ID_OBFUSCATOR_KEY): | ||
i = int(i) | ||
if i < 0: | ||
raise ValueError("Input must be a positive integer.") | ||
result = "" | ||
pos = i % len(key) | ||
combine_key = key[pos:] + key[:pos] | ||
asc = base58.b58encode(i) | ||
pos_asc = base58.b58encode(pos) | ||
if len(asc) < length: | ||
asc = ("0" * (length-len(asc))) + asc | ||
for cpos in range(0, len(asc)): | ||
a_lookup = base58.characters.find(asc[cpos]) | ||
k_lookup = base58.characters.find(combine_key[cpos]) | ||
k = a_lookup + k_lookup | ||
if k == -1: | ||
result += '0' | ||
continue | ||
k = (k + base58.base) % base58.base | ||
#print asc[cpos], "(%d) + " % a_lookup , combine_key[cpos], "(%d) =" % k_lookup, base58.characters[k], "(%d)" % k | ||
if k - k_lookup == -1 and asc[cpos] != "0": | ||
result += "." | ||
result += base58.characters[k] | ||
result = pos_asc + result | ||
return result | ||
|
||
VALID_HASH_FORMAT=r"^[0%(chars)s](\.?[0%(chars)s])+$" % {'chars': base58.characters} | ||
def deobfuscate(s, key=settings.ID_OBFUSCATOR_KEY): | ||
if not re.search(VALID_HASH_FORMAT, s): | ||
raise ValueError("Invalid hash value: %s" % s) | ||
pos = base58.b58decode(s[0]) | ||
combine_key = key[pos:] + key[:pos] | ||
#print "The combine key is %s" % combine_key | ||
s = s[1:] | ||
asc = "" | ||
for cpos in range(0, len(s.replace(".",""))): | ||
if s[cpos] == ".": | ||
treat_as_number = True | ||
s = s[:cpos] + s[cpos+1:] | ||
else: | ||
treat_as_number = False | ||
k = base58.characters.find(s[cpos]) | ||
k = k - base58.characters.find(combine_key[cpos]) | ||
if not treat_as_number and (k == -1 or s[cpos] == "0"): | ||
#print s[cpos], "(%d) - " % base58.characters.find(s[cpos]) , combine_key[cpos], "(%d) =" % base58.characters.find(combine_key[cpos]), base58.characters[k], "(%d)" % k | ||
continue | ||
k = (k + base58.base) % base58.base | ||
#print s[cpos], "(%d) - " % base58.characters.find(s[cpos]) , combine_key[cpos], "(%d) =" % base58.characters.find(combine_key[cpos]), base58.characters[k], "(%d)" % k | ||
asc += base58.characters[k] | ||
result = base58.b58decode(asc) | ||
return result |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1 @@ | ||
# Create your views here. |
Empty file.
Binary file not shown.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,57 @@ | ||
#!/usr/bin/env python | ||
## | ||
## Copyright 2009 Adriana Lukas & Alec Muffett | ||
## | ||
## Licensed under the Apache License, Version 2.0 (the "License"); you | ||
## may not use this file except in compliance with the License. You | ||
## may obtain a copy of the License at | ||
## | ||
## http://www.apache.org/licenses/LICENSE-2.0 | ||
## | ||
## Unless required by applicable law or agreed to in writing, software | ||
## distributed under the License is distributed on an "AS IS" BASIS, | ||
## WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or | ||
## implied. See the License for the specific language governing | ||
## permissions and limitations under the License. | ||
## | ||
|
||
"""docstring goes here""" # :-) | ||
|
||
# spec: http://www.flickr.com/groups/api/discuss/72157616713786392/ | ||
|
||
__b58chars = '123456789abcdefghijkmnopqrstuvwxyzABCDEFGHJKLMNPQRSTUVWXYZ' | ||
__b58base = len(__b58chars) # let's not bother hard-coding | ||
|
||
def b58encode(value): | ||
""" | ||
encode integer 'value' as a base58 string; returns string | ||
""" | ||
|
||
encoded = '' | ||
while value >= __b58base: | ||
div, mod = divmod(value, __b58base) | ||
encoded = __b58chars[mod] + encoded # add to left | ||
value = div | ||
encoded = __b58chars[value] + encoded # most significant remainder | ||
return encoded | ||
|
||
def b58decode(encoded): | ||
""" | ||
decodes base58 string 'encoded' to return integer | ||
""" | ||
|
||
value = 0 | ||
column_multiplier = 1; | ||
for c in encoded[::-1]: | ||
column = __b58chars.index(c) | ||
value += column * column_multiplier | ||
column_multiplier *= __b58base | ||
return value | ||
|
||
if __name__ == '__main__': | ||
x = b58encode(12345678) | ||
print x, '26gWw' | ||
print b58decode(x), 12345678 | ||
|
||
characters = __b58chars | ||
base = __b58base |
Binary file not shown.
Empty file.
Binary file not shown.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,39 @@ | ||
""" | ||
This file demonstrates writing tests using the unittest module. These will pass | ||
when you run "manage.py test". | ||
Replace this with more appropriate tests for your application. | ||
""" | ||
|
||
import sys | ||
from django.test import TestCase | ||
from utils import obfuscate, deobfuscate | ||
|
||
class SimpleTest(TestCase): | ||
|
||
def test_correctly_hashes(self): | ||
""" | ||
Tests that 1 + 1 always equals 2. | ||
""" | ||
seen_hashes = set() | ||
collisions = 0 | ||
max_num = 1000000 | ||
for k in range(0, max_num): | ||
o = obfuscate(k) | ||
d = deobfuscate(o) | ||
if d in seen_hashes: | ||
collisions += 1 | ||
seen_hashes.add(d) | ||
self.assertEquals(k, d, "Incorrect hash: %s -> %s -> %s " % (k, o, d)) | ||
self.assertEqual(collisions, 0, "There were %d collisions between 0 and %d" % (collisions, max_num)) | ||
|
||
for k in range(0, 4294967295, 1048576): | ||
o = obfuscate(k) | ||
d = deobfuscate(o) | ||
self.assertEquals(k, d, "Incorrect hash: %s -> %s -> %s " % (k, o, d)) | ||
|
||
def test_bad_inputs(self): | ||
self.assertRaises(ValueError, obfuscate, -1) | ||
self.assertRaises(ValueError, obfuscate, "noninteger") | ||
self.assertRaises(ValueError, deobfuscate, "!@#$%^") | ||
self.assertRaises(ValueError, deobfuscate, "Zd..4") |
Binary file not shown.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,58 @@ | ||
from django.conf import settings | ||
import random, re | ||
from id_obfuscator import base58 | ||
|
||
def generate_secret_key(length=40): | ||
random.sample(base58.characters, length) | ||
|
||
def obfuscate(i, length=8, key=settings.ID_OBFUSCATOR_KEY): | ||
i = int(i) | ||
if i < 0: | ||
raise ValueError("Input must be a positive integer.") | ||
result = "" | ||
pos = i % len(key) | ||
combine_key = key[pos:] + key[:pos] | ||
asc = base58.b58encode(i) | ||
pos_asc = base58.b58encode(pos) | ||
if len(asc) < length: | ||
asc = ("0" * (length-len(asc))) + asc | ||
for cpos in range(0, len(asc)): | ||
a_lookup = base58.characters.find(asc[cpos]) | ||
k_lookup = base58.characters.find(combine_key[cpos]) | ||
k = a_lookup + k_lookup | ||
if k == -1: | ||
result += '0' | ||
continue | ||
k = (k + base58.base) % base58.base | ||
#print asc[cpos], "(%d) + " % a_lookup , combine_key[cpos], "(%d) =" % k_lookup, base58.characters[k], "(%d)" % k | ||
if k - k_lookup == -1 and asc[cpos] != "0": | ||
result += "." | ||
result += base58.characters[k] | ||
result = pos_asc + result | ||
return result | ||
|
||
VALID_HASH_FORMAT=r"^[0%(chars)s](\.?[0%(chars)s])+$" % {'chars': base58.characters} | ||
def deobfuscate(s, key=settings.ID_OBFUSCATOR_KEY): | ||
if not re.search(VALID_HASH_FORMAT, s): | ||
raise ValueError("Invalid hash value: %s" % s) | ||
pos = base58.b58decode(s[0]) | ||
combine_key = key[pos:] + key[:pos] | ||
#print "The combine key is %s" % combine_key | ||
s = s[1:] | ||
asc = "" | ||
for cpos in range(0, len(s.replace(".",""))): | ||
if s[cpos] == ".": | ||
treat_as_number = True | ||
s = s[:cpos] + s[cpos+1:] | ||
else: | ||
treat_as_number = False | ||
k = base58.characters.find(s[cpos]) | ||
k = k - base58.characters.find(combine_key[cpos]) | ||
if not treat_as_number and (k == -1 or s[cpos] == "0"): | ||
#print s[cpos], "(%d) - " % base58.characters.find(s[cpos]) , combine_key[cpos], "(%d) =" % base58.characters.find(combine_key[cpos]), base58.characters[k], "(%d)" % k | ||
continue | ||
k = (k + base58.base) % base58.base | ||
#print s[cpos], "(%d) - " % base58.characters.find(s[cpos]) , combine_key[cpos], "(%d) =" % base58.characters.find(combine_key[cpos]), base58.characters[k], "(%d)" % k | ||
asc += base58.characters[k] | ||
result = base58.b58decode(asc) | ||
return result |
Binary file not shown.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1 @@ | ||
# Create your views here. |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,14 @@ | ||
#!/usr/bin/env python | ||
from django.core.management import execute_manager | ||
import imp | ||
try: | ||
imp.find_module('settings') # Assumed to be in the same directory. | ||
except ImportError: | ||
import sys | ||
sys.stderr.write("Error: Can't find the file 'settings.py' in the directory containing %r. It appears you've customized things.\nYou'll have to run django-admin.py, passing it your settings module.\n" % __file__) | ||
sys.exit(1) | ||
|
||
import settings | ||
|
||
if __name__ == "__main__": | ||
execute_manager(settings) |
Oops, something went wrong.