Changed separators to constants, added set,get unique and set,get separator
This commit is contained in:
parent
7bef10a2a5
commit
d420db9d09
12
README.md
12
README.md
|
@ -13,12 +13,18 @@ composer require sikofitt/generate-mac
|
||||||
use Sikofitt\GenerateMac\Mac;
|
use Sikofitt\GenerateMac\Mac;
|
||||||
|
|
||||||
$mac = new Mac(); // default is ':'
|
$mac = new Mac(); // default is ':'
|
||||||
|
// or
|
||||||
|
$mac->setSeparator(':');
|
||||||
$address = $mac->getAddress(); // ab:cd:ef:01:23:45
|
$address = $mac->getAddress(); // ab:cd:ef:01:23:45
|
||||||
|
|
||||||
$mac = new Mac('-');
|
$mac = new Mac('-');
|
||||||
|
// or
|
||||||
|
$mac->setSeparator('-');
|
||||||
$address = $mac->getAddress(); // ab-cd-ef-01-23-45
|
$address = $mac->getAddress(); // ab-cd-ef-01-23-45
|
||||||
|
|
||||||
$mac = new Mac('');
|
$mac = new Mac('');
|
||||||
|
// or
|
||||||
|
$mac->setSeparator('');
|
||||||
$address = $mac->getAddress(); // abcdef012345
|
$address = $mac->getAddress(); // abcdef012345
|
||||||
```
|
```
|
||||||
|
|
||||||
|
@ -26,6 +32,9 @@ If you don't care that it is unique you can remove the check for private mac pre
|
||||||
|
|
||||||
```php
|
```php
|
||||||
$mac = new Mac(':', false);
|
$mac = new Mac(':', false);
|
||||||
|
// or
|
||||||
|
$mac->setUnique(false);
|
||||||
|
|
||||||
$address = $mac->getAddress();
|
$address = $mac->getAddress();
|
||||||
|
|
||||||
// '52:54:00:ab:cd:ef', QEMU virtual NIC prefix 52:54:00
|
// '52:54:00:ab:cd:ef', QEMU virtual NIC prefix 52:54:00
|
||||||
|
@ -51,6 +60,9 @@ var_dump($addresses);
|
||||||
* 9 => '32:73:c0:b3:62:27',
|
* 9 => '32:73:c0:b3:62:27',
|
||||||
* );
|
* );
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
// if you call this with 1 as the count it will still
|
||||||
|
// return an array [0 => '32:73:c0:b3:62:27']
|
||||||
```
|
```
|
||||||
|
|
||||||
#### Test
|
#### Test
|
||||||
|
|
|
@ -21,12 +21,15 @@ namespace Sikofitt\GenerateMac\Command;
|
||||||
|
|
||||||
use Sikofitt\GenerateMac\Mac;
|
use Sikofitt\GenerateMac\Mac;
|
||||||
use Symfony\Component\Console\Command\Command;
|
use Symfony\Component\Console\Command\Command;
|
||||||
use Symfony\Component\Console\Exception\InvalidArgumentException;
|
use Symfony\Component\Console\Exception\{
|
||||||
use Symfony\Component\Console\Exception\RuntimeException;
|
InvalidArgumentException,
|
||||||
|
RuntimeException
|
||||||
|
};
|
||||||
use Symfony\Component\Console\Input\{
|
use Symfony\Component\Console\Input\{
|
||||||
InputInterface,
|
InputInterface,
|
||||||
InputOption
|
InputOption
|
||||||
};
|
};
|
||||||
|
use Symfony\Component\Console\Output\ConsoleOutput;
|
||||||
use Symfony\Component\Console\Output\OutputInterface;
|
use Symfony\Component\Console\Output\OutputInterface;
|
||||||
use Symfony\Component\Console\Style\SymfonyStyle;
|
use Symfony\Component\Console\Style\SymfonyStyle;
|
||||||
|
|
||||||
|
@ -41,7 +44,7 @@ class GenerateMacCommand extends Command
|
||||||
->addOption('separator', 's', InputOption::VALUE_REQUIRED, 'The separator to use for mac addresses.')
|
->addOption('separator', 's', InputOption::VALUE_REQUIRED, 'The separator to use for mac addresses.')
|
||||||
;
|
;
|
||||||
|
|
||||||
parent::configure(); // TODO: Change the autogenerated stub
|
parent::configure();
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -49,7 +52,7 @@ class GenerateMacCommand extends Command
|
||||||
* @param \Symfony\Component\Console\Output\OutputInterface $output
|
* @param \Symfony\Component\Console\Output\OutputInterface $output
|
||||||
*
|
*
|
||||||
* @throws \Exception
|
* @throws \Exception
|
||||||
* @return int|null
|
* @return int
|
||||||
*/
|
*/
|
||||||
public function execute(InputInterface $input, OutputInterface $output): int
|
public function execute(InputInterface $input, OutputInterface $output): int
|
||||||
{
|
{
|
||||||
|
@ -58,6 +61,7 @@ class GenerateMacCommand extends Command
|
||||||
if ($count <= 0) {
|
if ($count <= 0) {
|
||||||
throw new RuntimeException('$count should be a positive number greater than zero.');
|
throw new RuntimeException('$count should be a positive number greater than zero.');
|
||||||
}
|
}
|
||||||
|
|
||||||
$separator = strtolower($input->getOption('separator') ?? 'colon');
|
$separator = strtolower($input->getOption('separator') ?? 'colon');
|
||||||
|
|
||||||
if (!\in_array($separator, ['colon','none','dash'], true)) {
|
if (!\in_array($separator, ['colon','none','dash'], true)) {
|
||||||
|
@ -67,19 +71,22 @@ class GenerateMacCommand extends Command
|
||||||
$outputFormat = strtolower($input->getOption('output') ?? 'string');
|
$outputFormat = strtolower($input->getOption('output') ?? 'string');
|
||||||
|
|
||||||
$io = new SymfonyStyle($input, $output);
|
$io = new SymfonyStyle($input, $output);
|
||||||
|
|
||||||
switch ($separator) {
|
switch ($separator) {
|
||||||
case 'colon':
|
case 'colon':
|
||||||
default:
|
default:
|
||||||
$separator = ':';
|
$separator = Mac::SEPARATOR_COLON;
|
||||||
break;
|
break;
|
||||||
case 'none':
|
case 'none':
|
||||||
$separator = '';
|
$separator = Mac::SEPARATOR_NONE;
|
||||||
break;
|
break;
|
||||||
case 'dash':
|
case 'dash':
|
||||||
$separator = '-';
|
$separator = Mac::SEPARATOR_DASH;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
$mac = new Mac($separator);
|
$mac = new Mac($separator);
|
||||||
|
|
||||||
$macAddresses = $mac->getMacAddresses($count);
|
$macAddresses = $mac->getMacAddresses($count);
|
||||||
|
|
||||||
switch ($outputFormat) {
|
switch ($outputFormat) {
|
||||||
|
@ -93,7 +100,7 @@ class GenerateMacCommand extends Command
|
||||||
$io->writeln(\json_encode($result, JSON_PRETTY_PRINT));
|
$io->writeln(\json_encode($result, JSON_PRETTY_PRINT));
|
||||||
break;
|
break;
|
||||||
case 'plain':
|
case 'plain':
|
||||||
$io->writeln($macAddresses);
|
$io->writeln($macAddresses, SymfonyStyle::OUTPUT_PLAIN | SymfonyStyle::VERBOSITY_NORMAL);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -21,6 +21,10 @@ namespace Sikofitt\GenerateMac;
|
||||||
|
|
||||||
class Mac
|
class Mac
|
||||||
{
|
{
|
||||||
|
/**
|
||||||
|
* Private mac address prefixes that are used
|
||||||
|
* internally or with virtual machines and containers.
|
||||||
|
*/
|
||||||
private const UNAVAILABLE_LOCAL_PREFIXES = [
|
private const UNAVAILABLE_LOCAL_PREFIXES = [
|
||||||
'02bb01', // Octothorpe
|
'02bb01', // Octothorpe
|
||||||
'02aa3c', // Olivetti Telecomm SPA (olteco)
|
'02aa3c', // Olivetti Telecomm SPA (olteco)
|
||||||
|
@ -44,42 +48,46 @@ class Mac
|
||||||
'deadca', // PearPC virtual NIC
|
'deadca', // PearPC virtual NIC
|
||||||
];
|
];
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Reserved mac prefixes for private devices.
|
||||||
|
*/
|
||||||
private const AVAILABLE_PREFIXES = [
|
private const AVAILABLE_PREFIXES = [
|
||||||
'x2xxxx',
|
'x2xxxx',
|
||||||
'x6xxxx',
|
'x6xxxx',
|
||||||
'xaxxxx',
|
'xaxxxx',
|
||||||
'xaxxxx',
|
'xexxxx',
|
||||||
];
|
];
|
||||||
|
|
||||||
|
public const SEPARATOR_COLON = 0;
|
||||||
|
public const SEPARATOR_DASH = 1;
|
||||||
|
public const SEPARATOR_NONE = 2;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @var bool
|
* @internal
|
||||||
|
* @var bool For testing that we get a prefix that is not used.
|
||||||
*/
|
*/
|
||||||
protected $isTest = false;
|
protected $isTest = false;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @var string
|
* @var int The mac address separator, can be self::SEPARATOR_*
|
||||||
*/
|
*/
|
||||||
private $separator;
|
private $separator;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @var bool
|
* @var bool If we care if we get an already used prefix or not.
|
||||||
*/
|
*/
|
||||||
private $unique;
|
private $unique;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Mac constructor.
|
* Mac constructor.
|
||||||
*
|
*
|
||||||
* @param string $separator
|
* @param int $separator The mac address separator, one of ':', '-', or ''
|
||||||
* @param bool $unique
|
* @param bool $unique Whether or not we care if we get a non unique prefix.
|
||||||
*/
|
*/
|
||||||
public function __construct(string $separator = ':', bool $unique = true)
|
public function __construct(int $separator = self::SEPARATOR_COLON, bool $unique = true)
|
||||||
{
|
{
|
||||||
if (!\in_array($separator, [':', '', '-'], true)) {
|
$this->setUnique($unique);
|
||||||
throw new \InvalidArgumentException('Separator is invalid. Acceptable values: ":", "-", or ""');
|
$this->setSeparator($separator);
|
||||||
}
|
|
||||||
|
|
||||||
$this->unique = $unique;
|
|
||||||
$this->separator = $separator;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -95,7 +103,7 @@ class Mac
|
||||||
$prefix = '02bb01';
|
$prefix = '02bb01';
|
||||||
}
|
}
|
||||||
|
|
||||||
if ($this->unique) {
|
if ($this->getUnique()) {
|
||||||
while ($this->isTaken($prefix)) {
|
while ($this->isTaken($prefix)) {
|
||||||
$prefix = $this->generateString($template);
|
$prefix = $this->generateString($template);
|
||||||
}
|
}
|
||||||
|
@ -107,7 +115,9 @@ class Mac
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @param int $count
|
* Note: if count is 1 it will still be returned as an array. [0 => $macAddress]
|
||||||
|
*
|
||||||
|
* @param int $count The number of mac addresses to generate.
|
||||||
*
|
*
|
||||||
* @throws \Exception
|
* @throws \Exception
|
||||||
* @return array
|
* @return array
|
||||||
|
@ -124,7 +134,53 @@ class Mac
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @param string $prefix
|
* @param bool $unique
|
||||||
|
*
|
||||||
|
* @return \Sikofitt\GenerateMac\Mac
|
||||||
|
*/
|
||||||
|
public function setUnique(bool $unique = true): Mac
|
||||||
|
{
|
||||||
|
$this->unique = $unique;
|
||||||
|
|
||||||
|
return $this;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return bool
|
||||||
|
*/
|
||||||
|
public function getUnique(): bool
|
||||||
|
{
|
||||||
|
return $this->unique;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param int $separator
|
||||||
|
*
|
||||||
|
* @return \Sikofitt\GenerateMac\Mac
|
||||||
|
*/
|
||||||
|
public function setSeparator(int $separator): Mac
|
||||||
|
{
|
||||||
|
if (!\in_array($separator, [self::SEPARATOR_COLON, self::SEPARATOR_DASH, self::SEPARATOR_NONE], true)) {
|
||||||
|
throw new \InvalidArgumentException('Separator is invalid. Acceptable values: ":", "-", or ""');
|
||||||
|
}
|
||||||
|
|
||||||
|
$this->separator = $separator;
|
||||||
|
|
||||||
|
return $this;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return int
|
||||||
|
*/
|
||||||
|
public function getSeparator(): int
|
||||||
|
{
|
||||||
|
return $this->separator;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Test to see if we have a unique prefix.
|
||||||
|
*
|
||||||
|
* @param string $prefix The current prefix.
|
||||||
*
|
*
|
||||||
* @return bool
|
* @return bool
|
||||||
*/
|
*/
|
||||||
|
@ -134,12 +190,14 @@ class Mac
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @param string $template
|
* Generates a string
|
||||||
|
*
|
||||||
|
* @param string $template The template to use xexxxx.
|
||||||
*
|
*
|
||||||
* @throws \Exception
|
* @throws \Exception
|
||||||
* @return mixed|string
|
* @return string
|
||||||
*/
|
*/
|
||||||
private function generateString(string $template)
|
private function generateString(string $template): string
|
||||||
{
|
{
|
||||||
$bytes = sodium_bin2hex(\random_bytes(32));
|
$bytes = sodium_bin2hex(\random_bytes(32));
|
||||||
|
|
||||||
|
@ -161,13 +219,29 @@ class Mac
|
||||||
return \current($prefixes);
|
return \current($prefixes);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private function getSeparatorAsString(): string
|
||||||
|
{
|
||||||
|
switch($this->getSeparator()) {
|
||||||
|
default:
|
||||||
|
case self::SEPARATOR_COLON:
|
||||||
|
return ':';
|
||||||
|
case self::SEPARATOR_DASH:
|
||||||
|
return '-';
|
||||||
|
case self::SEPARATOR_NONE:
|
||||||
|
return '';
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
* Inserts the chosen separator.
|
||||||
|
*
|
||||||
* @param string $macAddress
|
* @param string $macAddress
|
||||||
*
|
*
|
||||||
* @return string
|
* @return string
|
||||||
*/
|
*/
|
||||||
private function insertSeparator(string $macAddress): string
|
private function insertSeparator(string $macAddress): string
|
||||||
{
|
{
|
||||||
return implode($this->separator, str_split($macAddress, 2));
|
|
||||||
|
return implode($this->getSeparatorAsString(), str_split($macAddress, 2));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -83,10 +83,10 @@ class GenerateMacCommandTest extends TestCase
|
||||||
$this->commandTester->execute(['--separator' => 'none', '--output' => 'plain']);
|
$this->commandTester->execute(['--separator' => 'none', '--output' => 'plain']);
|
||||||
|
|
||||||
$output = $this->commandTester->getDisplay(true);
|
$output = $this->commandTester->getDisplay(true);
|
||||||
// 13 because it adds a new line
|
// 13 because it adds a new line with SymfonyStyle::writeLn();
|
||||||
$this->assertSame(13, strlen($output));
|
$this->assertSame(13, \strlen($output));
|
||||||
// just to make sure trim it.
|
// just to make sure trim it.
|
||||||
$this->assertSame(12, strlen(trim($output)));
|
$this->assertSame(12, \strlen(trim($output)));
|
||||||
|
|
||||||
$this->commandTester->execute(['--separator' => 'dash', '--output' => 'plain']);
|
$this->commandTester->execute(['--separator' => 'dash', '--output' => 'plain']);
|
||||||
$output = $this->commandTester->getDisplay();
|
$output = $this->commandTester->getDisplay();
|
||||||
|
|
|
@ -40,12 +40,20 @@ class MacTest extends TestCase
|
||||||
}
|
}
|
||||||
|
|
||||||
$this->assertRegExp(self::REGEX, $mac->getMacAddress());
|
$this->assertRegExp(self::REGEX, $mac->getMacAddress());
|
||||||
|
$this->assertSame(Mac::SEPARATOR_COLON, $mac->getSeparator());
|
||||||
|
$this->assertTrue($mac->getUnique());
|
||||||
}
|
}
|
||||||
|
|
||||||
public function testSeparator(): void
|
public function testSeparator(): void
|
||||||
{
|
{
|
||||||
$mac = new Mac('-');
|
$mac = new Mac(Mac::SEPARATOR_DASH);
|
||||||
|
|
||||||
|
$this->assertSame(Mac::SEPARATOR_DASH, $mac->getSeparator());
|
||||||
$this->assertRegExp(self::REGEX, $mac->getMacAddress());
|
$this->assertRegExp(self::REGEX, $mac->getMacAddress());
|
||||||
|
$mac->setSeparator(Mac::SEPARATOR_COLON);
|
||||||
|
$this->assertSame(Mac::SEPARATOR_COLON, $mac->getSeparator());
|
||||||
|
$this->assertRegExp(self::REGEX, $mac->getMacAddress());
|
||||||
|
$this->assertNotFalse(strpos($mac->getMacAddress(), ':'));
|
||||||
}
|
}
|
||||||
|
|
||||||
public function testUnique(): void
|
public function testUnique(): void
|
||||||
|
@ -53,14 +61,17 @@ class MacTest extends TestCase
|
||||||
$class = new class extends Mac {
|
$class = new class extends Mac {
|
||||||
protected $isTest = true;
|
protected $isTest = true;
|
||||||
};
|
};
|
||||||
|
$this->assertTrue($class->getUnique());
|
||||||
|
|
||||||
$macAddress = $class->getMacAddress();
|
$macAddress = $class->getMacAddress();
|
||||||
$this->assertStringStartsNotWith(self::NON_UNIQ_PREFIX, $macAddress);
|
$this->assertStringStartsNotWith(self::NON_UNIQ_PREFIX, $macAddress);
|
||||||
|
$class->setUnique(false);
|
||||||
|
$this->assertFalse($class->getUnique());
|
||||||
}
|
}
|
||||||
|
|
||||||
public function testThrowsOnInvalidPrefix(): void
|
public function testThrowsOnInvalidPrefix(): void
|
||||||
{
|
{
|
||||||
$this->expectException(\InvalidArgumentException::class);
|
$this->expectException(\InvalidArgumentException::class);
|
||||||
$mac = new Mac('_');
|
$mac = new Mac(4);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue