I'm looking for a platform independent way to generate a random alphanumeric string for a Twitter nonce. Currently I'm using this but it depends on /dev/random which is obviously UNIX-specific:
private auto _getNonce() {
ubyte[32] buffer;
File devRandom = File("/dev/random", "rb");
auto randomData = devRandom.rawRead(buffer);
auto randomBase = Base64.encode(randomData);
auto nonWords = regex(r"[\W_]", "g");
return replaceAll(randomBase, nonWords, "");
}
This follows the recommendation in the Twitter development documentation to get 32 bytes of random data, base-64 encode them and strip all non-alphanumeric characters.
The nonce doesn't have to be cryptographically secure, it's just used to prevent duplicate submissions. Any suggestions for a better way to do this which works on Windows as well as UNIX?
Note: After all these years I should point out that randomCover does not repeat. Meaning this solution will only provide a character once in lower case and once in upper case. I looked at using cycle() to remedy this but randomCover doesn't support infinite ranges.
If all you need is 32 alphnumeric characters:
import std.algorithm : fill;
import std.ascii : letters, digits;
import std.conv : to;
import std.random : randomCover, rndGen;
import std.range : chain;
import std.stdio : writeln;
void main() {
// dchar[] are random access, strings (char[]) are not
auto asciiLetters = to!(dchar[])(letters);
auto asciiDigits = to!(dchar[])(digits);
dchar[32] key;
fill(key[], randomCover(chain(asciiLetters, asciiDigits), rndGen));
writeln(key);
}
The range documentation specifically states
static assert(!isNarrowString!R); // narrow strings cannot be indexed as ranges
narrow strings being char[] and wchar[]. While they are arrays, one cannot find "character" 2,531 in O(1) preventing these types from being considered random access, which is required by randomCover.
std.random should work just fine. It has a variety of random number generators if you care what type you use, but std.random.rndGen uses Mt19937, which is an implementation of Mersenne Twister MT19937. And std.random's number generators are ranges, which makes them interact really well with the rest of Phobos.
One possible implementation
string genNonce()
{
import std.algorithm, std.ascii, std.base64, std.conv, std.random, std.range;
auto rndNums = rndGen().map!(a => cast(ubyte)a)().take(32);
auto result = appender!string();
Base64.encode(rndNums, result);
return result.data.filter!isAlphaNum().to!string();
}
rndGen() generates an infinite range of random numbers. map!(a => cast(ubyte)a)() then lazily converts them to ubyte. And take(32) lazily takes the first 32 of them so that the resultant range has a length of 32 instead of infinity. Base64.encode is then used to encode that in an output range, and that is filtered so that it only contains alphanumeric characters and converted to string.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With