Advertisement · 728 × 90
#
Hashtag
#Ransack
Advertisement · 728 × 90

Kickback
Body: G1 Ransack
Color: FOC Kickback
#kickback #ransack #transformers

1 0 0 1
Post image Post image

Voilà je suis venu à bout de cette villa rustica devenue ferme du haut moyen-âge. Il y a plein de trucs à prendre en compte, c'est un kit assez exigeant.

#pillage #DarkAges #miniaturepainting #Ransack

perrysheroes.free.fr/spip.php?art...

3 1 0 0
Post image Post image

Voici quelques photos de mon moulin à eau basé sur une grange de Sarissa Precision modifiée. La rivière est une création de Poland Games.

perrysheroes.free.fr/spip.php?art...

#pillage #Ransack #DarkAges #miniaturepainting

7 2 0 0
Post image Post image

Mes deux bandes pour le jeu de figurines Pillage passent à 750pts.

perrysheroes.free.fr/spip.php?art...

perrysheroes.free.fr/spip.php?art...

#DarkAges #pillage #Ransack #miniaturepainting

5 1 0 0
Post image

J'ai terminé mes renforts scandinaves pour Pillages avec ces 15 anciennes figurines Artizan Designs.

perrysheroes.free.fr/spip.php?art...

#DarkAges #miniaturepainting #pillage #Ransack

7 1 0 0

Une fois terminées, j'aurais deux bandes de vikings près pour aller piller les côtes de Franquie et affronter mes carolingiens dans une mini campagne dynamique à venir.

#miniaturepainting #Ransack #pillage #DarkAges

0 0 0 0
Post image Post image

Bien avancé (mais pas terminé) la peinture des 15 guerriers nordiques pour renforcer mes bandes scandinaves pour Pillage. L'objectif est de les divervisifier avec guerriers sans armure avec une arme de base. J'ai ajouté quelques hirdmen en armure.

#miniaturepainting #Ransack #pillage #DarkAges

2 1 1 0
Post image Post image

Et voilà un premier lot de clôtures en clayonnage terminé. J'ai préféré les floquer que de continuer à les assembler car j'étais à cours de colle. J'en ai profité pour mettre les chèvres et sangliers peints avant.
perrysheroes.free.fr/spip.php?art...
#darkages #MiniaturePainting #pillage #Ransack

2 0 0 0
Post image Post image Post image

Travaux du week-end, des chèvres, des sangliers et des clôtures en clayonnage (Renedra) pour habiller les fermes.

#miniaturepainting #pillage #darkages #ransack

0 0 0 0
Post image Post image

Mon troupeau de moutons pour Pillage est terminé! beeeeh!

J'ai hâte de tester son influence sur une partie.

perrysheroes.free.fr/spip.php?art...

#miniaturepainting #pillage #Ransack

2 0 1 0
Post image Post image Post image

J'ai pu prendre des photos de tous les éléments de la ferme de 1st Corps disponibles dans la boutique de www.pillagewargame.com

perrysheroes.free.fr/spip.php?art...

#pillage #miniaturepainting #Ransack

1 0 0 0
Post image Post image Post image

2e lot de la ferme du haut Moyen-âge terminé. Bâtiments 1st Corps miniatures.

#miniaturepainting #Ransack #pillage

0 0 0 0
Post image Post image

Ca méritera de meilleures photos mais le premier lot est vernis et floqué. Retournons au 2e.

#miniaturepainting #pillage #Ransack

2 0 0 0
Post image Post image Post image

Le premier lot va passer à la phase de vernissage avant de décorer certains socles. Ensuite le 2e lot.

#miniaturepainting #pillage #Ransack

1 0 0 0
Post image Post image

Premiers tests de mise en peinture avant d'attaquer le gros.

#miniaturepainting #pillage #ransack

0 0 0 0
Post image Post image Post image

Ransack

#ToyPhotography #ToyRobots #ToyswillbeToys #Transformers #Transformers40 #actionfigures #itsnotadollitsanactionfigure #plasticcrack #Hasbro #RevengeoftheFallen #Ransack

3 0 0 0
Video

Cat burglars at your service 😸😽😻

"Oh no, my house is in a mess!" 😱

#cats #ransack

29 6 1 1
Post image Post image

#ransack
#thundercracker

6 0 1 0
Post image

Venom/Venin is the Only New Deluxe Insecticon Figure I'll ever Get

#Transformers #Insecticons #Decepticons #Venom #Venin #Ransack #Barrage #Maccadam #TransformersLegacy #Memes #TransformersGenerations #ChopShop #Hasbro

1 1 1 0
Post image Post image Post image Post image

Ransack

#ToyPhotography #ToyRobots #ToyswillbeToys #Transformers #Transformers40 #actionfigures #itsnotadollitsanactionfigure #plasticcrack #Hasbro #Transformers #RevengeoftheFallen #Ransack

1 0 0 0
Yes, I will not rest until all the Decepticons from Cybertron have been turned into food or drink.This is Unicron's dream! In the meantime, remove your thirst!

Yes, I will not rest until all the Decepticons from Cybertron have been turned into food or drink.This is Unicron's dream! In the meantime, remove your thirst!

Yes,I will not rest until all the Decepticons from Cybertron have been turned into food or drink.This is Unicron's dream!In the meantime, remove your thirst!🥃🥤🧊
#maccadam
#TransformersCybertron
#Transformersgalaxyforce
#Unicrontrilogy
#Ransack
#Cola
#Decepticons

7 0 0 0
Video

The Cybertron toy line had a weird mix of unposeable and very poseable figures. Ransack is one of the better poseable ones.

#Transformers #TransformersCybertron #Decepticons #Ransack #Velocitron #ToysAtWork

0 0 0 0
Video

Couple of end of day videos of Cybertron Ransack! Gotta love the shiny paint and translucent red~

#Transformers #TransformersCybertron #Decepticons #Ransack #Velocitron #ToysAtWork

0 0 1 0
Video

Ransack was a fun design. It's not easy to make a robot that can turn into a sleek motorcycle. His robot mode is great for poseability, but has some awkward design choices. Still fun!

#Transformers #TransformersCybertron #Decepticons #Ransack #Velocitron #ToysAtWork

0 0 0 0
Video

Brought a vintage (oh god) Transformers Cybertron Ransack to work!

#Transformers #TransformersCybertron #Decepticons #Ransack #Velocitron #ToysAtWork

0 2 2 0
7 найкращих бібліотек (gems) Ruby on Rails для покращення вашого веб-розробки <p>Ruby on Rails — потужний фреймворк, який пропонує безліч вбудованих функцій і можливостей. Однак є кілька гемів, які можна додати до проекту на Rails для ще більшого вдосконалення веб-розробки. У цій статті ми розглянемо сім популярних і корисних гемів, які не є рідними для Rails, але можуть додати додаткові можливості вашим додаткам.</p> <h2>1. Devise</h2> <p>Devise — це гем для аутентифікації, який спрощує процес створення аутентифікації в додатках Rails. Він надає такі функції, як вхід, реєстрація, відновлення пароля і багато іншого, дозволяючи вам швидко та безпечно додавати аутентифікацію до ваших проектів.</p> <p>Посилання: <a href="https://github.com/heartcombo/devise">https://github.com/heartcombo/devise</a></p> <h2>2. ActiveAdmin</h2> <p>ActiveAdmin — це гем, який пропонує інтерфейс адміністратора для ваших додатків Rails. З ним ви можете швидко створювати кастомізовану панель управління для керування моделями та даними бази даних, економлячи час і зусилля на розробку адміністративних функцій.</p> <p>Посилання: <a href="https://github.com/activeadmin/activeadmin">https://github.com/activeadmin/activeadmin</a></p> <h2>3. Pundit</h2> <p>Pundit — це гем для контролю доступу, який дозволяє визначати чіткі та гнучкі політики авторизації в ваших додатках Rails. Він надає систему дозволів, основану на об'єктах, що полегшує визначення правил доступу та захист ресурсів залежно від дозволів користувача.</p> <p>Посилання: <a href="https://github.com/varvet/pundit">https://github.com/varvet/pundit</a></p> <h2>4. Sidekiq</h2> <p>Sidekiq — це гем для обробки завдань у фоновому режимі, який допомагає виконувати тривалі завдання у фоні, зберігаючи реактивність вашого додатку Rails. Він використовує Redis як бекенд і надає ефективний та масштабований спосіб обробки завдань у фоні.</p> <p>Посилання: <a href="https://github.com/mperham/sidekiq">https://github.com/mperham/sidekiq</a></p> <h2>5. Kaminari</h2> <p>Kaminari — це гем, який спрощує пагінацію колекцій даних у ваших додатках Rails. Він надає прості та інтуїтивно зрозумілі методи для поділу великих наборів результатів на кілька сторінок, дозволяючи користувачам ефективно переміщатися по даних.</p> <p>Посилання: <a href="https://github.com/kaminari/kaminari">https://github.com/kaminari/kaminari</a></p> <h2>6. Ransack</h2> <p>Ransack — це гем для пошуку та фільтрації в додатках Rails. Він дозволяє створювати складні форми пошуку, де користувачі можуть визначати фільтри для пошуку записів на основі конкретних критеріїв. За допомогою Ransack ви можете генерувати складні SQL-запити легко та інтуїтивно, без необхідності писати SQL-код вручну. Він також надає функції, такі як сортування результатів, пошук за асоціаціями та підтримка AJAX для оновлення результатів в реальному часі.</p> <p>Посилання: <a href="https://github.com/activerecord-hackery/ransack">https://github.com/activerecord-hackery/ransack</a></p> <h2>7. Omniauth</h2> <p>Omniauth — це гем для аутентифікації через сторонні сервіси в додатках Rails. Він спрощує процес інтеграції з зовнішніми постачальниками аутентифікації, такими як Facebook, Google, Twitter та іншими. З Omniauth ви можете дозволити користувачам входити в ваш додаток, використовуючи свої акаунти в соціальних мережах, роблячи процес реєстрації та входу зручнішим.</p> <p>Посилання: <a href="https://github.com/omniauth/omniauth">https://github.com/omniauth/omniauth</a></p> <p>Ці додаткові геми можуть принести додаткові можливості та полегшити розробку додатків на Rails. Завдяки таким функціям, як пагінація даних і аутентифікація через сторонні сервіси, ви можете покращити досвід користувачів і прискорити розробку вашого проекту. Скористайтеся цими потужними гемами для створення більш ефективних і повних додатків на Rails.</p> <p>А якщо вам цікаво дізнатися більше про веб-розробку та програмування, ознайомтеся з моїми іншими статтями <a href="https://javascript.org.ua/@williamlopes.dev">тут на Medium</a>.<br/> Слідкуйте за останніми тенденціями, порадами та основними патернами проектування, щоб вдосконалити свої навички як розробник. Підемо разом цим шляхом до досконалості у світі програмування!</p> <p>Перекладено з: <a href="https://medium.com/@williamlopes.dev/as-7-principais-gems-do-ruby-on-rails-para-aprimorar-seu-desenvolvimento-web-eebc19d529cb">As 7 Principais Gems do Ruby on Rails para Aprimorar seu Desenvolvimento Web</a></p>

7 найкращих бібліотек (gems) Ruby on Rails для покращення вашо...

javascript.org.ua/7-najkrashhih-bibliotek-...

#Blog #rails #ransack

Event Attributes

0 0 0 0
Preview
Заміна Elasticsearch на Meilisearch у Rails за допомогою Docker <p><img alt="pic" decoding="async" src="https://drive.javascript.org.ua/985c31c3671_GHsNVJCoYiYW6Qf83ZHQZA_png"/></p> <p><em>Розумний вибір для додатків з простими потребами в пошуку</em></p> <p>Elasticsearch — це всебічний і висококонфігурований пошуковий двигун і система зберігання для багатьох завдань в додатках. У цій статті ми порівняємо лише його можливості пошуку в контексті Dockerized додатку на Ruby on Rails. Якщо ваш додаток має потребу в специфічному підвищенні ваги атрибутів, результатах, які поліпшуються за допомогою машинного навчання, розвинених можливостях шардінгу з високою доступністю або пошуку по кількох індексах, Elasticsearch — це саме те, що вам потрібно.</p> <p>Якщо ваші потреби в пошуку знаходяться між pg_search/ransack і Elasticsearch, Meilisearch — новий претендент, який працює дуже швидко (&lt;50ms), значно ефективніший у використанні ресурсів, має розумну конфігурацію за замовчуванням, власну бібліотеку для Ruby і гем для Rails, а також панель адміністратора, де можна спробувати пошук перед повною інтеграцією в додаток. З повнотекстовим пошуком, синонімами, толерантністю до помилок, стоп-словами і налаштовуваними правилами релевантності, Meilisearch має достатньо функцій, щоб задовольнити потреби більшості додатків — і це ще до їх релізу v1.0 👏. Пошук по кількох індексах також знаходиться на <a href="https://roadmap.meilisearch.com/tabs/4-in-progress">дорожній карті</a>.</p> <h2>Частина нуль: Але чому?</h2> <p><img alt="pic" decoding="async" src="https://drive.javascript.org.ua/503b7a48d61_1xVIzjzgJnmuWTJoaG3kAQ_gif"/></p> <p><em>Чому варто пройти через труднощі зміни? Продуктивність та ефективність використання ресурсів!</em></p> <p>Спочатку давайте порівняємо Elasticsearch і Meilisearch за показником, за яким ви, ймовірно, прийшли — використанням ресурсів. Пам'ять в хмарі коштує дорого, і Elasticsearch відомий тим, що споживає багато пам'яті. На моєму додатку на Rails, який має досить низьке навантаження, він використовує 3,5 ГБ. Це на 2,7 ГБ більше, ніж наступний за величиною контейнер, в якому працюють веб-робітники Rails, що використовують malloc замість jemalloc (це тема для іншої статті!).</p> <p>Отже, наскільки ефективніший Meilisearch? Спочатку давайте встановимо базовий рівень з Elasticsearch. Ми будемо використовувати <a href="https://docs.meilisearch.com/movies.json">цю базу даних фільмів</a> з ~32k рядків.</p> <p>Тут треба зауважити, що налаштування Elasticsearch зайняло набагато більше часу. Він спочатку відмовився запускатися, бо йому потрібно було більше пам'яті, ніж ОС дозволяла виділити лише для запуску. Цю межу потрібно було збільшити за допомогою <code>sysctl -w vm.max_map_count=262144</code>. Потім JSON файл потребував значних маніпуляцій, оскільки bulk JSON API вимагає вказувати індекс <strong>для кожного рядка</strong>. Це не було очевидно з документації, і <a href="https://stackoverflow.com/a/52225439/1686604">стара відповідь на StackOverflow</a> прийшла мені на допомогу.</p> <pre><code>docker network create elastic docker run --name es01 --net elastic -p 9200:9200 -p 9300:9300 -it docker.elastic.co/elasticsearch/elasticsearch:8.2.3curl --location --request POST '[https://localhost:9200/movies/_bulk/'](https://localhost:9200/movies/_bulk/') \ --header 'Content-Type: application/x-ndjson' \ --header 'Authorization: Basic ---' \ --data-binary '@movies.json' </code></pre> <p><code>docker stats</code> показує, що Elasticsearch використовує <strong>5,2 ГБ пам'яті</strong>. Додавання фільмів до індексу не збільшило це — він використовує 5,2 ГБ за замовчуванням без даних. Ви, звісно, можете налаштувати <code>ES_JAVA_OPTS</code> і зменшити це. Однак навіть для маленьких додатків є ризик, що контейнери будуть евіковані через високий тиск на пам'ять. Це була основна причина, чому я вирішив ознайомитися з Meilisearch.</p> <p>Тепер давайте зробимо те ж саме з Meilisearch. Налаштування було значно простіше, і bulk імпорт був безтурботним.</p> <pre><code>docker run --rm -p 7700:7700 -v "$(pwd)/meili_data:/meili_data" getmeili/meilisearchcurl -i -X POST 'http://127.0.0.1:7700/indexes/movies/documents' \ --header 'content-type: application/json' \ --data-binary @movies.json </code></pre> <p>Через кілька хвилин роботи Meilisearch, використання пам'яті фактично зменшилося до <strong>96,7 МБ</strong>.</p> <p>Тепер давайте проведемо просте порівняння. Ми запустимо 100 ітерацій <code>q=batman&amp;limit=10</code> для Meilisearch та <code>?q=batman&amp;size=10</code> для Elasticsearch.</p> <p><strong>Elasticsearch: середнє 9,68мс, пікове 15мс.</strong><br/> <strong>Meilisearch: 5.17ms середнє значення. 11ms пікове значення.</strong></p> <p><strong>Meilisearch використовує в 54.8 рази менше пам'яті і був на 46.6% швидший за Elasticsearch при однакових даних і запитах.</strong></p> <p><img alt="pic" decoding="async" src="https://drive.javascript.org.ua/02ecac8d071_JdDfBF36W6NwIHWthqVCZw_gif"/></p> <p><em>Це значно швидше і набагато легше для хостингу.</em></p> <p>Зображення також займає 36MB замість 1.2GB — круто. Зверніть увагу, що це порівняння <strong>за умовчанням</strong> конфігурацій. Що ще важливо, Meilisearch має інтерфейс на localhost:7700, тому нам навіть не потрібно відкривати Postman для тестування (вибачте, зараз немає фільтрації чи сортування в адміністративному інтерфейсі).</p> <p>Переконані? Тоді читайте далі, і я покажу, як виглядала міграція з Elasticsearch на Meilisearch для реального виробничого додатка — <a href="https://scribehub.com">ScribeHub</a>. Ми також перейшли від чудової бібліотеки <a href="https://github.com/ankane/searchkick">Searchkick</a> від Ankane до офіційної бібліотеки <a href="https://github.com/meilisearch/meilisearch-rails">meilisearch-rails</a>, і я покажу зміни, які ми зробили.</p> <h2>Частина перша: DevOps</h2> <p>Почнімо з того, що замінимо контейнер Elasticsearch на контейнер Meilisearch у вашому файлі docker-compose.yml:</p> <pre><code>meilisearch: image: getmeili/meilisearch:v0.27.0 user: root ports: - "7700:7700" volumes: - "meili:/meili_data/" env_file: - .msenv...volumes: meili: </code></pre> <p>Перша велика відмінність — це автентифікація. Meilisearch підтримує пряме інтегрування з фронтендом, яке навіть не торкається Rails (класно!). Це означає, що якщо встановлено головний ключ, він автоматично генерує стандартні ключі з конкретними правами доступу під час запуску. Якщо ви просто пробуєте Meilisearch локально, я рекомендую не встановлювати головний ключ, щоб дозволити неавтентифіковані запити. Якщо ви плануєте запускати на продакшн, я рекомендую встановити головний ключ, щоб зрозуміти, як це працює, перед запуском. Ми не будемо розглядати лише фронтенд реалізації в цій статті — зосередимося лише на міграції з ES на MS.</p> <p>Що змусило мене <a href="https://github.com/meilisearch/meilisearch-rails/issues/148">майже здатися</a> на самому початку, так це те, що сервіс MS буде генерувати нові ключі, якщо буде <strong>будь-яка</strong> зміна у його файлі середовища. Я постійно додавав стандартний адміністративний ключ у спільний файл .env, через що ключі генерувалися знову, і я отримував помилки автентифікації під час повторної індексації. Це повинно відбуватися тільки при зміні головного ключа, але генерування ключів при будь-яких змінах у файлі середовища означає, що <strong>для сервісу MS потрібно мати окремий файл середовища</strong>. Я назвав його '.msenv', як ви бачите вище. Я бачив, як ключі генерувалися навіть тоді, коли файл середовища не змінювався, але це було наслідком того, що я не монтував каталог до /meili_data.</p> <p>Якщо ви встановлюєте головний ключ, виконайте команду <code>SecureRandom.hex 32</code> у консолі Rails і вставте його в <code>MEILI_MASTER_KEY</code> у файлі .msenv. Ви також можете налаштувати хост і вимкнути анонімну аналітику, що, на мою думку, має бути вимкнено за замовчуванням. Ось мій приклад файлу .msenv:</p> <pre><code># УВАГА # Кожного разу, коли в цей файл вносяться зміни, Meilisearch генерує нові ключі. # Це призведе до анулювання поточних ключів і зробить вас сумними. MEILISEARCH_HOST=http://meilisearch:7700 MEILI_MASTER_KEY= MEILI_NO_ANALYTICS=true </code></pre> <p>Виконайте команду <code>docker-compose up</code>, і ви повинні побачити це виведення при запуску MS:</p> <blockquote> <p>Головний ключ встановлено. Запити до Meilisearch не будуть авторизовані, якщо ви не надасте ключ автентифікації.</p> </blockquote> <p>Тепер нам потрібно отримати стандартний адміністративний API-ключ. Ось запит curl для отримання ключів. Я рекомендую зберегти запит у Postman або Insomnia, щоб не доводилося постійно його шукати.</p> <pre><code>curl --location --request GET 'http://localhost:7700/keys' \ --header 'Authorization: Bearer ' </code></pre> <p>Вставте стандартний адміністративний API-ключ у <code>MEILISEARCH_API_KEY</code> у файлі .env вашого Rails додатка і встановіть <code>MEILISEARCH_HOST</code> на те саме значення, яке ви встановили в .msenv, щоб воно було доступне і в Rails.<br/> Час написати файл ініціалізації для Meilisearch! Ви можете налаштувати таймоути та кількість спроб під час налаштування.</p> <pre><code>MeiliSearch::Rails.configuration = { meilisearch_host: ENV['MEILISEARCH_HOST'], meilisearch_api_key: ENV['MEILISEARCH_API_KEY'], timeout: 1, max_retries: 2 } </code></pre> <p>Перезапустіть все, щоб зміни в середовищі набули чинності, і тепер ви повинні мати можливість повторно індексувати модель з урахуванням дозволів. Але спочатку нам потрібна модель для повторного індексування.</p> <h2>Частина друга: Інтеграція з Rails</h2> <p>Ось де мій шлях і ваш можуть відрізнятися, але я надам приклад інтеграції моделі. Оскільки ScribeHub має багато ресурсів для пошуку, я написав concern. schema_searchable.rb:</p> <pre><code>module SchemaSearchable extend ActiveSupport::Concern included do include MeiliSearch::Rails extend Pagy::Meilisearch end module ClassMethods def trigger_sidekiq_job(record, remove) MeilisearchEnqueueWorker.perform_async(record.class.name, record.id, remove) end end end </code></pre> <p>Це дозволило уникнути дублювання коду для Elasticsearch, але я завжди радий зменшенню обсягу коду. Тепер ви можете додавати <code>include SchemaSearchable</code> до будь-якої моделі, яку потрібно індексувати. Ось приклад додатків до нашої моделі GlossaryTerm:</p> <pre><code>after_touch :index!meilisearch enqueue: :trigger_sidekiq_job, per_environment: true, primary_id: :ms_id do attributes [:account_id, :id, :term, :definition, :updated] attribute :updated do updated_at.to_i end filterable_attributes [:account_id] enddef ms_id "gt_#{account_id}_#{id}" end </code></pre> <p>Зверніть увагу, що Meilisearch не має типу даних для об'єктів дати та часу Ruby чи Rails, тому ми перетворюємо це на Unix epoch за допомогою <code>to_i</code>. <code>after_touch :index!</code> дозволяє підтримувати індекс актуальним, коли модель змінюється. <code>per_environment: true</code> гарантує, що ви не забрудните свої індекси для розробки тестовими даними. <code>enqueue</code> запускає оновлення індексу у фоновому режимі відповідно до методу, визначеного в schema<em>searchable.rb — але нам ще потрібен цей worker. Ось meilisearch</em>enqueue_worker.rb:</p> <pre><code>class MeilisearchEnqueueWorker include Sidekiq::Worker def perform(klass, record_id, remove) if remove klass.constantize.index.delete_document(record_id) else klass.constantize.find(record_id).index! end end end </code></pre> <p>Якщо ви можете запустити нову консолі Rails і виконати <code>Model.reindex!</code> без помилок, то ви готові редагувати дію індексації у контролері. Зараз, використовуючи <a href="https://ddnexus.github.io/pagy/extras/meilisearch#active-mode">метод пошуку active pagy</a> без створення запиту N+1, нам потрібно використовувати обидва <code>pagy_meilisearch</code> і <code>pagy_search</code> ось так:</p> <pre><code>def index @pagy, @glossary_terms = pagy_meilisearch( GlossaryTerm.includes(GlossaryTerm.search_includes).pagy_search( params[:q], **{ filter: "account_id = #{current_account.id}" } ) ) end </code></pre> <p>Метод <code>search_includes</code> в <code>GlossaryTerm</code> просто повертає список асоціацій, які потрібні для уникнення запитів N+1. Мені подобається тримати це в моделі:</p> <pre><code>def self.search_includes %i( user ) end </code></pre> <p>Збір рядка <code>filter</code> може бути складнішим порівняно з Elasticsearch, оскільки це рядок, а не хеш, але це дає можливість складати логіку з будь-якою кількістю <code>AND</code> і <code>OR</code>, які тільки хочеться. Для таких випадків, як фільтрація за тегами з логікою AND, вам слід зробити ось так:</p> <pre><code>filter = "discarded=false" if @conditions.key?(:tags) @conditions[:tags].each do |tag| filter += " AND tags='#{tag}'" end end </code></pre> <p>У цьому випадку <code>@conditions</code> — це хеш, який заповнюється обробкою запиту для витягнення таких елементів, як теги та сортування для упорядкування. Документація має <a href="https://docs.meilisearch.com/learn/advanced/filtering_and_faceted_search.html#filter-expressions">корисні примітки щодо поєднання логіки</a>.</p> <p>Залишилося тільки виправити тести, і в основному це зводиться до заміни <code>index</code> на <code>index!</code> і <code>search_index.delete</code> на <code>clear_index!</code>.<br/> Було дуже круто бачити, як тести знову проходять після такої невеликої кількості виправлень у тестах.</p> <p>Сподіваюсь, вам сподобалося! Ми точно отримали задоволення тут, в <a href="https://scribehub.com">ScribeHub</a>, і з нетерпінням чекаємо на пошук по кількох індексах 😉.</p> <p>Перекладено з: <a href="https://medium.com/devops-dev/swapping-elasticsearch-for-meilisearch-in-rails-feat-docker-5eefab0b9971">Swapping Elasticsearch for Meilisearch in Rails feat. Docker</a></p>

Заміна Elasticsearch на Meilisearch у Rails за допомогою Docker Розумн...

javascript.org.ua/zamina-elasticsearch-na-...

#Blog #rails #ransack

Event Attributes

1 0 0 0
Тестування вебхуків Stripe в середовищі розробки <p>Інтеграція Stripe з будь-яким фреймворком є легкою. Stripe надає дуже хорошу документацію для інтеграції та тестування.</p> <p>Сьогодні я хотів би обговорити тестування вебхуків Stripe в середовищі розробки. Досить важко знайти документацію, що стосується тестування вебхуків у середовищі розробки.</p> <p>Я довго боровся, намагаючись протестувати події вебхуків на моєму локальному комп'ютері!</p> <p>Існує кілька способів тестування вебхуків.</p> <ul> <li>Ultrahook</li> <li>Ngrok</li> <li>stripe-cli</li> </ul> <p>Я покажу, як протестувати вебхуки Stripe, використовуючи stripe-cli з фреймворком Ruby on Rails.</p> <blockquote> <p>Версія Rails: Rails 5.1.7</p> <p>Версія Ruby: ruby 2.4.2p198</p> </blockquote> <p>Я припускаю, що ви вже інтегрували Stripe у вашому додатку.</p> <h2>У вас має бути файл stripe.rb у <em>config/initializers/stripe.rb.</em></h2> <p>Цей файл використовується для виконання користувацького коду на певні події Stripe.</p> <pre><code>Stripe.api_key = ENV['STRIPE_API_KEY']StripeEvent.signing_secret = ENV['STRIPE_SIGNING_SECRET'] StripeEvent.configure do |events| events.subscribe 'customer.subscription.deleted' do |event| # Напишіть ваш власний код, який ви хочете виконати при події видалення підписки end end </code></pre> <p>У наведеному прикладі STRIPE<em>API</em>KEY — це ключ для інтеграції з Stripe.</p> <p>STRIPE<em>SIGNING</em>SECRET — це підписаний секрет, який використовується для зв'язку зі Stripe через точку доступу Ultrahook або через stripe-cli.</p> <p>Значення STRIPE<em>SIGNING</em>SECRET буде різним для кожного з цих з'єднань.</p> <p>Вам потрібно зберігати STRIPE<em>API</em>KEY у файлі <strong>.env</strong> або, якщо ви тестуєте за допомогою будь-якої тестової системи, вказувати його в файлі <strong>.env.test</strong>.</p> <p>Перший крок — це встановити stripe-cli на вашому локальному комп'ютері.</p> <p>Перегляньте <a href="https://stripe.com/docs/stripe-cli">https://stripe.com/docs/stripe-cli</a>, щоб дізнатися, як встановити stripe-cli.</p> <p>Згідно з документацією, щоб активувати події Stripe, вам потрібно увійти за допомогою облікових даних Stripe. Однак ми розглянемо, як протестувати події Stripe без облікових даних для входу.</p> <p>Спочатку потрібно почати прослуховування сервера Stripe за допомогою stripe-cli.</p> <pre><code>stripe listen --api-key ENV[‘STRIPE_API_KEY’]&gt; Ready! Your webhook signing secret is **whsec_P3rrta1iba57AbetSBEjGeLJT27AIAx1** (^C to quit) </code></pre> <p>Скопіюйте згенерований код підпису секрету в змінну середовища STRIP<em>SIGNING</em>SECRET.</p> <p>Другий крок — це перенаправити всі події вебхуків на localhost.</p> <pre><code>stripe listen — forward-to localhost:3000/hooks --api-key ENV[‘STRIPE_API_KEY’] </code></pre> <p>Це прослуховуватиме події Stripe та передаватиме їх на localhost.</p> <p>Якщо ви визначили власні маршрути для вебхуків, вам потрібно вказати цей шлях замість <strong><em>/hooks.</em></strong></p> <p>Третій крок — запустити ваш сервер Rails.</p> <pre><code>rails s </code></pre> <p>Останній крок — це викликати подію Stripe.</p> <pre><code>stripe trigger customer.subscription.deleted --api-key ENV[‘STRIPE_API_KEY’] </code></pre> <p>Ця команда ініціює подію видалення підписки користувача, і всі зворотні виклики будуть направлені на “localhost:3000/hooks”</p> <p>Ура! Вона виконає код, написаний у файлі stripe.rb.</p> <p>Перекладено з: <a href="https://trispatel.medium.com/testing-stripe-webhooks-in-development-environment-21a26157be69">Testing Stripe Webhooks in Development Environment</a></p>

Тестування вебхуків Stripe в середовищі розробки Інтег...

javascript.org.ua/testuvannya-vebhukiv-str...

#Blog #rails #ransack

Event Attributes

0 0 0 0
Особливості Cloudinary <p><strong>Cloudinary — це система SaaS для керування та доставки медіа для додатків та вебсайтів.</strong></p> <p>Cloudinary безкоштовний до певного розміру трансформації та зберігання. Деталі цін можна знайти за посиланням у розділі References.</p> <p>Є кілька причин, чому варто використовувати Cloudinary для завантаження зображень замість інших хмарних сховищ.</p> <ul> <li><strong>Динамічний вибір найефективнішого формату</strong></li> <li><strong>Автоматичне регулювання якості стиснення</strong></li> <li><strong>Автоматичне масштабування та обрізка зображень відповідно до макету сторінки</strong></li> <li><strong>Динамічне перемикання між кількома CDN</strong></li> <li><strong>Динамічне створення URL для доставки, дружнього до SEO</strong></li> <li><strong>Підтримує майже всі популярні розробницькі фреймворки.</strong></li> <li><strong>Копіювання зображень на льоту з інших джерел.</strong></li> </ul> <p>Сьогодні ми обговоримо одну функцію, яка може заощадити ваш час.</p> <h2><strong>Копіювання зображень на льоту з інших джерел.</strong></h2> <p>Копіювання зображень з одного хмарного сховища в інше завжди є трудомістким завданням. Але з Cloudinary це дуже просто.</p> <p>Перед міграцією спершу потрібно надати права Cloudinary для копіювання зображень з вихідного хмарного сховища. Це може бути Google Cloud Storage, S3 тощо.</p> <pre><code>.wellknown/cloudinary/ </code></pre> <p>Ви зможете отримати назву вашого хмари в акаунті Cloudinary.</p> <p>Додавши цей файл до вашого вихідного хмари, ви надаєте Cloudinary авторизацію на копіювання зображень з хмари.</p> <p>Cloudinary має функцію авто-завантаження, за допомогою якої ми можемо вказати URL, з якого хочемо копіювати зображення в Cloudinary. Деталі, як вказати URL для копіювання зображень з джерела, можна знайти за посиланням в розділі References.</p> <p>Хороша новина: це не копіює всі зображення відразу. Коли хтось вперше завантажує сторінку, зображення буде скопійовано з джерела та вставлено у ваш акаунт Cloudinary.</p> <p>Однак є один момент, на який слід звернути увагу: якщо ви копіюєте вже трансформоване зображення, це може вплинути на якість зображення, оскільки Cloudinary знову трансформує зображення на основі браузера та розміру пристрою.</p> <p>Також ви можете вказати папку, в яку хочете скопіювати всі зображення.</p> <h2>Коли не слід використовувати Cloudinary?</h2> <p>Для зберігання сирих файлів, таких як .xls, .pdf, .txt тощо, не слід використовувати Cloudinary. Оскільки Cloudinary створює трансформацію для всього, що ви завантажуєте. Тобто, припустимо, ви завантажуєте 1 PDF файл, який містить 11 сторінок, тоді Cloudinary створить 11 нових трансформацій, плюс оригінал. Якщо ви хочете відображати сторінки вашого PDF у форматі зображень, то Cloudinary корисний, в іншому випадку це буде зайве використання трансформацій і обмеження простору.</p> <p>Я люблю Cloudinary!</p> <p>Залишайтеся на зв'язку!</p> <p>У наступному блозі я покажу, як обробляти зображення за допомогою Rails + ActiveStorage + Cloudinary.</p> <p>References:</p> <p><a href="https://support.cloudinary.com/hc/en-us/articles/203276521-How-do-I-allow-Cloudinary-to-read-from-my-private-S3-bucket-">https://support.cloudinary.com/hc/en-us/articles/203276521-How-do-I-allow-Cloudinary-to-read-from-my-private-S3-bucket-</a></p> <p><a href="https://cloudinary.com/documentation/fetch_remote_images#:%7E:text=The%20auto%2Dupload%20feature%20enables,for%20further%20management%20and%20manipulation">https://cloudinary.com/documentation/fetch<em>remote</em>images#:~:text=The%20auto%2Dupload%20feature%20enables,for%20further%20management%20and%20manipulation</a>.</p> <p><a href="https://cloudinary.com/pricing?utm_expid=.HzgzPplvQFixcNLVwMtd4A.0&amp;utm_referrer=https%3A%2F%2Fcloudinary.com%2F">https://cloudinary.com/pricing?utm<em>expid=.HzgzPplvQFixcNLVwMtd4A.0&amp;utm</em>referrer=https%3A%2F%2Fcloudinary.com%2F</a> для деталей ціноутворення</p> <p>Перекладено з: <a href="https://trispatel.medium.com/features-of-cloudinary-6945bae1b782?source=follow_footer---------0----------------------------">Features of Cloudinary</a></p>

Особливості Cloudinary Cloudinary — це система SaaS для керуванн...

https://javascript.org.ua/osoblivosti-cloudinary/

#Blog #rails #ransack

Event Attributes

0 0 0 0
Preview
Solidus — Огляд коду <p><a href="https://www.tenable.com/research">Як дослідник в Tenable</a>, ми маємо кілька періодів протягом року, коли можна працювати над темою на свій вибір, за умови, що це представляє інтерес для команди. Особисто я вирішив провести огляд коду на проекті Ruby on Rails.</p> <p>Основна мета — зосередитись на перевірці коду, його розумінні та взаємодії між компонентами.</p> <p>Я обрав <a href="https://github.com/solidusio/solidus">Solidus</a>, який є відкритим фреймворком для електронної комерції для піонерів галузі. Спочатку цей проект був форком <a href="https://spreecommerce.org/">Spree</a>.</p> <p>Розроблений на основі <a href="https://rubyonrails.org/">Ruby on Rails</a>, Solidus складається з кількох гемів. Коли ви підключаєте гем solidus у вашому Gemfile, Bundler встановить всі наступні геми:</p> <ul> <li><strong>solidus_api</strong> (RESTful API)</li> <li><strong>solidus_backend</strong> (Адмін-панель)</li> <li><strong>solidus_core</strong> (Основні моделі, поштові системи та класи)</li> <li><strong>solidus_sample</strong> (Приклад даних)</li> </ul> <p>Всі ці геми створені для того, щоб працювати разом, надаючи повноцінну платформу для електронної комерції.</p> <p><img alt="pic" decoding="async" src="https://drive.javascript.org.ua/7d2f5d004d0_i8FqnnSpOhzb_ATo"/></p> <p><em>https://www.tenable.com/research</em></p> <h2>Вибір проекту</h2> <p>Solidus не був моїм першим вибором, я спочатку хотів вибрати <a href="https://github.com/zammad/zammad">Zammad</a>, який є веб-системою підтримки клієнтів з відкритим кодом, також розробленою на Ruby on Rails.</p> <p>Проект досить популярний, і, після швидкого огляду, має хороший потенціал для атак. Цей тип проектів також цікавий, бо для багатьох бізнесів компонент підтримки/тестування критичний, тому виявлення вразливості в проекті на кшталт Zammad майже гарантовано забезпечить цікаву вразливість!</p> <p>З різних причин, чи то на моєму професійному, чи то на особистому ноутбуці, мені потрібно запускати проект у Docker, що сьогодні досить поширено для веб-проектів, але:</p> <p><img alt="pic" decoding="async" src="https://drive.javascript.org.ua/26d459b7750_Ns5cuW1MTPzc8RuH"/></p> <p>Zammad — це проект, що потребує багатьох компонентів, таких як Elasticsearch, Memcached, PostgresQL і Redis. І хоча проект надає готовий docker-compose, як тільки я спробував використовувати його в режимі розробки, проект не ініціалізувався належним чином.</p> <p>Замість того, щоб витрачати занадто багато часу, я вирішив відкласти його на потім (безсумнівно) і вибрати інший проект, який здався простішим для старту.</p> <p>Переглядаючи Github, я натрапив на <a href="https://github.com/solidusio/solidus">Solidus</a>, який не тільки пропонує інструкції для налаштування середовища розробки всього в кількох рядках, але й має <a href="https://github.com/solidusio/solidus/security">деякі публічні вразливості</a>.</p> <p>Для нас це загалом хороший знак з точки зору комунікації у разі виявлення проблем. Це показує, що видавець готовий до обміну, що, на жаль, не завжди так.</p> <p><em>Насправді, я також мав кілька проблем з Dockerfile для Solidus, але переглянувши</em> <a href="https://github.com/solidusio/solidus/issues/5523"><em>issues</em></a> <em>та зробивши деякі модифікації самостійно, я зміг швидко запустити проект.</em></p> <p><img alt="pic" decoding="async" src="https://drive.javascript.org.ua/1602bafc790_fGZcRMCQZi1TRVev"/></p> <p><em>Проект запустився за допомогою команди bin/dev</em></p> <h2>Архітектура Ruby on Rails та поверхня для атак</h2> <p>Як і багато веб-фреймворків, Ruby on Rails використовує архітектуру MVC, хоча це не є темою цього блогу, короткий нагадування не завадить, щоб ви краще зрозуміли решту:</p> <ul> <li><strong>Модель</strong> містить дані та логіку, що стосується цих даних (перевірка, реєстрація тощо)</li> <li><strong>Представлення</strong> показує результат користувачу</li> <li><strong>Контролер</strong> обробляє дії користувача та змінює дані моделі і представлення<br/> Це є зв’язок між моделлю та представленням.</li> </ul> <p>Ще один важливий аспект Ruby on Rails — це те, що цей фреймворк керується принципом “<em>Конвенція понад конфігурацію</em>”, що означає, що багато рішень прийнято за вас, і що всі середовища будуть мати схожості, що полегшує розуміння проекту з точки зору атакувальника, якщо ви знаєте, як працює фреймворк.</p> <p>У проекті Ruby on Rails маршрутизація застосунку керується безпосередньо файлом ‘config/routes.rb’. У цьому файлі визначено всі можливі дії!</p> <p>Як було пояснено в розділі огляду, Solidus складається з набору гемів (Core, Backend та API), розроблених для того, щоб працювати разом і забезпечити повноцінну платформу для електронної комерції.</p> <p>Ці три компоненти незалежні один від одного, тому коли ми перевіряємо проект Github Solidus/Solidus, ми фактично перевіряємо кілька проектів з різними поверхнями атак, які більш чи менш взаємопов’язані.</p> <p>Solidus має три основних файли маршрутів:</p> <ul> <li><strong>Admin</strong> Простір імен <strong>SolidusAdmin::Engine</strong></li> <li><strong>Backend</strong> Простір імен <strong>Spree::Core::Engine</strong></li> <li><strong>API</strong> Простір імен <strong>Spree::Core::Engine</strong></li> </ul> <p><img alt="pic" decoding="async" src="https://drive.javascript.org.ua/4329f5696e0_G3CQJAokzidUG77X"/></p> <p>Два з трьох файлів знаходяться в одному просторі імен, тоді як Admin є більш відокремленим.</p> <p>Простір імен можна розглядати як “групу”, що містить класи, константи чи інші модулі. Це дозволяє структурувати ваш проект. Тут важливо розуміти, що API та Backend безпосередньо пов’язані, але не можуть взаємодіяти безпосередньо з Admin.</p> <p>Якщо ми уважніше подивимось на файл, то побачимо, що маршрути визначені кількома способами. Не вдаючись у всі деталі та нюанси, ви можете визначити маршрут безпосередньо, наприклад:</p> <pre><code>get '/orders/mine', to: 'orders#mine', as: 'my_orders' </code></pre> <p>Це означає “Запит GET на /orders/mine” буде надіслано до методу “mine” контролера “Orders” (ми не будемо звертати увагу на “as: ‘my_orders’” тут).</p> <pre><code>module Spree module Api class OrdersController &lt; Spree::Api::BaseController #[...] def mine if current_api_user @orders = current_api_user.orders.by_store(current_store).reverse_chronological.ransack(params[:q]).result @orders = paginate(@orders) else render "spree/api/errors/unauthorized", status: :unauthorized end end #[...] </code></pre> <p>Або через систему CRUD, використовуючи щось на кшталт:</p> <pre><code>resources :customer_returns, except: :destroy </code></pre> <p>Для пояснень я перейду безпосередньо до того, що пояснюється в <a href="https://guides.rubyonrails.org/routing.html#crud-verbs-and-actions">документації Ruby on Rails</a>:</p> <p><em>“У Rails ресурсний маршрут забезпечує відповідність між HTTP дієсловами та URL для дій контролера. За умовчанням кожна дія також відповідає конкретній операції CRUD в базі даних.”</em></p> <p>Отже, тут ресурс :customer_returns буде зв’язаний з контролером CustomerReturns для таких URL:</p> <ul> <li>GET /customer_returns</li> <li>GET /customer_returns/new</li> <li>POST /customer_returns</li> <li>GET /customer_returns/:id</li> <li>GET /customer_returns/:id/edit</li> <li>PATCH/PUT /customer_returns/:id</li> <li>̶D̶E̶L̶E̶T̶E̶ ̶/̶c̶u̶s̶t̶o̶m̶e̶r̶_̶r̶e̶t̶u̶r̶n̶s̶/̶:̶i̶d̶ ігнорується через “except: :destroy”</li> </ul> <p>Отже, з цього можна легко побачити, що Solidus має значну поверхню для атак.</p> <h2>Статичний аналіз коду</h2> <p>Цей проект також дає мені можливість протестувати різні інструменти для статичного аналізу коду.<br/> Я не очікую багато від цих інструментів, але оскільки я не використовую їх регулярно, це дозволяє мені побачити, що нового і що розвивається.</p> <p>Перевага відкритого проекту на Github полягає в тому, що багато інструментів для статичного аналізу можна запустити через Github Action, принаймні… теоретично.</p> <p>Не рахуючи всіх перевірених інструментів, CodeQL — єдиний, який я зміг запустити “з коробки” через Github Action, результати потім безпосередньо видні у вкладці Security.</p> <p><img alt="pic" decoding="async" src="https://drive.javascript.org.ua/a99d4dd7f20_7WLG7fjAtZk4uoIo"/></p> <p><em>Витяг з вразливостей, виявлених за допомогою CodeQL</em></p> <p>Обробка результатів від усіх інструментів займає багато часу, багато з них є зайвими, і я також спостерігав, що деякі платні інструменти насправді є лише обгортками відкритих інструментів, таких як Semgrep (результати точно такі ж / ті ж самі фрази).</p> <p>Особливе згадування заслуговує <a href="https://brakemanscanner.org/">Brakeman</a>, інструмент, присвячений аналізу коду Ruby on Rails. Цей інструмент дозволяє швидко і просто знайти деякі цікаві шляхи для дослідження у зручному вигляді.</p> <p><img alt="pic" decoding="async" src="https://drive.javascript.org.ua/517dfc3c470_D6jojsGQAUQIE1qF"/></p> <p><em>Витяг з вразливостей, виявлених за допомогою Brakeman</em></p> <p>Не розглядаючи всі відкриття, які я відкинув (шляхи для дослідження). Деякі вразливості легко виключити. Наприклад, виявлення “Поліноміальний регулярний вираз, використаний на неконтрольованих даних” від CodeQL:</p> <p><img alt="pic" decoding="async" src="https://drive.javascript.org.ua/42f2facdc50_i6TO2ZMDY0xZkpg9"/></p> <p>Окрім того, що це здається неексплуатованим для мене, цей випадок не є дуже цікавим, оскільки він стосується адміністративної частини, і для його використання потрібні підвищені привілеї.</p> <p>Тепер розглянемо цей приклад “SQL Injection” від Brakeman:</p> <p><img alt="pic" decoding="async" src="https://drive.javascript.org.ua/a6afa077f60_JNF6ZwqMqCY_5bPt"/></p> <p>Оскільки аналіз позбавлений контексту, він не знає, що насправді “price<em>table</em>name” не відповідає введенню користувача, а є викликом методу, який повертає назву таблиці (яка, отже, не піддається контролю з боку користувача).</p> <p>Проте ці інструменти залишаються цікавими, оскільки вони можуть надати швидкий огляд областей для подальшого дослідження.</p> <h2>Ідентифікація сайту на Solidus</h2> <p>Перед тим як зануритися в деталі теми, може бути цікаво визначити, чи використовує відвіданий сайт Solidus, і для цього існує кілька методів.</p> <p>На головній сторінці магазину можна шукати такі патерни:</p> <pre><code>Powered by Solidus /assets/spree/frontend/solidus_starter_frontend </code></pre> <p>Або перевірити, чи доступні такі функції JS:</p> <pre><code>Solidus() SolidusPaypalBraintree </code></pre> <p>Або, врешті-решт, відвідати адміністративну панель, доступну за адресою ‘/admin/login’, і шукати один з наступних патернів:</p> <p><img alt="pic" decoding="async" src="https://drive.javascript.org.ua/30b5f989510_ynR9rblX5RW8MwAb"/></p> <p>Після того як замовлення зроблено, дії користувача досить обмежені</p> <ul> <li>Переглянути свої замовлення</li> <li>Переглянути конкретне замовлення (але без PDF або відстеження)</li> <li>Оновити свою інформацію (тільки email і пароль)</li> </ul> <p><img alt="pic" decoding="async" src="https://drive.javascript.org.ua/3e25cbb88c1_lebfVb2hVW7tJQTHVQm5gA_png"/></p> <p>Додамо, що коли замовлення оформлено, користувачеві надсилається email, а новий email відправляється, коли продукт відправлено.</p> <p><img alt="pic" decoding="async" src="https://drive.javascript.org.ua/86497b435c1_fBKW7bBE2EMT3zjKFx0W_A_png"/></p> <p>Адміністративна панель також досить обмежена, окрім класичних функцій інтернет-магазину (управління замовленнями, продуктами, запасами тощо), є лише невелика кількість налаштувань, які можна зробити безпосередньо з панелі.</p> <p><img alt="pic" decoding="async" src="https://drive.javascript.org.ua/cc22197f650_bgYMdTe_o9clx2_u"/></p> <p>Наприклад, неможливо налаштувати SMTP, це налаштування потрібно робити безпосередньо в конфігурації Rails проекту.</p> <p><img alt="pic" decoding="async" src="https://drive.javascript.org.ua/670421214e0_eeIZWgFJ1nD5FlOu"/></p> <h2>Аутентифікація та управління сесіями</h2> <p>Аутентифікація є важливим аспектом безпеки веб-додатків. Вона гарантує, що лише авторизовані особи мають доступ до функцій додатку та чутливої інформації.</p> <p>Devise — це популярний, високонастроюваний та надійний Ruby on Rails gem для аутентифікації користувачів. Цей gem забезпечує повне рішення для управління аутентифікацією, включаючи створення акаунтів, вхід, вихід та скидання паролю.</p> <p>Однією з причин, чому Devise вважається надійним рішенням, є його здатність підтримувати розширені функції безпеки, такі як перевірка email, двофакторна аутентифікація та управління сесіями. Крім того, Devise регулярно оновлюється для виправлення вразливостей безпеки та покращення своїх функцій.</p> <p>Коли я налаштовував свій проект Solidus, була використана версія 4.9.3 Devise, тобто остання доступна версія, тому я не витратив багато часу на цю частину, яка одразу здавалася мені тупиковою.</p> <h2>Авторизація та управління дозволами</h2> <p>Авторизація та управління дозволами — ще один критично важливий аспект безпеки веб-додатків. Вона гарантує, що користувачі мають доступ лише до тих функцій та даних, до яких їм дозволено доступати на основі їх ролі чи дозволів.</p> <p>За замовчуванням, Solidus має лише дві визначені ролі:</p> <ul> <li><strong>SuperUser</strong>: Тобто адміністратор, який має доступ до всіх функцій</li> <li><strong>DefaultCustomer</strong>: Роль, яка за замовчуванням присвоюється під час реєстрації, базова роль, яка просто дозволяє робити покупки на сайті</li> </ul> <p>Для управління цією частиною, Solidus використовує gem під назвою <a href="https://github.com/CanCanCommunity/cancancan">CanCanCan</a>. Як і Devise, CanCanCan вважається надійним рішенням завдяки здатності підтримувати складні сценарії авторизації, такі як ієрархічні ролі та динамічні дозволи. Крім того, CanCanCan дуже настроюється.</p> <p>Також, CanCanCan добре протестований та надійний, що робить його безпечним вибором для критичних застосунків.<br/> Він також має активну спільноту розробників, які можуть надати допомогу та поради, якщо це необхідно.</p> <h2>Декілька цікавих тем</h2> <p><strong>1/ Не дуже цікаве міжсайтове скриптування (Cross-Site Scripting)</strong></p> <p>Знаходити вразливості — це цікаво, особливо якщо вони критичні, але багато статей не пояснюють, що пошук займає багато часу, і багато спроб не призводять до результату.</p> <p>Розкопуючи ці вразливості, навіть знаючи, що вони не приведуть до нічого, не завжди марно.</p> <p>Візьмемо, наприклад, виявлення Brakeman:</p> <p><img alt="pic" decoding="async" src="https://drive.javascript.org.ua/7164066fac0_wgMgix95_ZOqnDT5"/></p> <p>Незважаючи на наявність <code>:target =&gt; “_blank”</code>, що ускладнює використання XSS (або через божевільні комбінації, такі як колесо миші), мені було цікаво розібратися в цій частині коду і зрозуміти, як можна здійснити таку ін'єкцію, просто тому, що це стосується адміністративної частини.</p> <p>Ось як можна було б експлуатувати цю вразливість:</p> <p>1/ Адміністратор повинен змінити методи доставки, щоб додати <code>javascript:alert(document.domain)</code> як URL для відстеження.</p> <p>2/ Користувач повинен оформити замовлення.</p> <p>3/ Адміністратор повинен підтвердити замовлення та додати номер для відстеження.</p> <p>4/ URL для відстеження буде відповідати payload, який можна буде активувати через колесо миші.</p> <p><img alt="pic" decoding="async" src="https://drive.javascript.org.ua/497976144c0_Hp3ggZq5itg8QJHT"/></p> <p>За замовчуванням, оскільки єдиною можливістю є роль адміністратора, єдина можливість — це коли один адміністратор заманює іншого адміністратора... іншими словами, це далеко не цікаво.</p> <p><strong>Примітка:</strong> Згідно з <a href="https://guides.solidus.io/advanced-solidus/permission-management">документацією Solidus</a>, у налаштуванні, яке відрізняється від базового, користувач з меншими привілеями міг би експлуатувати цю вразливість.</p> <p><em>Хоча вплив і експлуатація дуже низькі, ми вказали на цю вразливість для Solidus. Незважаючи на кілька спроб зв'язатися з ними, ми не отримали відповіді.<br/> Вразливість була опублікована під</em> <a href="https://www.tenable.com/security/research/tra-2024-15"><em>CVE-2024–4859</em></a></p> <p><strong>2/ Solidus, Машина станів (State Machine) та умови гонки (Race Conditions)</strong></p> <p>У веб-магазині я вважаю, що тестування умов гонки — це корисна річ, оскільки певні функції підходять для такого тесту, наприклад, знижки.</p> <p>Але перед тим, як говорити про умови гонки, потрібно зрозуміти концепцію Машини станів (State Machine).</p> <p>Машина станів — це модель поведінки, що використовується в розробці програмного забезпечення для представлення різних станів, у яких може перебувати об'єкт або система, а також переходів між цими станами. У контексті веб-додатку, машина станів може використовуватися для моделювання різних станів, в яких може перебувати користувач або ресурс, а також дій, які можуть бути виконані для переходу між цими станами.</p> <p>Наприклад, у Solidus користувачі можуть оформляти замовлення. Користувач може бути в одному з кількох станів щодо замовлення, таких як "очікує", "обробляється" або "відправлено". Машина станів визначатиме ці стани та переходи між ними, такі як "оформити замовлення" (що переходить з "очікує" в "обробляється"), "відмінити замовлення" (що повертає з "обробляється" в "очікує"), та "відправити замовлення" (що переходить з "обробляється" в "відправлено").</p> <p>Використання машини станів у веб-додатку дає кілька переваг. По-перше, це допомагає забезпечити стабільність і передбачуваність роботи додатку, оскільки поведінка системи чітко визначена та контролюється. По-друге, це полегшує розуміння додатку та відлагодження проблем, оскільки стан системи можна легко перевірити та зрозуміти.<br/> По-третє, це може допомогти спростити кодову базу, оскільки складну логіку можна інкапсулювати в машині станів (State Machine).</p> <p>Якщо я говорю про це, то тому, що <a href="https://guides.solidus.io/advanced-solidus/state-machines/">документація Solidus має розділ, присвячений цьому</a>, і я вважаю, що це досить рідко виділяється!</p> <p>Тепер ми можемо спробувати подивитися, чи є приховані умови гонки (Race Conditions) у використанні промо-коду.</p> <p>Цей розділ коду все ще належить Spree (попереднику Solidus), тому я одразу не зміг до нього дістатися, але в разі whitebox-аудиту іноді легше відслідкувати код через помилку на сайті.</p> <p>У цьому випадку, при дворазовому застосуванні того самого промо-коду, сайт виводить помилку “The coupon code has already been applied to this order”</p> <p><img alt="pic" decoding="async" src="https://drive.javascript.org.ua/4fafc6760c0_RkuZUHH2n40CH3ap"/></p> <p>Тоді просто шукаємо цю помилку в усьому коді проекту і відслідковуємо її використання назад до методу, який перевіряє використання купона.</p> <p><img alt="pic" decoding="async" src="https://drive.javascript.org.ua/24578727eb0_p5DItaV8W1sBftJY"/></p> <p><img alt="pic" decoding="async" src="https://drive.javascript.org.ua/e9339e83490_UvSbkGbur0MVSo0N"/></p> <p>Досить важко вникнути в деталі та пояснити всі перевірки, але можна підсумувати, що купон асоціюється з конкретним замовленням, і як тільки ми намагаємось застосувати новий купон, код перевіряє, чи вже асоційований він із замовленням чи ні.</p> <p>Отже, підсумовуючи, цей код не виглядав вразливим до умов гонки (Race Conditions).</p> <p>Представлення всіх проведених тестів було б нудним, але з цих рядків ми розуміємо, що основні будівельні блоки Solidus досить надійні, і на стандартній установці, на жаль, мені не вдалося знайти багато чого цікавого.</p> <p>Тож, можливо, цікавіше зосередитись на кастомних розробках, зокрема на розширеннях. У Solidus можна організувати розширення за трьома типами:</p> <ul> <li><strong>Офіційні інтеграції:</strong> <a href="https://solidus.io/integrations">Перелічено на основному сайті</a>, здебільшого це розширення для обробки платежів</li> <li><strong>Розширення від спільноти:</strong> Перелічено в окремому репозиторії на GitHub, це різноманітні розширення, які більш-менш підтримуються</li> <li><strong>Інші розширення:</strong> Розширення, знайдені в інших місцях, але немає гарантії, що вони працюватимуть або будуть підтримуватись</li> </ul> <p>Майже всі офіційні розширення потребують інтеграції з третіми сторонами і тому робитимуть запити до сторонніх сервісів, чого я хотів уникнути тут.</p> <p>Замість цього я звернувся до розширень від спільноти, щоб протестувати кілька розширень, для яких мені б хотілося мати рідну функціональність на сайті, наприклад, експорт рахунків у форматі PDF.</p> <p>Для цього я знайшов плагін <a href="https://github.com/solidusio-contrib/solidus_print_invoice/">Solidus Print Invoice</a>, який не підтримується вже 2 роки. Можна було б подумати, що це хороший знак з точки зору атакувальника, але насправді цей плагін не призначений для роботи з Solidus 4, тому першим кроком було зробити його сумісним, щоб його можна було встановити...</p> <p>Як вказано в документації, цей плагін додає лише генерацію PDF на стороні адміністратора.</p> <p><img alt="pic" decoding="async" src="https://drive.javascript.org.ua/321e5d16260_QKaSuQikNquWSS6L"/></p> <p>Довго не розповідаючи, цей плагін не дав мені нічого нового, і я витратив більше часу на його встановлення, ніж на розуміння того, що я не отримаю від нього жодних вразливостей.</p> <p>Я ще не перевіряв це, але цікаво зазначити, що інші плагіни, такі як <a href="https://github.com/friendlycart/solidus_friendly_promotions">Solidus Friendly Promotions</a>, згідно з документацією, заміняють основні функції Solidus, і тому вони природно більш схильні до виникнення вразливостей.</p> <h2>Висновок</h2> <p>Представлення всіх тестів, які можуть бути проведені, також займає занадто багато часу.<br/> Аналіз коду справді займає багато часу, тому стверджувати, що я повністю проаналізував всю програму, було б неправдою. Але, після кількох днів роботи з Solidus, я думаю, що це дуже цікава програма з точки зору безпеки.</p> <p>Звісно, я б хотів детально описати кілька вразливостей, але цей блог-пост намагається показати, що не завжди можна отримати результат.</p> <p>Перекладено з: <a href="https://medium.com/tenable-techblog/solidus-code-review-7e9b606a5c10">Solidus — Code Review</a></p>

Solidus — Огляд коду Як дослідник в Tenable, ми маємо кілька ...

https://javascript.org.ua/solidus-oglyad-kodu/

#Blog #rails #ransack

Event Attributes

0 0 0 0