userpattern 0.2.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1,5 @@
1
+ # frozen_string_literal: true
2
+
3
+ module UserPattern
4
+ VERSION = '0.2.0'
5
+ end
@@ -0,0 +1,28 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'openssl'
4
+
5
+ module UserPattern
6
+ # Persists threshold violations with an anonymized user identifier.
7
+ # The raw user ID is NEVER stored — only a one-way HMAC hash.
8
+ class ViolationRecorder
9
+ def self.record!(violation)
10
+ Violation.create!(
11
+ model_type: violation.model_type,
12
+ endpoint: violation.endpoint,
13
+ period: violation.period,
14
+ count: violation.count,
15
+ limit: violation.limit,
16
+ user_identifier: anonymize_user_id(violation.user_id, violation.model_type),
17
+ occurred_at: Time.current
18
+ )
19
+ rescue StandardError => e
20
+ Rails.logger.error("[UserPattern] Violation record error: #{e.message}")
21
+ end
22
+
23
+ def self.anonymize_user_id(user_id, model_type)
24
+ salt = UserPattern.configuration.anonymous_salt
25
+ OpenSSL::HMAC.hexdigest('SHA256', salt, "#{model_type}:#{user_id}")[0, 16]
26
+ end
27
+ end
28
+ end
@@ -0,0 +1,66 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'userpattern/version'
4
+ require 'userpattern/configuration'
5
+
6
+ module UserPattern
7
+ class << self
8
+ def configuration
9
+ @configuration ||= Configuration.new
10
+ end
11
+
12
+ def configure
13
+ yield(configuration)
14
+ end
15
+
16
+ def buffer
17
+ @buffer ||= begin
18
+ require 'userpattern/buffer'
19
+ Buffer.new
20
+ end
21
+ end
22
+
23
+ attr_reader :threshold_cache, :rate_limiter
24
+
25
+ def start_alert_mode!
26
+ require 'userpattern/threshold_cache'
27
+ require 'userpattern/rate_limiter'
28
+
29
+ @threshold_cache = ThresholdCache.new
30
+ store = configuration.rate_limiter_store || default_cache_store
31
+ @rate_limiter = RateLimiter.new(store: store, threshold_cache: @threshold_cache)
32
+ end
33
+
34
+ def enabled?
35
+ configuration.enabled
36
+ end
37
+
38
+ def cleanup!
39
+ require 'userpattern/request_event_cleanup'
40
+ RequestEventCleanup.run!
41
+ end
42
+
43
+ def reset!
44
+ @buffer&.shutdown
45
+ @threshold_cache&.shutdown
46
+ @configuration = Configuration.new
47
+ @buffer = nil
48
+ @threshold_cache = nil
49
+ @rate_limiter = nil
50
+ end
51
+
52
+ private
53
+
54
+ def default_cache_store
55
+ if defined?(Rails) && Rails.respond_to?(:cache) && Rails.cache
56
+ Rails.cache
57
+ else
58
+ ActiveSupport::Cache::MemoryStore.new
59
+ end
60
+ end
61
+ end
62
+ end
63
+
64
+ # :nocov:
65
+ require 'userpattern/engine' if defined?(Rails::Engine)
66
+ # :nocov:
metadata ADDED
@@ -0,0 +1,97 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: userpattern
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.2.0
5
+ platform: ruby
6
+ authors:
7
+ - UserPattern Contributors
8
+ bindir: bin
9
+ cert_chain: []
10
+ date: 1980-01-02 00:00:00.000000000 Z
11
+ dependencies:
12
+ - !ruby/object:Gem::Dependency
13
+ name: concurrent-ruby
14
+ requirement: !ruby/object:Gem::Requirement
15
+ requirements:
16
+ - - ">="
17
+ - !ruby/object:Gem::Version
18
+ version: '1.1'
19
+ type: :runtime
20
+ prerelease: false
21
+ version_requirements: !ruby/object:Gem::Requirement
22
+ requirements:
23
+ - - ">="
24
+ - !ruby/object:Gem::Version
25
+ version: '1.1'
26
+ - !ruby/object:Gem::Dependency
27
+ name: rails
28
+ requirement: !ruby/object:Gem::Requirement
29
+ requirements:
30
+ - - ">="
31
+ - !ruby/object:Gem::Version
32
+ version: '7.0'
33
+ type: :runtime
34
+ prerelease: false
35
+ version_requirements: !ruby/object:Gem::Requirement
36
+ requirements:
37
+ - - ">="
38
+ - !ruby/object:Gem::Version
39
+ version: '7.0'
40
+ description: Track and analyze endpoint usage patterns of logged-in users with full
41
+ anonymization. Provides a sortable dashboard with per-model-type frequency statistics.
42
+ email: []
43
+ executables: []
44
+ extensions: []
45
+ extra_rdoc_files: []
46
+ files:
47
+ - LICENSE
48
+ - README.md
49
+ - app/assets/stylesheets/user_pattern/dashboard.css
50
+ - app/controllers/user_pattern/dashboard_controller.rb
51
+ - app/models/user_pattern/request_event.rb
52
+ - app/models/user_pattern/violation.rb
53
+ - app/views/user_pattern/dashboard/index.html.erb
54
+ - app/views/user_pattern/dashboard/violations.html.erb
55
+ - config/routes.rb
56
+ - lib/generators/userpattern/install_generator.rb
57
+ - lib/generators/userpattern/templates/create_userpattern_request_events.rb.erb
58
+ - lib/generators/userpattern/templates/create_userpattern_violations.rb.erb
59
+ - lib/generators/userpattern/templates/initializer.rb
60
+ - lib/tasks/userpattern.rake
61
+ - lib/userpattern.rb
62
+ - lib/userpattern/anonymizer.rb
63
+ - lib/userpattern/buffer.rb
64
+ - lib/userpattern/configuration.rb
65
+ - lib/userpattern/controller_tracking.rb
66
+ - lib/userpattern/engine.rb
67
+ - lib/userpattern/path_normalizer.rb
68
+ - lib/userpattern/rate_limiter.rb
69
+ - lib/userpattern/request_event_cleanup.rb
70
+ - lib/userpattern/stats_calculator.rb
71
+ - lib/userpattern/threshold_cache.rb
72
+ - lib/userpattern/threshold_exceeded.rb
73
+ - lib/userpattern/version.rb
74
+ - lib/userpattern/violation_recorder.rb
75
+ homepage: https://github.com/userpattern/userpattern
76
+ licenses:
77
+ - MIT
78
+ metadata:
79
+ rubygems_mfa_required: 'true'
80
+ rdoc_options: []
81
+ require_paths:
82
+ - lib
83
+ required_ruby_version: !ruby/object:Gem::Requirement
84
+ requirements:
85
+ - - ">="
86
+ - !ruby/object:Gem::Version
87
+ version: '3.2'
88
+ required_rubygems_version: !ruby/object:Gem::Requirement
89
+ requirements:
90
+ - - ">="
91
+ - !ruby/object:Gem::Version
92
+ version: '0'
93
+ requirements: []
94
+ rubygems_version: 3.6.7
95
+ specification_version: 4
96
+ summary: Anonymized usage pattern analysis for Rails applications
97
+ test_files: []