Security News
Research
Data Theft Repackaged: A Case Study in Malicious Wrapper Packages on npm
The Socket Research Team breaks down a malicious wrapper package that uses obfuscation to harvest credentials and exfiltrate sensitive data.
Have you ever worked on code that evolves so quickly that not only it gives you anxiety, but becomes technical debt over time?
Apparatus is a very simple architectural way to solve this. It uses composition over inheritance and is a (very) simple ECS (entity-component-system) implementation.
It decouples data and logic.
It ensures your complex code parts are highly structured and easy to understand and modify:
Only use this gem for the business logic that is very volatile:
gem install apparatus
Add the following to your Gemfile:
gem "apparatus"
Let's build code that outputs delivery methods to the standard output. We have a imaginary cart and three shipping methods.
require "apparatus"
# aliases (optional)
Entity = Apparatus::Entity
System = Apparatus::System
# component classes
Type = Struct.new(:value)
Name = Struct.new(:value)
Identifier = Struct.new(:value)
Price = Struct.new(:value)
WeightInKg = Struct.new(:value)
Boolean = Struct.new(:value)
# entities
delivery = Entity.new({
type: Type.new("delivery_method"),
identifier: Identifier.new("delivery"),
name: Name.new("Delivery by courier"),
price: Price.new(3.99)
})
pickup = Entity.new({
type: Type.new("delivery_method"),
identifier: Identifier.new("pickup"),
name: Name.new("Pickup in closest store"),
price: Price.new(0.0)
})
pigeon = Entity.new({
type: Type.new("delivery_method"),
identifier: Identifier.new("pigeon"),
name: Name.new("Delivery by pigeon"),
price: Price.new(50.0)
})
cart = Entity.new({
type: Type.new("cart"),
total_price: Price.new(27.0),
total_weight: WeightInKg.new(5.0)
})
# systems
class PrintShippingMethods < System
def run
entities.each do |entity|
next if !entity.has?(:type, :price)
next if entity[:type].value.to_s != "delivery_method"
name, price, enabled = entity[:name], entity[:price], entity[:enabled]
next if enabled && !enabled.value
puts "#{name.value} (#{price.value} €)"
end
end
end
class EnableDeliveryMethods < System
def run
cart = entities.find { _1.has?(:type) && _1[:type].value.to_s == "cart" }
return if !cart
delivery_methods = entities.select do |entity|
entity.has?(:type, :identifier) &&
entity[:type].value.to_s == "delivery_method"
end
delivery_methods.each do |delivery_method|
delivery_method[:enabled] = delivery_method[:identifier].value.to_s == "pigeon" ?
Boolean.new(cart[:total_weight].value < 0.1) :
Boolean.new(true)
end
end
end
# apparatus itself
apparatus = Apparatus::Body.new
apparatus.add_entities(delivery, pickup, pigeon, cart)
apparatus.add_systems(
EnableDeliveryMethods,
PrintShippingMethods
)
# run all systems
apparatus.run
If you run this code, the output is following:
Delivery by courier (3.99)
Pickup in closest store (0.0)
Delivery by pigeon is missing, because the cart weight is too heavy and pigeon cannot bring you (imaginary) package.
However if you comment the line EnableDeliveryMethods,
and run the code again, the output changes to:
Delivery by courier (3.99)
Pickup in closest store (0.0)
Delivery by pigeon (50.0)
I think you should notice some positive things about the basic example:
Struct
, but it can be anything: custom class, String, Integer, etc.puts
or byebug
)This is not THE SOLUTION.
This gem is not meant to be used always, everywhere. It shines when you have suspicion that the incoming feature will be extremely volatile (business logic will change a lot or complexity will grow, there might be a lot of feature requests, etc).
If you check the source code of this gem, it is absurdly simple. However, with simplicity come the drawbacks:
There are alternatives that have a lot more features:
After checking out the repo, run bin/setup
to install dependencies. Then, run make check
to run the checks (rubocop + tests). You can also run bin/console
for an interactive prompt that will allow you to experiment.
To install this gem onto your local machine, run bundle exec rake install
. To release a new version, update the version number in version.rb
, and then run bundle exec rake release
, which will create a git tag for the version, push git commits and the created tag, and push the .gem
file to rubygems.org.
Bug reports and pull requests are welcome on GitHub at https://github.com/pirminis/apparatus.
The gem is available as open source under the terms of the MIT License.
FAQs
Unknown package
We found that apparatus 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
The Socket Research Team breaks down a malicious wrapper package that uses obfuscation to harvest credentials and exfiltrate sensitive data.
Research
Security News
Attackers used a malicious npm package typosquatting a popular ESLint plugin to steal sensitive data, execute commands, and exploit developer systems.
Security News
The Ultralytics' PyPI Package was compromised four times in one weekend through GitHub Actions cache poisoning and failure to rotate previously compromised API tokens.