Çfarë është UUID?

UUID-të tani janë 128 bit në madhësi, dyfishi i asaj që ishin fillimisht. Formati i përgjithshëm i një UUID është se 16 bajtë e tij përfaqësohen si vlera 32 heksadecimal (Baza 16) të ndara në pesë grupe me gjatësi përkatësisht 8, 4, 4, 4 dhe 12 (gjithsej 32 karaktere), të ndara me viza "-", që e bën një UUID të vetme 36 karaktere të gjatë, 32 karaktere heksadecimal + 4 viza.

UUID-të ndahen në grupe të ndryshme sipas Variantit dhe Versioneve të tyre. Varianti i UUID përfaqësohet në vetë UUID nga një nga karakteret heksadecimal dhe e njëjta gjë vlen edhe për versionin e UUID. Më poshtë është formati i përgjithshëm ose përfaqësimi tekstual kanonik i një UUID.

xxxxxxxx-xxxx-Mxxx-Nxxx-xxxxxxxxxxxxx

Karakteri heksadecimal M përfaqëson versionin e UUID dhe 1 deri në 3 bitët e parë më të rëndësishëm, në formën binare, të karakterit N përfaqësojnë variantin e UUID.

Si ndryshon UUID5 nga versionet e tjera?

UUID5 krijohet duke hash së bashku një identifikues space name me një string hyrje.

  1. Vargu i hyrjes: Çdo varg që mund të ndryshojë në aplikacionin tuaj.
  2. Hapësira e emrave: Një UUID fikse e përdorur në kombinim me vargun hyrës për të bërë dallimin midis UUID-ve të krijuara në aplikacione të ndryshme dhe për të parandaluar "hakimet e tabelës së ylberit"

Këto dy pjesë të informacionit konvertohen në një UUID duke përdorur algoritmin e hashimit SHA1.

Një hash SHA1 nxjerr 160 bit (20 byte); rezultati i hash-it konvertohet në një UUID.

Me një përmbledhje 20-bajtë nga SHA1:

SHA1 Digest:   74738ff5 5367 e958 1aee 98fffdcd1876 94028007
UUID (v5):     74738ff5-5367-5958-9aee-98fffdcd1876
                             ⭡    ⬑first two bits set to 1 and 0, respectively
                             ╰─low nibble is set to 5, to indicate type 5

sha1(NamespaceUUID+String Input);

Një pikë e rëndësishme për t'u theksuar është se UUID v5 është konsistent. Kjo do të thotë që çdo kombinim i dhënë i hyrjes dhe hapësirës së emrit do të rezultojë në të njëjtin UUID, çdo herë. Mund ta provoni vetë:

// Reference from SHA1 and UUID npm module
// http://www.movable-type.co.uk/scripts/sha1.html
function sha1(bytes) {
    const K = [0x5a827999, 0x6ed9eba1, 0x8f1bbcdc, 0xca62c1d6];
    const H = [0x67452301, 0xefcdab89, 0x98badcfe, 0x10325476, 0xc3d2e1f0];
  
    if (typeof bytes === 'string') {
        const msg = unescape(encodeURIComponent(bytes)); // UTF8 escape
        bytes = [];
        for (let i = 0; i < msg.length; ++i) {
        bytes.push(msg.charCodeAt(i));
        }
    } else if (!Array.isArray(bytes)) {
        // Convert Array-like to Array
        bytes = Array.prototype.slice.call(bytes);
    }
  
    bytes.push(0x80);
    const l = bytes.length / 4 + 2;
    const N = Math.ceil(l / 16);
    const M = new Array(N);
  
    for (let i = 0; i < N; ++i) {
        const arr = new Uint32Array(16);
        for (let j = 0; j < 16; ++j) {
            arr[j] = bytes[i * 64 + j * 4] << 24 | bytes[i * 64 + j * 4 + 1] << 16 | bytes[i * 64 + j * 4 + 2] << 8 | bytes[i * 64 + j * 4 + 3];
        }
        M[i] = arr;
    }
  
    M[N - 1][14] = (bytes.length - 1) * 8 / Math.pow(2, 32);
    M[N - 1][14] = Math.floor(M[N - 1][14]);
    M[N - 1][15] = (bytes.length - 1) * 8 & 0xffffffff;
  
    for (let i = 0; i < N; ++i) {
        const W = new Uint32Array(80);

        for (let t = 0; t < 16; ++t) {
            W[t] = M[i][t];
        }

        for (let t = 16; t < 80; ++t) {
            W[t] = ROTL(W[t - 3] ^ W[t - 8] ^ W[t - 14] ^ W[t - 16], 1);
        }

        let a = H[0];
        let b = H[1];
        let c = H[2];
        let d = H[3];
        let e = H[4];

        for (let t = 0; t < 80; ++t) {
            const s = Math.floor(t / 20);
            const T = ROTL(a, 5) + f(s, b, c, d) + e + K[s] + W[t] >>> 0;
            e = d;
            d = c;
            c = ROTL(b, 30) >>> 0;
            b = a;
            a = T;
        }
  
        H[0] = H[0] + a >>> 0;
        H[1] = H[1] + b >>> 0;
        H[2] = H[2] + c >>> 0;
        H[3] = H[3] + d >>> 0;
        H[4] = H[4] + e >>> 0;
    }
    return [H[0] >> 24 & 0xff, H[0] >> 16 & 0xff, H[0] >> 8 & 0xff, H[0] & 0xff, H[1] >> 24 & 0xff, H[1] >> 16 & 0xff, H[1] >> 8 & 0xff, H[1] & 0xff, H[2] >> 24 & 0xff, H[2] >> 16 & 0xff, H[2] >> 8 & 0xff, H[2] & 0xff, H[3] >> 24 & 0xff, H[3] >> 16 & 0xff, H[3] >> 8 & 0xff, H[3] & 0xff, H[4] >> 24 & 0xff, H[4] >> 16 & 0xff, H[4] >> 8 & 0xff, H[4] & 0xff];
}

function f(s, x, y, z) {
    switch (s) {
        case 0:
            return x & y ^ ~x & z;
        case 1:
            return x ^ y ^ z;
        case 2:
            return x & y ^ x & z ^ y & z;
        case 3:
            return x ^ y ^ z;
    }
}
  
function ROTL(x, n) {
    return x << n | x >>> 32 - n;
}
  
const uuidRegex = /^(?:[0-9a-f]{8}-[0-9a-f]{4}-[1-5][0-9a-f]{3}-[89ab][0-9a-f]{3}-[0-9a-f]{12}|00000000-0000-0000-0000-000000000000)$/i;
  
function validateUUID(uuid) {
    return (typeof uuid === 'string' && uuidRegex.test(uuid));
}
  
function parse(uuid) {
    if (!validateUUID(uuid)) {
        throw TypeError('Invalid UUID');
    }

    let v;
    const arr = new Uint8Array(16); // Parse ########-....-....-....-............
    arr[0] = (v = parseInt(uuid.slice(0, 8), 16)) >>> 24;
    arr[1] = v >>> 16 & 0xff;
    arr[2] = v >>> 8 & 0xff;
    arr[3] = v & 0xff; // Parse ........-####-....-....-............

    arr[4] = (v = parseInt(uuid.slice(9, 13), 16)) >>> 8;
    arr[5] = v & 0xff; // Parse ........-....-####-....-............

    arr[6] = (v = parseInt(uuid.slice(14, 18), 16)) >>> 8;
    arr[7] = v & 0xff; // Parse ........-....-....-####-............

    arr[8] = (v = parseInt(uuid.slice(19, 23), 16)) >>> 8;
    arr[9] = v & 0xff; // Parse ........-....-....-....-############
    // (Use "/" to avoid 32-bit truncation when bit-shifting high-order bytes)

    arr[10] = (v = parseInt(uuid.slice(24, 36), 16)) / 0x10000000000 & 0xff;
    arr[11] = v / 0x100000000 & 0xff;
    arr[12] = v >>> 24 & 0xff;
    arr[13] = v >>> 16 & 0xff;
    arr[14] = v >>> 8 & 0xff;
    arr[15] = v & 0xff;
    return arr;
}
  
const byteToHex = [];
for (let i = 0; i < 256; ++i) {
    byteToHex.push((i + 0x100).toString(16).slice(1));
}
function byteToString(arr, offset = 0) {
    return (byteToHex[arr[offset + 0]] + byteToHex[arr[offset + 1]] + byteToHex[arr[offset + 2]] + byteToHex[arr[offset + 3]] + '-' + byteToHex[arr[offset + 4]] + byteToHex[arr[offset + 5]] + '-' + byteToHex[arr[offset + 6]] + byteToHex[arr[offset + 7]] + '-' + byteToHex[arr[offset + 8]] + byteToHex[arr[offset + 9]] + '-' + byteToHex[arr[offset + 10]] + byteToHex[arr[offset + 11]] + byteToHex[arr[offset + 12]] + byteToHex[arr[offset + 13]] + byteToHex[arr[offset + 14]] + byteToHex[arr[offset + 15]]).toLowerCase();
}
  
function stringToBytes(str) {
    str = unescape(encodeURIComponent(str)); // UTF8 escape
    const bytes = [];

    for (let i = 0; i < str.length; ++i) {
        bytes.push(str.charCodeAt(i));
    }

    return bytes;
}
function generateUUID5(value, namespace, buf, offset) {
    var _namespace;
    if (typeof value === 'string') {
        value = stringToBytes(value);
    }
    if (typeof namespace === 'string') {
        namespace = parse(namespace);
    }
    if (((_namespace = namespace) === null || _namespace === void 0 ? void 0 : _namespace.length) !== 16) {
        throw TypeError('Namespace must be array-like (16 iterable integer values, 0-255)');
    } 

    let bytes = new Uint8Array(16 + value.length);
    bytes.set(namespace);
    bytes.set(value, namespace.length);
    bytes = sha1(bytes);
    bytes[6] = bytes[6] & 0x0f | 0x50;
    bytes[8] = bytes[8] & 0x3f | 0x80;

    if (buf) {
        offset = offset || 0;
        for (let i = 0; i < 16; ++i) {
            buf[offset + i] = bytes[i];
        }
        return buf;
    }
    return byteToString(bytes);
} 

Ju mund të jepni "vlerë" do të jetë çdo varg ex: ju mund të jepni edhe emrin e domenit tuaj këtu. "Hapësira e emrit" do të fiksohet uuid.

generateUUID5("www.google.com", "e95055fe-5034-5b8d-ab3d-62ea74997e21")

// will give you 
// "de0a6373-7879-5d60-a3b4-a74c1c74d993" => hasing of "www.google.com" with "e95055fe-5034-5b8d-ab3d-62ea74997e21"

Përfundim
UUID v5 zakonisht përdoret vetëm për raste përdorimi shumë specifik kur dëshironi të nxirrni një UUID nga një pjesë tjetër e informacionit në fluturim. Ju lutemi rishikoni rastin tuaj të përdorimit kur jeni në lidhje me përdorimin e UUID5.

Gëzuar kodimin :)