Create
cancel
Showing results for 
Search instead for 
Did you mean: 
Sign up Log in

Next challenges

Recent achievements

  • Global
  • Personal

Recognition

  • Give kudos
  • Received
  • Given

Leaderboard

  • Global

Trophy case

Kudos (beta program)

Kudos logo

You've been invited into the Kudos (beta program) private group. Chat with others in the program, or give feedback to Atlassian.

View group

It's not the same without you

Join the community to find out what other Atlassian users are discussing, debating and creating.

Atlassian Community Hero Image Collage

What is the algorithm used to create the "Tiny links"

Hi,

I've seen this question: Is there a way to get a Confluence page's tiny link programmatically? and I have one in a similar vein.

What is the algorithm used to create the tiny links?

I'm assuming it's some kind of base 64/62 encoder of some sort? If anyone knows where in the source to look for the code, a path would be greatly appreciated.

Steve

6 answers

1 accepted

Check out the source of com.atlassian.confluence.pages.TinyUrl...

Base64.encodeBase64(longToByteArray(id));

id is the pageId.

I used the following functions in PHP based on the Steve's code:

function id2tinylink($id)
{
    $bytes = pack("L", (int)$id);  // convert the long to bytes
    $base64string=base64_encode($bytes);
    $base64string_escaped=strtr($base64string,'+/','_-');
    return rtrim($base64string_escaped, "A=");
}

function tinylink2id($tinylink){
    $base64string_encoded = str_pad($tinylink, 8, "A", STR_PAD_RIGHT);
    $base64string = strtr($base64string_encoded, '_-', '+/');
    $bytes = base64_decode($base64string);
    return unpack("L",$bytes)[1];
}

If anyone would like to emulate this functionality in PHP for whatever reason:

function tinylinkid($id)
{
	$bytes = pack("L", $id);  // convert the long to bytes
	$bytes = rtrim($bytes);  // trim any null characters
	$bytestring = "";
	$len = strlen($bytes); 
	for($i = 0; $i < $len; $i++) {
		$bytestring = $bytestring . $bytes[$i]; // build the byte string
	}
	$base64string = base64_encode($bytestring); // base64 encode the byte string
	$base64string = rtrim($base64string, "="); // trim any base64 padding characters
	return $base64string;
}

Thanks for David for the pointer.

Steve

Could you describe a method of decoding?

Here a solution in JS. Please check if the browsers are compatible with btoa and atob (https://developer.mozilla.org/en-US/docs/Web/API/WindowOrWorkerGlobalScope/btoa).

// The long to byte array conversion is taken from this source:
// https://stackoverflow.com/questions/8482309/converting-javascript-integer-to-byte-array-and-back
function longToByteArray(long) {
var byteArray = [0, 0, 0, 0];
for ( var index = 0; index < byteArray.length; index ++ ) {
var byte = long & 0xff;
byteArray [ index ] = byte;
long = (long - byte) / 256 ;
}
return byteArray;
}

function pageIdToShortUrl(pageId) {
return btoa(longToByteArray(pageId)
.map(String.fromCharCode)
.map(function (s) { return s[0] })
.join(""))
.replace(/=/g,"");
}

function byteArrayToLong(byteArray) {
var value = 0;
for ( var i = byteArray.length - 1; i >= 0; i--) {
value = (value * 256) + byteArray[i];
}
return value;
};

function shortUrlToPageId(shortUrl) {
return byteArrayToLong(atob(shortUrl)
.split("")
.map(function (b) { return b.charCodeAt()}));
}

I recently ported this to python:

def page_id_to_tiny(page_id):
return base64.b64encode((page_id).to_bytes(4, byteorder='little')).decode().replace('/','-').replace('+','_').rstrip('A=')


def tiny_to_page_id(tiny):
return int.from_bytes(base64.b64decode(tiny.ljust(8,'A').replace('_','+').replace('-','/').encode()),byteorder='little')

Updated as per feedback below from @Sebastian Schmachtel and @Fabian Sturm that noticed that Atlassian do not actually implement url safe encoding from rfc4648 correctly.

This would have been a perfect answer but I think Atlassian screwed up and + is replaced by _ and / by - instead of the other way round as it is defined for the url safe encoding rfc4648.

Like sovlabs_sam likes this

I used this functions and started to see weird effects. So I returned here et voila a hint just in time :-)

My (working) code looks now like this

def page_id_to_tiny(page_ids: List[int]) -> List[str]:
"""converts a list of pageids (int) to a list of last part of shortlink (/x/$PART)"""
shortlinks: List[str] = []
for page_id in page_ids:
encoded = base64.b64encode(page_id.to_bytes(4, byteorder='little')).decode()
encoded_fixed = encoded.replace("/", "-").replace("+", "_").rstrip('A=')
shortlinks.append(encoded_fixed)
return shortlinks


def tiny_to_page_id(tiny_links: List[str]) -> List[int]:
"""converts a list of last part of shortlink (/x/$PART) to a list of pageids (int)"""
page_ids: List[int] = []
for tiny_link in tiny_links:
tiny_link = tiny_link.replace("-", "/").replace("_", "+")
page_ids.append(int.from_bytes(base64.b64decode(tiny_link.ljust(8, 'A').encode()), byteorder='little'))
return page_ids
Like sovlabs_sam likes this

Suggest an answer

Log in or Sign up to answer
TAGS
Community showcase
Posted in Confluence

What do you think is the most *delightful* Confluence feature? Comment for a prize!

- Create your own custom emoji 🔥 - "Shake for Feedback" on mobile 📱 - An endless supply of GIFs via GIPHY 🤩 Is there anything quite as nice as a pleasant surprise? Comment below with what...

383 views 23 8
Join discussion

Community Events

Connect with like-minded Atlassian users at free events near you!

Find an event

Connect with like-minded Atlassian users at free events near you!

Unfortunately there are no Community Events near you at the moment.

Host an event

You're one step closer to meeting fellow Atlassian users at your local event. Learn more about Community Events

Events near you