MAC Address Generator — JavaScript source
Generate random EUI-48 MAC addresses with a chosen separator, optional OUI prefix, uppercase formatting, and a locally-administered flag. Runs entirely in your browser with crypto-grade randomness.
This is the JavaScript implementation — the same logic the interactive tool runs, in a shareable, citable form.
/**
* mac-address-generator - random EUI-48 MAC address generator.
*
* Language: JavaScript (ES2020+, runs unmodified in Node 15+ and modern browsers)
* Source: CosmoDev polyglot showcase port of the MAC Address Generator tool,
* ported from src/lib/mac-generator.ts (the canonical TypeScript
* implementation), kept in lock-step with the Go twin at
* cli/mac-address-generator/mac-address-generator.go.
* License: display source - part of CosmoDev's polyglot tool pages.
*
* Design goals:
* - Pure + deterministic; never throws on randomness, only on a malformed OUI.
* - Functionally equivalent to the TS reference: same inputs -> same outputs.
* - Self-contained: stdlib only (no npm dependencies).
*
* API note: this port mirrors the TS canonical lib's public API, the
* deterministic, RNG-injectable superset of the Go twin's. The Go twin draws
* from crypto/rand directly (non-injectable), so its own suite asserts only
* structural properties (regex shape, OUI prefix, U/L bit). Like the TS lib,
* this port accepts an injected rng returning a number in [0, 1), letting the
* showcase tests below assert exact MAC strings.
*
* Pipeline: (optional OUI -> 3 octets) -> 3 random octets -> (force U/L bit) ->
* join 6 octets as 2-digit lowercase hex with the separator -> (uppercase). A
* malformed OUI (not 6 hex digits after stripping non-hex chars) throws.
*/
'use strict';
/**
* Default RNG: a 32-bit draw from the Web Crypto API mapped to [0, 1) - mirrors
* the TS default `crypto.getRandomValues(new Uint32Array(1))[0] / 2**32`. Works
* in Node 15+ (global crypto) and all modern browsers.
*
* @returns {number}
*/
function defaultRng() {
// crypto is global on Node 15+ and in browsers; guard for completeness.
const c = (typeof globalThis !== 'undefined' && globalThis.crypto) || crypto;
return c.getRandomValues(new Uint32Array(1))[0] / 2 ** 32;
}
/**
* Two-digit lowercase hex, mirroring TS `n.toString(16).padStart(2, '0')`.
*
* @param {number} n
* @returns {string}
*/
function hex(n) {
return n.toString(16).padStart(2, '0');
}
/**
* Options shape. Keys are all optional.
* @typedef {Object} MacOptions
* @property {(':' | '-' | '.' | '')} [separator] Joining chars. Defaults to ':'. Empty string concatenates.
* @property {boolean} [uppercase] Uppercase the hex letters in the result.
* @property {string} [oui] Optional 6-hex-digit OUI prefix (separators tolerated, stripped first).
* @property {boolean} [locallyAdministered] Force the U/L bit (0x02) of the first octet.
* @property {() => number} [rng] Random source returning a number in [0, 1).
*/
/**
* Build a random EUI-48 MAC address. The JS twin of `generateMac()` in
* src/lib/mac-generator.ts.
*
* @param {MacOptions} [options={}]
* @returns {string}
*/
function generateMac(options = {}) {
const rng = options.rng ?? defaultRng;
const sep = options.separator ?? ':';
const octets = [];
if (options.oui) {
const clean = options.oui.replace(/[^0-9a-fA-F]/g, '');
if (clean.length !== 6) throw new Error(`OUI must be 6 hex digits, got "${options.oui}"`);
octets.push(
parseInt(clean.slice(0, 2), 16),
parseInt(clean.slice(2, 4), 16),
parseInt(clean.slice(4, 6), 16),
);
} else {
octets.push(Math.floor(rng() * 256), Math.floor(rng() * 256), Math.floor(rng() * 256));
}
octets.push(Math.floor(rng() * 256), Math.floor(rng() * 256), Math.floor(rng() * 256));
if (options.locallyAdministered) {
octets[0] = (octets[0] & 0b11111101) | 0b00000010; // set U/L bit, clear multicast
}
let mac = octets.map(hex).join(sep);
if (options.uppercase) mac = mac.toUpperCase();
return mac;
}
// CommonJS export so the file is consumable from Node without a build step,
// while staying dependency-free and framework-agnostic.
module.exports = { generateMac, hex, defaultRng };
// ---------- showcase tests (mirror src/lib/mac-generator.test.ts) ----------
// Run: node javascript.js
if (require.main === module) {
const assert = require('assert');
assert.strictEqual(generateMac({ rng: () => 0 }), '00:00:00:00:00:00');
// separators: dash and concatenate
assert.strictEqual(generateMac({ rng: () => 0, separator: '-' }), '00-00-00-00-00-00');
assert.strictEqual(generateMac({ rng: () => 0, separator: '' }), '000000000000');
// floor(0.7 * 256) === 179 === 0xb3
assert.strictEqual(generateMac({ rng: () => 0.7, uppercase: true }), 'B3:B3:B3:B3:B3:B3');
// OUI prefix (embedded separators stripped)
assert.strictEqual(generateMac({ rng: () => 0, oui: 'aa-bb-cc' }), 'aa:bb:cc:00:00:00');
// locally administered: floor(0.5 * 256) === 0x80 -> 0x82
assert.strictEqual(generateMac({ rng: () => 0.5, locallyAdministered: true }), '82:80:80:80:80:80');
// malformed OUI -> throws
assert.throws(() => generateMac({ rng: () => 0, oui: 'abc' }));
console.log('ok');
}
Also available in 13 other languages
Every CosmoDev tool ships its pure logic in TypeScript (web) and Go (CLI), with authored implementations in a dozen-plus languages — the same contract, ported. Compare all languages side by side →