Research
Security News
Malicious npm Packages Inject SSH Backdoors via Typosquatted Libraries
Socket’s threat research team has detected six malicious npm packages typosquatting popular libraries to insert SSH backdoors.
It is the pervading law of all things organic and inorganic,
Of all things physical and metaphysical,
Of all things human, and all things super-human,
Of all true manifestations of the head,
Of the heart, of the soul,
That the life is recognizable in its expression,
That form ever follows function. This is the law.
— Louis Sullivan, 1896
Sullivan is a functional, composable, simple way to validate nested data structures. It generates validation errors which are especially suitable for API responses.
Sullivan doesn't do much, because it doesn't need to. It's three things:
require 'sullivan'
laugh_session_validation = Sullivan.validation do
laugh = hash(
sound: string_matching(/\Al(ol)+\z/, error: "must be be a laughing sound of some length"),
intensity: optional(kind_of(Numeric))
)
hash(
primary_laugh: laugh,
rebound_giggles: many(laugh)
)
end
laugh_session = {
primary_laugh: {
sound: "lolololol",
intensity: "High"
},
rebound_giggles: [
{
sound: "lololol",
intensity: 2
},
{
sound: "sigh",
mood: "pleasant"
}
]
}
laugh_session_validation.validate(laugh_session)
# =>
# {
# :primary_laugh => {
# :intensity => "must be a kind of Numeric, if present"
# },
# :rebound_giggles => [
# nil,
# {
# :sound => "must be be a laughing sound of some length",
# :mood => "is unexpected"
# }
# ]
# }
Add this line to your application's Gemfile:
gem 'sullivan'
And then execute:
$ bundle
Or install it yourself as:
$ gem install sullivan
Like it says above, Sullivan is three things.
validate
: A simple pattern for defining validators.Sullivan specifies a simple API for defining validators. It's so simple, you
don't need Sullivan to use it. All you need is an object which responds to
#validate
. If it fails to validate, it should return an error message (a
string). If it passes validation, it should return nil
. That's all there is
to it.
If your validator takes parameters, it might make sense to write it as a class and instantiate it:
class LegalVotingAge
def initialize(country:)
@minimum_age =
case country
when :united_states
18
when :austria
16
else
raise "Don't know the voting age in #{country}"
end
end
def validate(age)
"is too young to vote" if age < @minimum_age
end
end
LegalVotingAge.new(:united_states).validate(17) #=> "is too young to vote"
LegalVotingAge.new(:austria).validate(17) #=> nil
If your validator doesn't take parameters, you might want to just make it an object:
ApiBoolean = Object.tap do |v|
def v.validate(value)
"must be a boolean value" unless [true, false, 'true', 'false'].include?(value)
end
end
ApiBoolean.validate(true) #=> nil
ApiBoolean.validate('false') #=> nil
ApiBoolean.validate('not sure') #=> "must be a boolean value"
Sullivan doesn't care. In fact, Sullivan-the-libary isn't even involved yet.
Sullivan::Validators
: A handful of useful, composable validators provided for freeSometimes you need a really custom validator, but there are a few staples we
need in all sorts of projects. Sullivan provides those, including some
higher-order validators (validators which take other validators as
parameters, like Hash
and Optional
), which is where Sullivan's
composability really shines.
Sullivan's built-in validators live in Sullivan::Validators
. Look there to
read more about each one.
Sullivan.validation
: Some syntactic sugar for using the built-in validatorsThe built-in validators are a bit cumbersome to instantiate, considering you'll
be using them quite a bit. To help, there's Sullivan.validation
. Within its
block, you can instantiate the validators in Sullivan::Validators
as
snake_cased
methods. So:
v = Sullivan.validation do
hash({})
end
v.class #=> Sullivan::Validators::Hash
There's one catch: because this uses instance_eval
, inside the block self
will not be the same as self
outside the block, so you can't use method calls
the way you might like to. That is, this won't work:
class User
def valid_username_regex
%r{\w+}
end
def validation
Sullivan.validation do
string_matching(valid_username_regex)
#=> NameError: undefined local variable or method `valid_username_regex' for #<Sullivan::DSL:0x007fa5c44e1508>
end
end
end
If you need to do something like that, you can use the 1-arity form of the block, for a slightly more verbose syntax:
class User
def valid_username_regex
%r{\w+}
end
def validation
Sullivan.validation do |vals|
vals.string_matching(valid_username_regex)
end
end
end
Of course, Sullivan.validation
is completely optional. Feel free to instantiate the validation classes directly.
This is where it gets fun. Let's say you're validating API input. Suppose you have an API that can create a Person record and one that can create multiple Person records at once. You might have validations like:
module Validations
Person = Sullivan.validation do
hash(
name: kind_of(String),
favorite_ice_cream_flavor: optional(kind_of(String))
)
end
PersonCreation = Sullivan.validation do
hash(person: Person)
end
PeopleCreation = Sullivan.validation do
hash(people: many(Person))
end
end
Now your API could use Validations::PersonCreation.validate
and Validations::PeopleCreation.validate
to validate the two kinds of requests.
Notice that I've assigned these validators to constants in a module. That's a useful pattern in some cases, but it's completely optional. Store them wherever they're most useful in your application. They're just objects.
git checkout -b my-new-feature
)git commit -am 'Add some feature'
)git push origin my-new-feature
)FAQs
Unknown package
We found that sullivan demonstrated a not healthy version release cadence and project activity because the last version was released a year ago. It has 1 open source maintainer 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.
Research
Security News
Socket’s threat research team has detected six malicious npm packages typosquatting popular libraries to insert SSH backdoors.
Security News
MITRE's 2024 CWE Top 25 highlights critical software vulnerabilities like XSS, SQL Injection, and CSRF, reflecting shifts due to a refined ranking methodology.
Security News
In this segment of the Risky Business podcast, Feross Aboukhadijeh and Patrick Gray discuss the challenges of tracking malware discovered in open source softare.