
Security News
/Research
Wallet-Draining npm Package Impersonates Nodemailer to Hijack Crypto Transactions
Malicious npm package impersonates Nodemailer and drains wallets by hijacking crypto transactions across multiple blockchains.
A set of objects that acts like types (type checking and type casting) with a support for basic type algebra.
Minimalistic type system for any ruby project. Supports custom type definition, type validation, type casting and type categorizing. Provides a set of commonly used type categories and general purpose types. Has a flexible and simplest type definition toolchain.
gem 'smart_types'
bundle install
# --- or ---
gem install smart_types
require 'smart_core/types'
SmartCore::Types::Value
)SmartCore::Types::Protocol
)SmartCore::Types::Variadic
)# documentation is coming
type.valid?(value)
type.validate!(value)
type.cast(value)
type.nilable
type3 = type1 | type2
type4 = type1 & type2
Types with runtime:
# get a type object with a custom runtime (instances of String or Symbol):
type = SmartCore::Types::Protocol::InstanceOf(::String, ::Symbol)
type.valid?(:test) # => true
type.valid?('test') # => true
type.valid?(123.456) # => false
# another type object with a custom runtime (tuple (String, Integer, Time)):
type = SmartCore::Types::Variadic::Tuple(::String, ::Integer, ::DateTime)
type.valid?(['test', 1, DateTime.new]) # => true
type.valid?([:test, 2]) # => false
SmartCore::Types::Value::Any
SmartCore::Types::Value::Nil
SmartCore::Types::Value::String
SmartCore::Types::Value::Symbol
SmartCore::Types::Value::Text
SmartCore::Types::Value::Integer
SmartCore::Types::Value::Float
SmartCore::Types::Value::Numeric
SmartCore::Types::Value::BigDecimal
SmartCore::Types::Value::Boolean
SmartCore::Types::Value::Array
SmartCore::Types::Value::Set
SmartCore::Types::Value::Hash
SmartCore::Types::Value::Proc
SmartCore::Types::Value::Class
SmartCore::Types::Value::Module
SmartCore::Types::Value::Time
SmartCore::Types::Value::DateTime
SmartCore::Types::Value::Date
SmartCore::Types::Value::TimeBased
SmartCore::Types::Value::Method
SmartCore::Types::Protocol::InstanceOf
# examples (SmartCore::Types::Protocol::InstanceOf):
SmartCore::Types::Protocol::InstanceOf(::Integer) # only integer
SmartCore::Types::Protocol::InstanceOf(::String, ::Symbol) # string or symbol
SmartCore::Types::Protocol::InstanceOf(::Time, ::DateTime, ::Date) # time or datetime or date
SmartCore::Types::Variadic::ArrayOf
SmartCore::Types::Variadic::Enum
SmartCore::Types::Variadic::Tuple
# example (SmartCore::Types::Variadic::ArrayOf):
SmartCore::Types::Variadic::ArrayOf(::String, ::Array) # array of strings or arrays
# example (SmartCore::Types::Variadic::Enum):
SmartCore::Types::Variadic::Enum('string', 1337, :symbol) # one of enumerated values
# examples (SmartCore::Types::Variadic::Tuple):
SmartCore::Types::Variadic::Tuple(::String, ::Integer, ::Time) # array with signature [<string>, <integer>, <time>]
SmartCore::Types::Variadic::Tuple(::Symbol, ::Float) # array with signature [<symbol>, <float>]
.nilable
on any type object:SmartCore::Types::Value::String.nilable
# -- or --
SmartCore::Types::Value::Time.nilable
# and etc.
Type definition is a composition of:
Invariant is a custom validation block that will work as a logical value checker. You can have as much invariants as you want.
Type invariants does not depends on each other (invariant defined out from chain does not depends on other invariants);
Invariants inside invariant chains will be invoked in order they was defined and each internal invariant depends on the valid previous invariant check.
!IMPORTANT! Type sum and type multiplication does not support invariant checking and custom invariant definition at this moment. Type sum and type mult ignores type invariants in their validation logic (currently this functionality in development yet).
Invariant checking is a special validation layer (see #type validation readme section). Invariant error code pattern:
TypeName.invariant_chain_name.invariant_name
;TypeName.invariant_name
;# documentation is coming
# example:
SmartCore::Types::Value.define_type(:String) do |type|
type.define_checker do |value, runtime_attrs| # runtime attributes are optional
value.is_a?(::String)
end
type.define_caster do |value, runtime_attrs| # runtime attributes are optional
value.to_s
end
end
# get a type object:
SmartCore::Types::Value::String
# --- or ---
SmartCore::Types::Value::String() # without runtime attributes
# --- or ---
SmartCore::Types::Value::String('some_attr', :another_attr) # with runtime attributes
# work with type object: see documentation below
SmartCore::Types::Value.define_type(:String) do |type|
type.define_checker do |value, runtime_attrs|
value.is_a?(::String)
end
type.define_caster do |value, runtime_attrs|
value.to_s
end
# NOTE:
# invariant defined out from chain does not depends on other invariants
type.invariant(:uncensored_content) do |value, runtime_attrs|
!value.include?('uncensored_word')
end
type.invariant(:filled) do |value, runtime_attrs|
value != ''
end
type.invariant_chain(:password) do
invariant(:should_present) do |value, runtime_attrs|
value != ''
end
invariant(:should_have_numbers) do |value, runtime_attrs|
v.match?(/[0-9]+/)
end
# NOTE:
# inside a chain each next invariant invocation
# depends on previous successful invariant check
end
end
Type validation reflects on two APIs:
Type invariants does not depends on each other (invariant defined out from the chain does not depends on other invariants);
Invariants inside invariant chains will be invoked in order they was defined and each internal invariant depends on the valid previous invariant check.
!IMPORTANT! Type sum and type multiplication does not support invariant checking and custom invariant definition at this moment. Type sum and type mult ignores type invariants in their validation logic (currently this functionality in development yet).
Invariant checking is a special validation layer (see #type validation readme section) and represents a set of error codes in result object;
Type validation interface:
valid?(value)
- validates value and returns true
or false
;
ture
only if the type checker returns true
and all invariants are valid;validate(value)
- validates value and returns the monadic result object:
SmartCore::Types::Primitive::Validator::Result
for primitive types;SmartCore::Types::Primitive::SumValidator::Result
for sum-based types;SmartCore::Types::Primitive::MultValidator::Result
for mult-based types;SmartCore::Types::Primitive::NilableValidator::Result
for nilable types;validate!(value)
- validates value and returns nothing (for successful validation) or
raises an exception (SmartCore::Types::TypeError
) (for unsuccessful validation);Validation result object interface:
#success?
/ #failure?
(#success?
is a combination of valid_check? && valid_invariants?
; #failure?
- is an opposite of #success?
);#valid_check?
(valid type checker or not);#valid_invariants?
(false
if at least one invariant is invalid);#errors
(the same as #invariant_errors
and the same as #error_codes
) - an array of failed invariant names;
TypeName.invariant_chain_name.invariant_name
;TypeName.invariant_name
;#checked_value
(the same as #value
) - checked value :)Imagine that we have String
type like this:
SmartCore::Types::Value.define_type(:String) do |type|
type.define_checker do |value|
value.is_a?(::String)
end
type.define_caster do |value|
value.to_s
end
type.invariant(:uncensored_content) do |value|
!value.include?('uncensored_word')
end
type.invariant(:filled) do |value|
value != ''
end
type.invariant_chain(:password) do
invariant(:should_present) { |value| value != '' }
invariant(:should_have_numbers) { |value| v.match?(/[0-9]+/) }
end
end
Validation interface and usage:
SmartCore::Types::Value::String.valid?('test123') # => true
SmartCore::Types::Value::String.valid?(123.45) # => false
result = SmartCore::Types::Value::String.validate('test')
result.checked_value # => 'test'
# --- same as: ---
result.value
result.success? # => false (valid_check? && valid_invariants?)
result.failure? # => true
result.valid_check? # => true
result.valid_invariants? # => false
# invariant errors:
result.errors # => ['String.password.should_have_numbers']
# -- same as: ---
result.invariant_errors
# -- same as: ---
result.error_codes
result = SmartCore::Types::Value::String.validate('test1234')
result.success? # => true
result.errors # => []
SmartCore::Types::Value::String.validate!('test') # => SmartCore::Types::TypeError
SmartCore::Types::Value::String.cast(123) # => "123"
SmartCore::Types::Value::Float.cast('55') # => 55.0
(type sum and type multiplication does not support invariants at this moment (in development yet));
# documentation is coming
# how to define primitive type sum:
SmartCore::Types::Value::Text = SmartCore::Types::Value::String | SmartCore::Types::Value::Symbol
SmartCore::Types::Value::Numeric = SmartCore::Types::Value::Float | SmartCore::Types::Value::Integer
# how to define primitive type multiplication:
SmartCore::Types::Value::CryptoString = SmartCore::Types::Value::NumberdString & SmartCore::Types::Value::SymbolicString
migrate to Github Actions
;
support for block
-attribute in runtime attributes;
type configuration:
SmartCore::Types::Value.type(:Time) do |type|
type.configuration do |config| # config definition
setting :iso, :rfc2822
# TODO: think about a more convinient DSL
end
type.define_caster do |value, config| # config usage
case config.standard
when :rfc2822
::Time.rfc2822(value)
else
# ...
end
end
end
SmartCore::Types::Value::TimeLike = SmartCore::Types::System.type_sum(
SmartCore::Types::Time,
SmartCore::Types::DateTime,
SmartCore::Types::Date,
) do |type|
type.define_caster(:pipelined) # try Time.cast => try DateTime.cast => try Date.cast
end
# before:
SmartCore::Types::Value::Boolean.validate!(123)
# => SmartCore::Types::TypeError
SmartCore::Types::Value::Class.cast(123)
# => SmartCore::Types::TypeCastingError
# after:
SmartCore::Types::Value::Boolean.validate!(123)
# => SmartCore::Types::Value::Boolean::TypeError
# (inheritance tree: Types::Value::<Type>::TypeError => Types::Value::TypeError => Types::TypeError)
SmartCore::Types::Value::Class.cast(123)
# => SmartCore::Types::Value::Class::TypeCastingError
# (inheritance tree: the same as above)
SmartCore::Types.configure do |config|
config.warn_on_type_refinements = true # false by default
end
SmartCore::Types::Value.refine(:Time) do |type|
# new type definition
end
SmartCore::Types::Value::Time.refine do |type|
# new type definition
end
SmartCore::Types::Value::Time.refine_checker do |value, original_checker|
# new type checker
end
SmartCore::Types::Value::Time.refine_caster do |value, original_caster|
# new type caster
end
SmartCore::Types::Value::Time.refine_runtime_attributes_checker do |value, original_checker|
# new runtime attribute checker
end
SmartCore::Types::Value::Time.refine_invariant(:name) do |value|
# new invariant
end
SmartCore::Types::Value::Time.refine_invariant_chain(:chain_name) do
# new invariant chain
end
SmartCore::Types::Value.define_type(:Date) do |type|
type.define_caster do |value, options = {}| # options goes here
iso = options.fetch(:iso, nil)
iso ? ::Date.pasre(value, iso) : ::Date.parse(value)
end
end
# usage:
SmartCore::Types::Value::Date.cast('2020-01-01', { iso: :rfc3339 })
SmartCore::Types.define_category(:YourCategoryName)
SmartCore::Types::YourCategoryName.define_type(:YourNewType) { ... }
SmartCore::Types::Value::UnboundMethod
SmartCore::Types::Value::Enumerable
SmartCore::Types::Value::Comparable
SmartCore::Types::Value::Enumerator
SmartCore::Types::Value::EnumeratorChain
SmartCore::Types::Value::Range
SmartCore::Types::Value::Rational
SmartCore::Types::Value::SortedSet
SmartCore::Types::Value::IO
SmartCore::Types::Value::StringIO
SmartCore::Types::Value::BasicObject
SmartCore::Types::Struct::Schema
SmartCore::Types::Struct::JSONSchema
SmartCore::Types::Struct::StrictArray
SmartCore::Types::Struct::StrictHash
SmartCore::Types::Struct::Map
SmartCore::Types::Protocol::Interface
SmartCore::Types::Protocol::Ancestors
SmartCore::Types::Protocol::Enumerable
SmartCore::Types::Protocol::Comparable
SmartCore::Types::Protocol::Forwardable
SmartCore::Types::Protocol::Callable
SmartCore::Types::Behavior::Truthy
SmartCore::Types::Behavior::Falsy
# Common types:
SmartCore::Types::Common::UUDv4
# think about:
Clonable # for example, you can not clone or duplicate Method-objects
Duplicable
Allocatable # for example, Method object can not be allocated with #allocate method
#sum
alias for |
and #mult
alias for &
(with a support for type name definition and other API);
type category in invariant error codes:
# before:
'String.password.should_contain_numbers' # `String` type from `Value` category
# after:
'Value.String.password.should_contain_numbers' # `Value::String`
SmartCore::Types::Primitive::Undefined
);type.reconcilable { |value, *types| .... }
setting;type.reconcilable
should be accessible for type sum and type mult definitions;type.reconcilable { |value, *types| .... }
setting;type.reconcilable
should be accessible for type sum and type mult definitions;git checkout -b feature/my-new-feature
)git commit -am '[feature_context] Add some feature'
)git push origin feature/my-new-feature
)bundle exec rake rspec
# --- or ---
bundle exec rspec
bundle exec rake rubocop
# --- or ---
bundle exec rubocop
bundle exec rake rubcoop -A
# --- or ---
bundle exec rubocop -A
Released under MIT License.
FAQs
Unknown package
We found that smart_types 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.
Security News
/Research
Malicious npm package impersonates Nodemailer and drains wallets by hijacking crypto transactions across multiple blockchains.
Security News
This episode explores the hard problem of reachability analysis, from static analysis limits to handling dynamic languages and massive dependency trees.
Security News
/Research
Malicious Nx npm versions stole secrets and wallet info using AI CLI tools; Socket’s AI scanner detected the supply chain attack and flagged the malware.