Security News
Fluent Assertions Faces Backlash After Abandoning Open Source Licensing
Fluent Assertions is facing backlash after dropping the Apache license for a commercial model, leaving users blindsided and questioning contributor rights.
@snaplet/copycat
Advanced tools
import { copycat } from '@snaplet/copycat'
copycat.email('foo')
// => 'Zakary.Block356@gmail.com'
copycat.email('bar')
// => 'Thurman.Schowalter668@hotmail.com'
copycat.email('foo')
// => 'Zakary.Block356@gmail.com'
Many of the use cases we aim on solving with snaplet involve anonymizing sensitive information. In practice, this involves replacing each bit of sensitive data with something else that resembles the original value, yet does not allow the original value to be inferred.
To do this, we initially turned to faker for replacing the sensitive data with fake data. This approach took us quite far. However, we struggled with getting the replacement data to be deterministic: we found we did not have enough control over how results are generated to be able to easily ensure that for each value of the original data we wanted to replace, we'd always get the same replacement value out.
Faker allows one to seed a psuedo-random number generator (PRNG), such that the same sequence of values will be generated every time. While this means the sequence is deterministic, the problem was we did not have enough control over where the next value in the sequence was going to be used. Changes to the contents or structure in the original data we're replacing and changes to how we are using faker both had an effect on the way we used this sequence, which in turn had an effect on the resulting replacement value for any particular value in the original data. In other words, we had determinism, but not in a way that is useful for our purposes.
What we were really needing was not the same sequence of generated values every time, but the same mapping to generated values every time.
This is exactly what we designed copycat
to do. For each method provided by copycat, a given input value will always map to the same output value.
import { copycat } from '@snaplet/copycat'
copycat.email('foo')
// => 'Zakary.Block356@gmail.com'
copycat.email('bar')
// => 'Thurman.Schowalter668@hotmail.com'
copycat.email('foo')
// => 'Zakary.Block356@gmail.com'
Copycat work statelessly: for the same input, the same value will be returned regardless of the environment, process, call ordering, or any other external factors.
Under the hood, copycat hashes the input values (in part relying on md5), with the intention of making it computationally infeasible for the input values to be inferred from the output values.
It is still technically possible to make use of faker or similar libraries that offer deterministic PRNG - with some modification. That said, these solutions came with practical limitations that we decided made them less viable for us:
Note though that for either of these approaches, hashing might also still be needed to make it infeasible for the inputs to be inferred from the outputs.
All copycat functions take in an input
value as their first parameter:
import { copycat } from '@snaplet/copycat'
copycat.email('foo')
// => 'Zakary.Block356@gmail.com'
The given input can be any JSON-serializable value. For any two calls to the same function, the input given in each call serializes down to the same value, the same output will be returned.
Note that unlike JSON.stringify()
, object property ordering is not considered.
faker
A re-export of faker
from @faker-js/faker
. We do not alter faker in any way, and do not seed it.
copycat.oneOf(input, values)
Takes in an input
value and an array of values
, and returns an item in values
that corresponds to that input
:
copycat.oneOf('foo', ['red', 'green', 'blue'])
// => 'red'
times(input, range, fn)
Takes in an input
value and a function fn
, calls that function repeatedly (each time with a unique input) for a number of times within the given range
, and returns the results as an array:
copycat.times('foo', [4, 5], copycat.word)
// => [ 'Raeko', 'Vame', 'Kiyumo', 'Koviva', 'Kiyovami' ]
As shown above, range
can be a tuple array of the minimum and maximum possible number of times the maker should be called. It can also be given as a number, in which case fn
will be called exactly that number of times:
copycat.times('foo', 2, copycat.word)
// => [ 'Raeko', 'Vame' ]
copycat.int(input[, options])
Takes in an input
value and returns an integer.
int('foo')
// => 2196697842
options
min=0
and max=Infinity
: the minimum and maximum possible values for returned numberscopycat.bool(input)
Takes in an input
value and returns a boolean.
copycat.bool('foo')
// => false
copycat.float(input[, options])
Takes in an input
value and returns a number value with both a whole and decimal segment.
copycat.float('foo')
// => 2566716916.329745
copycat.char(input)
Takes in an input
value and returns a string with a single character.
copycat.char('foo')
// => 'M'
The generated character will be an alphanumeric: lower and upper case ASCII letters and digits 0 to 9.
copycat.hex(input)
Takes in an input
value and returns a string with a single digit value.
copycat.digit('foo')
// => '2'
copycat.hex(input)
Takes in an input
value and returns a string with a single hex value.
copycat.hex('foo')
// => '2'
options
min=0
and max=Infinity
: the minimum and maximum possible values for returned numberscopycat.dateString(input[, options])
Takes in an input
value and returns a string representing a date in ISO 8601 format.
dateString('foo')
// => '1982-07-11T18:47:39.000Z'
options
minYear=1980
and maxYear=2019
: the minimum and maximum possible year values for returned datescopycat.uuid(input)
Takes in an input and returns a string value resembling a uuid.
copycat.uuid('foo')
// => '540b95dd-98a2-56fe-9c95-6e7123c148ca'
copycat.email(input)
Takes in an input and returns a string value resembling an email address.
copycat.email('foo')
// => 'Zakary.Block356@gmail.com'
copycat.firstName(input)
Takes in an input and returns a string value resembling a first name.
copycat.firstName('foo')
// => 'Alejandrin'
copycat.lastName(input)
Takes in an input and returns a string value resembling a last name.
copycat.lastName('foo')
// => 'Keeling'
copycat.fullName(input)
Takes in an input and returns a string value resembling a full name.
copycat.fullName('foo')
// => 'Zakary Hessel'
copycat.phoneNumber(input)
Takes in an input and returns a string value resembling a phone number.
copycat.phoneNumber('foo')
// => '+3387100418630'
note The strings resemble phone numbers, but will not always be valid. For example, the country dialing code may not exist, or for a particular country, the number of digits may be incorrect. Please let us know if you need valid phone numbers, and feel free to contribute :)
copycat.username(input)
Takes in an input and returns a string value resembling a username.
copycat.username('foo')
// => 'Zakary.Block356'
copycat.password(input)
Takes in an input
value and returns a string value resembling a password.
password('foo')
// => 'uRkXX&u7^uvjX'
Note: not recommended for use as a personal password generator.
copycat.city(input)
Takes in an input and returns a string value representing a city.
copycat.city('foo')
// => 'Garland'
copycat.country(input)
Takes in an input and returns a string value representing a country.
copycat.country('foo')
// => 'Bosnia and Herzegovina'
copycat.streetName(input)
Takes in an input and returns a string value representing a fictitious street name.
copycat.streetName('foo')
// => 'Courtney Orchard'
copycat.streetAddress(input)
Takes in an input and returns a string value representing a fictitious street address.
copycat.streetAddress('foo')
// => '757 Evie Vista'
copycat.postalAddress(input)
Takes in an input and returns a string value representing a fictitious postal address.
copycat.postalAddress('foo')
// => '178 Adaline Forge, Moreno Valley 8538, Haiti'
copycat.countryCode(input)
Takes in an input and returns a string value representing a country code.
copycat.countryCode('foo')
// => 'BV'
copycat.timezone(input)
Takes in an input and returns a string value representing a time zone.
copycat.timezone('foo')
// => 'Asia/Tbilisi'
copycat.word(input)
Takes in an input
value and returns a string value resembling a fictitious word.
copycat.word('foo')
// => 'Kinkami'
options
capitalize=true
: whether or not the word should start with an upper case letterminSyllables=2
and maxSyllables=4
: the minimum and maximum possible number of syllables that returned words will containword('id-2', {
minSyllables: 1,
maxSyllables: 6,
unicode: 0.382
})
// =>
'Rayuashira'
copycat.words(input)
Takes in an input
value and returns a string value resembling fictitious words.
copycat.words('foo')
// => 'Niko vichinashi'
options
min=2
and max=3
: the minimum and maximum possible number of words that returned strings will contain.capitalize='first'
: whether or not the words should start with upper
case letters. If true
or 'all'
is given, each string returned will start with an upper case letter in each word. If 'first'
is given, for each string returned, only the first word will start with an upper case letter. If false
is given, each string returned will always contain only lower case letters.minSyllables=1
and maxSyllables=4
: the minimum and maximum possible number of syllables that returned words will containcopycat.sentence(input)
Takes in an input
value and returns a string value resembling a sentence of fictitious words.
copycat.sentence('foo')
// => 'Kiraevavi somani kihy viyoshi nihahyke kimeraeni.'
options
minClauses=1
and maxClauses=2
: the minimum and maximum possible number of clauses that a returned sentence will contain.minWords=5
and maxWords=8
: the minimum and maximum possible number of words that each clause will contain.minSyllables=1
and maxSyllables=4
: the minimum and maximum possible number of syllables that returned words will containcopycat.paragraph(input)
Takes in an input
value and returns a string value resembling a paragraph of fictitious words.
copycat.paragraph('foo')
// => 'Vakochiko ke rako kimuvachi hayuso mi vako kaichina, mishi mukaimo hakin va racea. Raechime miko kaimo keki shi navi makin yomehyha, na hya nano kin yokimo rae ra. Ke chi kakinaki kakorae machi. Raeva ka kaiko muvani ka racea kaichiyuchi muvinota, sokaiyu komechino shiso yuha raeraceaki kin chitavi. Kokaiashi chirako rae muyo vachi mukani nakoyuta kinmochikai, muhamuva hy mayushita ke shimo takinka notavi kinvayo.'
options
minSentences=3
and minSentences=7
: the minimum and maximum possible number of sentences that a returned paragraph will contain.minClauses=1
and maxClauses=2
: the minimum and maximum possible number of clauses that each sentence will contain.minWords=5
and maxWords=8
: the minimum and maximum possible number of words that each clause will contain.minSyllables=1
and maxSyllables=4
: the minimum and maximum possible number of syllables that returned words will containcopycat.ipv4(input)
Takes in an input
value and returns a string value resembling an IPv4 address.
copycat.ipv4('foo')
// => '166.164.23.159'
copycat.mac(input)
Takes in an input
value and returns a string value resembling a MAC address.
copycat.mac('foo')
// => 'e1:2c:54:74:b7:80'
copycat.userAgent(input)
Takes in an input
value and returns a string value resembling a browser User Agent string.
copycat.userAgent('foo')
// => 'Mozilla/5.0 (compatible; MSIE 9.0; Windows NT 5.3; Trident/3.1; .NET CLR 1.2.39149.4)'
note For simplicity, this is currently working off of a list of 500 pre-defined user agent strings. If this is too limiting for your needs and you need something more dynamic than this, please let us know, and feel free to contribute :)
FAQs
```js import { copycat } from '@snaplet/copycat'
The npm package @snaplet/copycat receives a total of 30,687 weekly downloads. As such, @snaplet/copycat popularity was classified as popular.
We found that @snaplet/copycat demonstrated a healthy version release cadence and project activity because the last version was released less than a year ago. It has 4 open source maintainers collaborating on the project.
Did you know?
Socket for GitHub automatically highlights issues in each pull request and monitors the health of all your open source dependencies. Discover the contents of your packages and block harmful activity before you install or update your dependencies.
Security News
Fluent Assertions is facing backlash after dropping the Apache license for a commercial model, leaving users blindsided and questioning contributor rights.
Research
Security News
Socket researchers uncover the risks of a malicious Python package targeting Discord developers.
Security News
The UK is proposing a bold ban on ransomware payments by public entities to disrupt cybercrime, protect critical services, and lead global cybersecurity efforts.