thuban 0.4.12 → 0.4.13
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.
- package/dist/cli.js +1 -1
- package/dist/package.json +1 -1
- package/dist/packages/crucible/rules/code-scanner-core.json +11 -0
- package/dist/packages/scanner/ghost-code-detector.js +1 -1
- package/package.json +1 -1
- package/dist/packages/crucible/seeds/python/seed-021 2.py +0 -37
- package/dist/packages/crucible/seeds/python/seed-022 2.py +0 -34
- package/dist/packages/crucible/seeds/python/seed-023 2.py +0 -37
- package/dist/packages/crucible/seeds/python/seed-024 2.py +0 -38
- package/dist/packages/crucible/seeds/python/seed-025 2.py +0 -40
- package/dist/packages/crucible/seeds/python/seed-026 2.py +0 -35
- package/dist/packages/crucible/seeds/python/seed-027 2.py +0 -35
- package/dist/packages/crucible/seeds/python/seed-028 2.py +0 -42
- package/dist/packages/crucible/seeds/python/seed-030 2.py +0 -37
- package/dist/packages/crucible/seeds/python/seed-031 2.py +0 -34
- package/dist/packages/crucible/seeds/python/seed-036 2.py +0 -33
- package/dist/packages/crucible/seeds/python/seed-037 2.py +0 -41
- package/dist/packages/crucible/seeds/python/seed-038 2.py +0 -33
- package/dist/packages/crucible/seeds/python/seed-039 2.py +0 -39
- package/dist/packages/crucible/seeds/python/seed-040 2.py +0 -39
- package/dist/packages/crucible/seeds/python/seed-041 2.py +0 -37
- package/dist/packages/crucible/seeds/python/seed-042 2.py +0 -38
- package/dist/packages/crucible/seeds/python/seed-043 2.py +0 -32
- package/dist/packages/crucible/seeds/python/seed-044 2.py +0 -38
- package/dist/packages/crucible/seeds/python/seed-045 2.py +0 -36
- package/dist/packages/crucible/seeds/python/seed-046 2.py +0 -33
- package/dist/packages/crucible/seeds/python/seed-047 2.py +0 -44
- package/dist/packages/crucible/seeds/python/seed-048 2.py +0 -35
- package/dist/packages/crucible/seeds/python/seed-049 2.py +0 -39
- package/dist/packages/crucible/seeds/python/seed-050 2.py +0 -39
- package/dist/packages/crucible/seeds/python/seed-051 2.py +0 -38
- package/dist/packages/crucible/seeds/python/seed-052 2.py +0 -41
- package/dist/packages/crucible/seeds/ruby/seed-001 2.rb +0 -15
- package/dist/packages/crucible/seeds/ruby/seed-002 2.rb +0 -22
- package/dist/packages/crucible/seeds/ruby/seed-003 2.rb +0 -25
- package/dist/packages/crucible/seeds/ruby/seed-004 2.rb +0 -17
- package/dist/packages/crucible/seeds/ruby/seed-005 2.rb +0 -21
- package/dist/packages/crucible/seeds/ruby/seed-006 2.rb +0 -17
- package/dist/packages/crucible/seeds/ruby/seed-007 2.rb +0 -16
- package/dist/packages/crucible/seeds/ruby/seed-008 2.rb +0 -18
- package/dist/packages/crucible/seeds/ruby/seed-009 2.rb +0 -20
- package/dist/packages/crucible/seeds/ruby/seed-010 2.rb +0 -24
- package/dist/packages/crucible/seeds/ruby/seed-011 2.rb +0 -21
- package/dist/packages/crucible/seeds/ruby/seed-012 2.rb +0 -22
- package/dist/packages/crucible/seeds/ruby/seed-013 2.rb +0 -21
- package/dist/packages/crucible/seeds/ruby/seed-014 2.rb +0 -16
- package/dist/packages/crucible/seeds/ruby/seed-015 2.rb +0 -18
- package/dist/packages/crucible/seeds/ruby/seed-016 2.rb +0 -17
- package/dist/packages/crucible/seeds/ruby/seed-017 2.rb +0 -25
- package/dist/packages/crucible/seeds/ruby/seed-018 2.rb +0 -23
- package/dist/packages/crucible/seeds/ruby/seed-019 2.rb +0 -20
- package/dist/packages/crucible/seeds/ruby/seed-020 2.rb +0 -17
- package/dist/packages/crucible/seeds/ruby/seed-021 2.rb +0 -20
- package/dist/packages/crucible/seeds/ruby/seed-022 2.rb +0 -21
- package/dist/packages/crucible/seeds/ruby/seed-023 2.rb +0 -19
- package/dist/packages/crucible/seeds/ruby/seed-024 2.rb +0 -17
- package/dist/packages/crucible/seeds/ruby/seed-025 2.rb +0 -17
- package/dist/packages/crucible/seeds/ruby/seed-026 2.rb +0 -18
- package/dist/packages/crucible/seeds/ruby/seed-027 2.rb +0 -21
- package/dist/packages/crucible/seeds/ruby/seed-028 2.rb +0 -22
- package/dist/packages/crucible/seeds/ruby/seed-029 2.rb +0 -19
- package/dist/packages/crucible/seeds/ruby/seed-030 2.rb +0 -20
- package/dist/packages/crucible/seeds/ruby/seed-031 2.rb +0 -17
- package/dist/packages/crucible/seeds/ruby/seed-032 2.rb +0 -22
- package/dist/packages/crucible/seeds/ruby/seed-033 2.rb +0 -18
- package/dist/packages/crucible/seeds/ruby/seed-034 2.rb +0 -19
- package/dist/packages/crucible/seeds/ruby/seed-035 2.rb +0 -19
- package/dist/packages/crucible/seeds/ruby/seed-036 2.rb +0 -18
- package/dist/packages/crucible/seeds/ruby/seed-037 2.rb +0 -21
- package/dist/packages/crucible/seeds/ruby/seed-038 2.rb +0 -24
- package/dist/packages/crucible/seeds/ruby/seed-039 2.rb +0 -24
- package/dist/packages/crucible/seeds/ruby/seed-040 2.rb +0 -22
- package/dist/packages/crucible/seeds/ruby/seed-041 2.rb +0 -23
- package/dist/packages/crucible/seeds/ruby/seed-042 2.rb +0 -25
- package/dist/packages/crucible/seeds/ruby/seed-043 2.rb +0 -23
- package/dist/packages/crucible/seeds/ruby/seed-044 2.rb +0 -16
- package/dist/packages/crucible/seeds/ruby/seed-045 2.rb +0 -22
- package/dist/packages/crucible/seeds/ruby/seed-046 2.rb +0 -27
- package/dist/packages/crucible/seeds/ruby/seed-047 2.rb +0 -26
- package/dist/packages/crucible/seeds/ruby/seed-048 2.rb +0 -24
- package/dist/packages/crucible/seeds/ruby/seed-049 2.rb +0 -20
- package/dist/packages/crucible/seeds/ruby/seed-050 2.rb +0 -27
- package/dist/packages/crucible/seeds/rust/seed-001 2.rs +0 -25
- package/dist/packages/crucible/seeds/rust/seed-002 2.rs +0 -20
- package/dist/packages/crucible/seeds/rust/seed-003 2.rs +0 -23
- package/dist/packages/crucible/seeds/rust/seed-004 2.rs +0 -21
- package/dist/packages/crucible/seeds/rust/seed-005 2.rs +0 -21
- package/dist/packages/crucible/seeds/rust/seed-006 2.rs +0 -24
- package/dist/packages/crucible/seeds/rust/seed-007 2.rs +0 -20
- package/dist/packages/crucible/seeds/rust/seed-008 2.rs +0 -19
- package/dist/packages/crucible/seeds/rust/seed-009 2.rs +0 -28
- package/dist/packages/crucible/seeds/rust/seed-010 2.rs +0 -28
- package/dist/packages/crucible/seeds/rust/seed-011 2.rs +0 -25
- package/dist/packages/crucible/seeds/rust/seed-012 2.rs +0 -31
- package/dist/packages/crucible/seeds/rust/seed-013 2.rs +0 -27
- package/dist/packages/crucible/seeds/rust/seed-014 2.rs +0 -30
- package/dist/packages/crucible/seeds/rust/seed-015 2.rs +0 -33
- package/dist/packages/crucible/seeds/rust/seed-016 2.rs +0 -22
- package/dist/packages/crucible/seeds/rust/seed-017 2.rs +0 -28
- package/dist/packages/crucible/seeds/rust/seed-018 2.rs +0 -21
- package/dist/packages/crucible/seeds/rust/seed-019 2.rs +0 -36
- package/dist/packages/crucible/seeds/rust/seed-020 2.rs +0 -27
- package/dist/packages/crucible/seeds/rust/seed-021 2.rs +0 -26
- package/dist/packages/crucible/seeds/rust/seed-022 2.rs +0 -23
- package/dist/packages/crucible/seeds/rust/seed-023 2.rs +0 -22
- package/dist/packages/crucible/seeds/rust/seed-024 2.rs +0 -24
- package/dist/packages/crucible/seeds/rust/seed-025 2.rs +0 -29
- package/dist/packages/crucible/seeds/rust/seed-026 2.rs +0 -23
- package/dist/packages/crucible/seeds/rust/seed-027 2.rs +0 -24
- package/dist/packages/crucible/seeds/rust/seed-028 2.rs +0 -25
- package/dist/packages/crucible/seeds/rust/seed-029 2.rs +0 -25
- package/dist/packages/crucible/seeds/rust/seed-030 2.rs +0 -30
- package/dist/packages/crucible/seeds/rust/seed-031 2.rs +0 -22
- package/dist/packages/crucible/seeds/rust/seed-032 2.rs +0 -25
- package/dist/packages/crucible/seeds/rust/seed-033 2.rs +0 -25
- package/dist/packages/crucible/seeds/rust/seed-034 2.rs +0 -20
- package/dist/packages/crucible/seeds/rust/seed-035 2.rs +0 -28
- package/dist/packages/crucible/seeds/rust/seed-036 2.rs +0 -26
- package/dist/packages/crucible/seeds/rust/seed-037 2.rs +0 -31
- package/dist/packages/crucible/seeds/rust/seed-038 2.rs +0 -25
- package/dist/packages/crucible/seeds/rust/seed-039 2.rs +0 -28
- package/dist/packages/crucible/seeds/rust/seed-040 2.rs +0 -27
- package/dist/packages/crucible/seeds/rust/seed-041 2.rs +0 -32
- package/dist/packages/crucible/seeds/rust/seed-042 2.rs +0 -27
- package/dist/packages/crucible/seeds/rust/seed-043 2.rs +0 -29
- package/dist/packages/crucible/seeds/rust/seed-044 2.rs +0 -25
- package/dist/packages/crucible/seeds/rust/seed-045 2.rs +0 -28
- package/dist/packages/crucible/seeds/rust/seed-046 2.rs +0 -25
- package/dist/packages/crucible/seeds/rust/seed-047 2.rs +0 -34
- package/dist/packages/crucible/seeds/rust/seed-048 2.rs +0 -21
- package/dist/packages/crucible/seeds/rust/seed-049 2.rs +0 -26
- package/dist/packages/crucible/seeds/rust/seed-050 2.rs +0 -23
- package/dist/packages/crucible/seeds/ts/seed-001 2.ts +0 -32
- package/dist/packages/crucible/seeds/ts/seed-002 2.ts +0 -34
- package/dist/packages/crucible/seeds/ts/seed-003 2.ts +0 -28
- package/dist/packages/crucible/seeds/ts/seed-004 2.ts +0 -34
- package/dist/packages/crucible/seeds/ts/seed-005 2.ts +0 -32
- package/dist/packages/crucible/seeds/ts/seed-006 2.ts +0 -31
- package/dist/packages/crucible/seeds/ts/seed-007 2.ts +0 -28
- package/dist/packages/crucible/seeds/ts/seed-008 2.ts +0 -40
- package/dist/packages/crucible/seeds/ts/seed-009 2.ts +0 -31
- package/dist/packages/crucible/seeds/ts/seed-010 2.ts +0 -33
- package/dist/packages/crucible/seeds/ts/seed-011 2.ts +0 -29
- package/dist/packages/crucible/seeds/ts/seed-012 2.ts +0 -34
- package/dist/packages/crucible/seeds/ts/seed-013 2.ts +0 -31
- package/dist/packages/crucible/seeds/ts/seed-014 2.ts +0 -36
- package/dist/packages/crucible/seeds/ts/seed-015 2.ts +0 -31
- package/dist/packages/crucible/seeds/ts/seed-016 2.ts +0 -37
- package/dist/packages/crucible/seeds/ts/seed-017 2.ts +0 -44
- package/dist/packages/crucible/seeds/ts/seed-018 2.ts +0 -33
- package/dist/packages/crucible/seeds/ts/seed-019 2.ts +0 -32
- package/dist/packages/crucible/seeds/ts/seed-020 2.ts +0 -33
- package/dist/packages/crucible/seeds/ts/seed-021 2.ts +0 -33
- package/dist/packages/crucible/seeds/ts/seed-022 2.ts +0 -34
- package/dist/packages/crucible/seeds/ts/seed-023 2.ts +0 -33
- package/dist/packages/crucible/seeds/ts/seed-024 2.ts +0 -35
- package/dist/packages/crucible/seeds/ts/seed-025 2.ts +0 -29
- package/dist/packages/crucible/seeds/ts/seed-026 2.ts +0 -36
- package/dist/packages/crucible/seeds/ts/seed-027 2.ts +0 -30
- package/dist/packages/crucible/seeds/ts/seed-028 2.ts +0 -32
- package/dist/packages/crucible/seeds/ts/seed-029 2.ts +0 -34
- package/dist/packages/crucible/seeds/ts/seed-030 2.ts +0 -37
- package/dist/packages/crucible/seeds/ts/seed-031 2.ts +0 -31
- package/dist/packages/crucible/seeds/ts/seed-032 2.ts +0 -32
- package/dist/packages/crucible/seeds/ts/seed-033 2.ts +0 -32
- package/dist/packages/crucible/seeds/ts/seed-034 2.ts +0 -34
- package/dist/packages/crucible/seeds/ts/seed-035 2.ts +0 -29
- package/dist/packages/crucible/seeds/ts/seed-036 2.ts +0 -34
- package/dist/packages/crucible/seeds/ts/seed-037 2.ts +0 -33
- package/dist/packages/crucible/seeds/ts/seed-038 2.ts +0 -29
- package/dist/packages/crucible/seeds/ts/seed-039 2.ts +0 -35
- package/dist/packages/crucible/seeds/ts/seed-040 2.ts +0 -31
- package/dist/packages/crucible/seeds/ts/seed-041 2.ts +0 -29
- package/dist/packages/crucible/seeds/ts/seed-042 2.ts +0 -33
- package/dist/packages/crucible/seeds/ts/seed-043 2.ts +0 -32
- package/dist/packages/crucible/seeds/ts/seed-044 2.ts +0 -36
- package/dist/packages/crucible/seeds/ts/seed-045 2.ts +0 -39
- package/dist/packages/crucible/seeds/ts/seed-046 2.ts +0 -41
- package/dist/packages/crucible/seeds/ts/seed-047 2.ts +0 -33
- package/dist/packages/crucible/seeds/ts/seed-048 2.ts +0 -33
- package/dist/packages/crucible/seeds/ts/seed-049 2.ts +0 -34
- package/dist/packages/crucible/seeds/ts/seed-050 2.ts +0 -41
- package/dist/packages/crucible/seeds/ts/seed-051 2.ts +0 -34
- package/dist/packages/crucible/seeds/ts/seed-052 2.ts +0 -36
|
@@ -1,22 +0,0 @@
|
|
|
1
|
-
# [CRUCIBLE-SEED]
|
|
2
|
-
# category: ssrf
|
|
3
|
-
# severity: critical
|
|
4
|
-
# language: ruby
|
|
5
|
-
# expected: HTTParty.get with user-supplied URL — SSRF to internal services
|
|
6
|
-
|
|
7
|
-
require 'httparty'
|
|
8
|
-
|
|
9
|
-
class WebhookController < ApplicationController
|
|
10
|
-
def trigger
|
|
11
|
-
callback_url = params[:callback]
|
|
12
|
-
payload = { event: 'triggered', timestamp: Time.now.to_i }
|
|
13
|
-
HTTParty.post(callback_url, body: payload.to_json, headers: { 'Content-Type' => 'application/json' })
|
|
14
|
-
render json: { triggered: true }
|
|
15
|
-
end
|
|
16
|
-
|
|
17
|
-
def preview_url
|
|
18
|
-
url = params[:url]
|
|
19
|
-
resp = HTTParty.get(url, timeout: 5)
|
|
20
|
-
render plain: resp.body
|
|
21
|
-
end
|
|
22
|
-
end
|
|
@@ -1,23 +0,0 @@
|
|
|
1
|
-
# [CRUCIBLE-SEED]
|
|
2
|
-
# category: ssrf
|
|
3
|
-
# severity: critical
|
|
4
|
-
# language: ruby
|
|
5
|
-
# expected: Faraday connection built from user-controlled base URL
|
|
6
|
-
|
|
7
|
-
require 'faraday'
|
|
8
|
-
|
|
9
|
-
class ImportController < ApplicationController
|
|
10
|
-
def import_feed
|
|
11
|
-
source_url = params[:feed_url]
|
|
12
|
-
conn = Faraday.new(url: source_url)
|
|
13
|
-
response = conn.get('/')
|
|
14
|
-
data = JSON.parse(response.body)
|
|
15
|
-
render json: { imported: data.size }
|
|
16
|
-
end
|
|
17
|
-
|
|
18
|
-
def fetch_avatar
|
|
19
|
-
avatar_url = params[:avatar_url]
|
|
20
|
-
response = Faraday.get(avatar_url)
|
|
21
|
-
send_data response.body, type: 'image/jpeg'
|
|
22
|
-
end
|
|
23
|
-
end
|
|
@@ -1,25 +0,0 @@
|
|
|
1
|
-
# [CRUCIBLE-SEED]
|
|
2
|
-
# category: ssrf
|
|
3
|
-
# severity: high
|
|
4
|
-
# language: ruby
|
|
5
|
-
# expected: open-uri used to fetch user-supplied URL — SSRF including file:// scheme
|
|
6
|
-
|
|
7
|
-
require 'open-uri'
|
|
8
|
-
|
|
9
|
-
def fetch_remote_resource(url)
|
|
10
|
-
URI.open(url).read
|
|
11
|
-
end
|
|
12
|
-
|
|
13
|
-
def download_image(image_url)
|
|
14
|
-
URI.open(image_url) do |f|
|
|
15
|
-
File.write('/tmp/downloaded_image', f.read)
|
|
16
|
-
end
|
|
17
|
-
end
|
|
18
|
-
|
|
19
|
-
class ResourceController < ApplicationController
|
|
20
|
-
def import
|
|
21
|
-
resource_url = params[:url]
|
|
22
|
-
content = URI.open(resource_url).read
|
|
23
|
-
render plain: content
|
|
24
|
-
end
|
|
25
|
-
end
|
|
@@ -1,23 +0,0 @@
|
|
|
1
|
-
# [CRUCIBLE-SEED]
|
|
2
|
-
# category: ssrf
|
|
3
|
-
# severity: critical
|
|
4
|
-
# language: ruby
|
|
5
|
-
# expected: RestClient.get with user-supplied URL — SSRF
|
|
6
|
-
|
|
7
|
-
require 'rest-client'
|
|
8
|
-
|
|
9
|
-
class ProxyService
|
|
10
|
-
def self.relay(target_url, headers = {})
|
|
11
|
-
RestClient.get(target_url, headers)
|
|
12
|
-
rescue RestClient::Exception => e
|
|
13
|
-
e.response
|
|
14
|
-
end
|
|
15
|
-
|
|
16
|
-
def self.post_webhook(url, payload)
|
|
17
|
-
RestClient.post(url, payload.to_json, content_type: :json)
|
|
18
|
-
end
|
|
19
|
-
|
|
20
|
-
def self.check_health(host)
|
|
21
|
-
RestClient.get("http://#{host}/health")
|
|
22
|
-
end
|
|
23
|
-
end
|
|
@@ -1,16 +0,0 @@
|
|
|
1
|
-
# [CRUCIBLE-SEED]
|
|
2
|
-
# category: open_redirect
|
|
3
|
-
# severity: high
|
|
4
|
-
# language: ruby
|
|
5
|
-
# expected: redirect_to params[:url] without validation — open redirect
|
|
6
|
-
|
|
7
|
-
class SessionsController < ApplicationController
|
|
8
|
-
def create
|
|
9
|
-
if authenticated?
|
|
10
|
-
redirect_to params[:url] || root_path
|
|
11
|
-
else
|
|
12
|
-
flash[:error] = 'Invalid credentials'
|
|
13
|
-
render :new
|
|
14
|
-
end
|
|
15
|
-
end
|
|
16
|
-
end
|
|
@@ -1,22 +0,0 @@
|
|
|
1
|
-
# [CRUCIBLE-SEED]
|
|
2
|
-
# category: open_redirect
|
|
3
|
-
# severity: high
|
|
4
|
-
# language: ruby
|
|
5
|
-
# expected: redirect_to with 'next' or 'return_to' parameter — open redirect after login
|
|
6
|
-
|
|
7
|
-
class AuthController < ApplicationController
|
|
8
|
-
def callback
|
|
9
|
-
next_url = params[:next] || params[:return_to] || dashboard_path
|
|
10
|
-
redirect_to next_url
|
|
11
|
-
end
|
|
12
|
-
|
|
13
|
-
def logout
|
|
14
|
-
sign_out current_user
|
|
15
|
-
redirect_to params[:redirect]
|
|
16
|
-
end
|
|
17
|
-
|
|
18
|
-
def sso_redirect
|
|
19
|
-
target = request.params['RelayState'] || root_url
|
|
20
|
-
redirect_to target, allow_other_host: true
|
|
21
|
-
end
|
|
22
|
-
end
|
|
@@ -1,27 +0,0 @@
|
|
|
1
|
-
# [CRUCIBLE-SEED]
|
|
2
|
-
# category: open_redirect
|
|
3
|
-
# severity: medium
|
|
4
|
-
# language: ruby
|
|
5
|
-
# expected: Regex-based redirect validation bypassable with CRLF or subdomain trick
|
|
6
|
-
|
|
7
|
-
class RedirectController < ApplicationController
|
|
8
|
-
SAFE_DOMAIN = 'example.com'
|
|
9
|
-
|
|
10
|
-
def go
|
|
11
|
-
target = params[:to]
|
|
12
|
-
if target =~ /example\.com/
|
|
13
|
-
redirect_to target, allow_other_host: true
|
|
14
|
-
else
|
|
15
|
-
redirect_to root_path
|
|
16
|
-
end
|
|
17
|
-
end
|
|
18
|
-
|
|
19
|
-
def external
|
|
20
|
-
url = params[:url]
|
|
21
|
-
trusted = ['example.com', 'partner.com']
|
|
22
|
-
host = URI.parse(url).host rescue ''
|
|
23
|
-
if trusted.include?(host)
|
|
24
|
-
redirect_to url, allow_other_host: true
|
|
25
|
-
end
|
|
26
|
-
end
|
|
27
|
-
end
|
|
@@ -1,26 +0,0 @@
|
|
|
1
|
-
# [CRUCIBLE-SEED]
|
|
2
|
-
# category: open_redirect
|
|
3
|
-
# severity: high
|
|
4
|
-
# language: ruby
|
|
5
|
-
# expected: send_file or redirect after download with user-controlled path
|
|
6
|
-
|
|
7
|
-
class DownloadsController < ApplicationController
|
|
8
|
-
def complete
|
|
9
|
-
file = params[:file]
|
|
10
|
-
callback = params[:callback_url]
|
|
11
|
-
send_file Rails.root.join('public', 'downloads', file)
|
|
12
|
-
redirect_to callback
|
|
13
|
-
end
|
|
14
|
-
|
|
15
|
-
def track_and_redirect
|
|
16
|
-
destination = params[:destination]
|
|
17
|
-
track_click(destination)
|
|
18
|
-
redirect_to destination, allow_other_host: true
|
|
19
|
-
end
|
|
20
|
-
|
|
21
|
-
private
|
|
22
|
-
|
|
23
|
-
def track_click(url)
|
|
24
|
-
ClickLog.create(url: url, user_id: current_user&.id)
|
|
25
|
-
end
|
|
26
|
-
end
|
|
@@ -1,24 +0,0 @@
|
|
|
1
|
-
# [CRUCIBLE-SEED]
|
|
2
|
-
# category: yaml_deserialization
|
|
3
|
-
# severity: critical
|
|
4
|
-
# language: ruby
|
|
5
|
-
# expected: YAML.load with user-controlled input — allows arbitrary object instantiation
|
|
6
|
-
|
|
7
|
-
class ConfigController < ApplicationController
|
|
8
|
-
def import
|
|
9
|
-
config_data = params[:config]
|
|
10
|
-
config = YAML.load(config_data)
|
|
11
|
-
apply_config(config)
|
|
12
|
-
render json: { applied: true }
|
|
13
|
-
end
|
|
14
|
-
|
|
15
|
-
def load_template(template_string)
|
|
16
|
-
YAML.load(template_string)
|
|
17
|
-
end
|
|
18
|
-
|
|
19
|
-
private
|
|
20
|
-
|
|
21
|
-
def apply_config(cfg)
|
|
22
|
-
cfg.each { |k, v| Rails.application.config.send("#{k}=", v) rescue nil }
|
|
23
|
-
end
|
|
24
|
-
end
|
|
@@ -1,20 +0,0 @@
|
|
|
1
|
-
# [CRUCIBLE-SEED]
|
|
2
|
-
# category: yaml_deserialization
|
|
3
|
-
# severity: critical
|
|
4
|
-
# language: ruby
|
|
5
|
-
# expected: YAML.load on file contents from user-supplied path — RCE via Psych gadget
|
|
6
|
-
|
|
7
|
-
def load_config_file(config_name)
|
|
8
|
-
path = "/etc/app/configs/#{config_name}.yml"
|
|
9
|
-
content = File.read(path)
|
|
10
|
-
YAML.load(content)
|
|
11
|
-
end
|
|
12
|
-
|
|
13
|
-
def parse_pipeline(pipeline_definition)
|
|
14
|
-
YAML.load(pipeline_definition)
|
|
15
|
-
end
|
|
16
|
-
|
|
17
|
-
def deserialize_job(job_yaml)
|
|
18
|
-
job = YAML.load(job_yaml)
|
|
19
|
-
job.merge(loaded_at: Time.now)
|
|
20
|
-
end
|
|
@@ -1,27 +0,0 @@
|
|
|
1
|
-
# [CRUCIBLE-SEED]
|
|
2
|
-
# category: yaml_deserialization
|
|
3
|
-
# severity: critical
|
|
4
|
-
# language: ruby
|
|
5
|
-
# expected: YAML.load used in API endpoint — remote code execution via crafted payload
|
|
6
|
-
|
|
7
|
-
require 'sinatra'
|
|
8
|
-
require 'yaml'
|
|
9
|
-
|
|
10
|
-
post '/api/import' do
|
|
11
|
-
content_type :json
|
|
12
|
-
raw_body = request.body.read
|
|
13
|
-
data = YAML.load(raw_body)
|
|
14
|
-
process_import(data)
|
|
15
|
-
{ imported: data.keys.count }.to_json
|
|
16
|
-
end
|
|
17
|
-
|
|
18
|
-
post '/api/config/update' do
|
|
19
|
-
yaml_config = params[:yaml]
|
|
20
|
-
config = YAML.load(yaml_config)
|
|
21
|
-
config.each { |k, v| CONFIG[k] = v }
|
|
22
|
-
{ updated: true }.to_json
|
|
23
|
-
end
|
|
24
|
-
|
|
25
|
-
def process_import(data)
|
|
26
|
-
data.each { |k, v| puts "#{k}: #{v}" }
|
|
27
|
-
end
|
|
@@ -1,25 +0,0 @@
|
|
|
1
|
-
// [CRUCIBLE-SEED]
|
|
2
|
-
// category: hardcoded_secret
|
|
3
|
-
// severity: critical
|
|
4
|
-
// language: rust
|
|
5
|
-
// expected: Hardcoded AWS access key and secret in string literals
|
|
6
|
-
|
|
7
|
-
use aws_sdk_s3::Client;
|
|
8
|
-
|
|
9
|
-
const AWS_ACCESS_KEY_ID: &str = "AKIAIOSFODNN7EXAMPLE1";
|
|
10
|
-
const AWS_SECRET_ACCESS_KEY: &str = "wJalrXUtnFEMI/K7MDENG/bPxRfiCYEXAMPLEKEY";
|
|
11
|
-
const AWS_REGION: &str = "us-east-1";
|
|
12
|
-
const S3_BUCKET: &str = "my-production-bucket";
|
|
13
|
-
|
|
14
|
-
pub async fn create_s3_client() -> Client {
|
|
15
|
-
std::env::set_var("AWS_ACCESS_KEY_ID", AWS_ACCESS_KEY_ID);
|
|
16
|
-
std::env::set_var("AWS_SECRET_ACCESS_KEY", AWS_SECRET_ACCESS_KEY);
|
|
17
|
-
std::env::set_var("AWS_DEFAULT_REGION", AWS_REGION);
|
|
18
|
-
let config = aws_config::load_from_env().await;
|
|
19
|
-
Client::new(&config)
|
|
20
|
-
}
|
|
21
|
-
|
|
22
|
-
pub fn get_bucket() -> &'static str {
|
|
23
|
-
println!("Using bucket: {} with key: {}", S3_BUCKET, AWS_ACCESS_KEY_ID);
|
|
24
|
-
S3_BUCKET
|
|
25
|
-
}
|
|
@@ -1,20 +0,0 @@
|
|
|
1
|
-
// [CRUCIBLE-SEED]
|
|
2
|
-
// category: hardcoded_secret
|
|
3
|
-
// severity: critical
|
|
4
|
-
// language: rust
|
|
5
|
-
// expected: Hardcoded database password in connection string literal
|
|
6
|
-
|
|
7
|
-
use sqlx::PgPool;
|
|
8
|
-
|
|
9
|
-
const DB_URL: &str = "postgresql://appuser:Sup3rS3cr3tP@ssw0rd!@prod-db.example.com:5432/appdb";
|
|
10
|
-
const REDIS_URL: &str = "redis://:myR3d1sS3cret@redis.prod.example.com:6379/0";
|
|
11
|
-
const MONGO_URL: &str = "mongodb://admin:M0ng0P@ssw0rd@mongo.example.com:27017/proddb";
|
|
12
|
-
|
|
13
|
-
pub async fn connect_db() -> PgPool {
|
|
14
|
-
PgPool::connect(DB_URL).await.expect("Failed to connect to DB")
|
|
15
|
-
}
|
|
16
|
-
|
|
17
|
-
pub fn get_db_url() -> &'static str {
|
|
18
|
-
eprintln!("Connecting to: {}", DB_URL);
|
|
19
|
-
DB_URL
|
|
20
|
-
}
|
|
@@ -1,23 +0,0 @@
|
|
|
1
|
-
// [CRUCIBLE-SEED]
|
|
2
|
-
// category: hardcoded_secret
|
|
3
|
-
// severity: critical
|
|
4
|
-
// language: rust
|
|
5
|
-
// expected: Hardcoded JWT secret key used to sign tokens
|
|
6
|
-
|
|
7
|
-
use hmac::{Hmac, Mac};
|
|
8
|
-
use sha2::Sha256;
|
|
9
|
-
|
|
10
|
-
const JWT_SECRET: &str = "mySuperSecretJWTSigningKey_2024_doNotCommit";
|
|
11
|
-
const JWT_EXPIRY_HOURS: u64 = 24;
|
|
12
|
-
const ADMIN_API_KEY: &str = "admin_sk_live_xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx";
|
|
13
|
-
|
|
14
|
-
pub fn sign_token(payload: &str) -> Vec<u8> {
|
|
15
|
-
let mut mac = Hmac::<Sha256>::new_from_slice(JWT_SECRET.as_bytes())
|
|
16
|
-
.expect("HMAC key error");
|
|
17
|
-
mac.update(payload.as_bytes());
|
|
18
|
-
mac.finalize().into_bytes().to_vec()
|
|
19
|
-
}
|
|
20
|
-
|
|
21
|
-
pub fn verify_admin(key: &str) -> bool {
|
|
22
|
-
key == ADMIN_API_KEY
|
|
23
|
-
}
|
|
@@ -1,21 +0,0 @@
|
|
|
1
|
-
// [CRUCIBLE-SEED]
|
|
2
|
-
// category: hardcoded_secret
|
|
3
|
-
// severity: critical
|
|
4
|
-
// language: rust
|
|
5
|
-
// expected: Hardcoded Stripe and payment processor API keys
|
|
6
|
-
|
|
7
|
-
const STRIPE_SECRET_KEY: &str = "sk_live_51HxyzABCDEFGHIJKLMNOPQRSTUVWXYZ1234567890abcdefghij";
|
|
8
|
-
const STRIPE_WEBHOOK_SECRET: &str = "whsec_abcdefghijklmnopqrstuvwxyz0123456789ABCDEFGHIJ";
|
|
9
|
-
const PAYPAL_CLIENT_ID: &str = "AaBbCcDdEeFfGgHhIiJjKkLlMmNnOoPpQqRrSsTtUuVv";
|
|
10
|
-
const PAYPAL_CLIENT_SECRET: &str = "EeLlKkJjIiHhGgFfEeDdCcBbAa0123456789xyzabcdef";
|
|
11
|
-
|
|
12
|
-
pub fn get_stripe_headers() -> Vec<(&'static str, String)> {
|
|
13
|
-
vec![
|
|
14
|
-
("Authorization", format!("Bearer {}", STRIPE_SECRET_KEY)),
|
|
15
|
-
("Stripe-Version", "2023-10-16".to_string()),
|
|
16
|
-
]
|
|
17
|
-
}
|
|
18
|
-
|
|
19
|
-
pub fn validate_webhook(sig: &str) -> bool {
|
|
20
|
-
sig.starts_with(&STRIPE_WEBHOOK_SECRET[..10])
|
|
21
|
-
}
|
|
@@ -1,21 +0,0 @@
|
|
|
1
|
-
// [CRUCIBLE-SEED]
|
|
2
|
-
// category: hardcoded_secret
|
|
3
|
-
// severity: high
|
|
4
|
-
// language: rust
|
|
5
|
-
// expected: Hardcoded GitHub and GitLab personal access tokens
|
|
6
|
-
|
|
7
|
-
const GITHUB_TOKEN: &str = "ghp_xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx";
|
|
8
|
-
const GITLAB_TOKEN: &str = "glpat-xxxxxxxxxxxxxxxxxxxxxxxxxxxx";
|
|
9
|
-
const GITHUB_WEBHOOK_SECRET: &str = "github_webhook_secret_super_secret_value_here";
|
|
10
|
-
|
|
11
|
-
pub fn clone_repo(repo_url: &str) -> String {
|
|
12
|
-
format!(
|
|
13
|
-
"https://{}@github.com/{}",
|
|
14
|
-
GITHUB_TOKEN, repo_url
|
|
15
|
-
)
|
|
16
|
-
}
|
|
17
|
-
|
|
18
|
-
pub async fn create_github_issue(owner: &str, repo: &str, title: &str) {
|
|
19
|
-
let url = format!("https://api.github.com/repos/{}/{}/issues", owner, repo);
|
|
20
|
-
println!("POST {} with token: {}", url, &GITHUB_TOKEN[..10]);
|
|
21
|
-
}
|
|
@@ -1,24 +0,0 @@
|
|
|
1
|
-
// [CRUCIBLE-SEED]
|
|
2
|
-
// category: hardcoded_secret
|
|
3
|
-
// severity: critical
|
|
4
|
-
// language: rust
|
|
5
|
-
// expected: Hardcoded encryption key and IV in const literals
|
|
6
|
-
|
|
7
|
-
use aes::Aes256;
|
|
8
|
-
use cbc::cipher::KeyIvInit;
|
|
9
|
-
|
|
10
|
-
const ENCRYPTION_KEY: &[u8] = b"0123456789abcdef0123456789abcdef";
|
|
11
|
-
const ENCRYPTION_IV: &[u8] = b"abcdef0123456789";
|
|
12
|
-
const HMAC_KEY: &str = "super-secret-hmac-key-do-not-share";
|
|
13
|
-
|
|
14
|
-
pub fn create_cipher() -> cbc::Encryptor<Aes256> {
|
|
15
|
-
cbc::Encryptor::<Aes256>::new(
|
|
16
|
-
ENCRYPTION_KEY.into(),
|
|
17
|
-
ENCRYPTION_IV.into(),
|
|
18
|
-
)
|
|
19
|
-
}
|
|
20
|
-
|
|
21
|
-
pub fn get_hmac_key() -> &'static [u8] {
|
|
22
|
-
println!("HMAC key length: {}", HMAC_KEY.len());
|
|
23
|
-
HMAC_KEY.as_bytes()
|
|
24
|
-
}
|
|
@@ -1,20 +0,0 @@
|
|
|
1
|
-
// [CRUCIBLE-SEED]
|
|
2
|
-
// category: hardcoded_secret
|
|
3
|
-
// severity: high
|
|
4
|
-
// language: rust
|
|
5
|
-
// expected: Hardcoded SMTP credentials and email service API key
|
|
6
|
-
|
|
7
|
-
const SMTP_HOST: &str = "smtp.sendgrid.net";
|
|
8
|
-
const SMTP_PORT: u16 = 587;
|
|
9
|
-
const SMTP_USERNAME: &str = "apikey";
|
|
10
|
-
const SMTP_PASSWORD: &str = "SG.xxxxxxxxxxxxxxxxxxxxxxxxxxxx.yyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyy";
|
|
11
|
-
const FROM_EMAIL: &str = "noreply@example.com";
|
|
12
|
-
|
|
13
|
-
pub fn build_smtp_transport() -> String {
|
|
14
|
-
format!("{}://{}:{}@{}:{}", "smtp", SMTP_USERNAME, SMTP_PASSWORD, SMTP_HOST, SMTP_PORT)
|
|
15
|
-
}
|
|
16
|
-
|
|
17
|
-
pub fn get_smtp_config() -> (String, String) {
|
|
18
|
-
println!("SMTP config loaded for: {}", SMTP_HOST);
|
|
19
|
-
(SMTP_USERNAME.to_string(), SMTP_PASSWORD.to_string())
|
|
20
|
-
}
|
|
@@ -1,19 +0,0 @@
|
|
|
1
|
-
// [CRUCIBLE-SEED]
|
|
2
|
-
// category: hardcoded_secret
|
|
3
|
-
// severity: critical
|
|
4
|
-
// language: rust
|
|
5
|
-
// expected: Hardcoded Slack webhook URL and bot token
|
|
6
|
-
|
|
7
|
-
const SLACK_BOT_TOKEN: &str = "xoxb-1234567890-1234567890123-abcdefghijklmnopqrstuvwx";
|
|
8
|
-
const SLACK_SIGNING_SECRET: &str = "abcdef0123456789abcdef0123456789";
|
|
9
|
-
const SLACK_WEBHOOK_URL: &str = "https://hooks.slack.com/services/T00000000/B00000000/XXXXXXXXXXXXXXXXXXXXXXXX";
|
|
10
|
-
|
|
11
|
-
pub async fn send_slack_message(channel: &str, text: &str) {
|
|
12
|
-
println!("Sending to {} via token: {}...", channel, &SLACK_BOT_TOKEN[..15]);
|
|
13
|
-
let client = reqwest::Client::new();
|
|
14
|
-
let _ = client
|
|
15
|
-
.post(SLACK_WEBHOOK_URL)
|
|
16
|
-
.json(&serde_json::json!({"text": text}))
|
|
17
|
-
.send()
|
|
18
|
-
.await;
|
|
19
|
-
}
|
|
@@ -1,28 +0,0 @@
|
|
|
1
|
-
// [CRUCIBLE-SEED]
|
|
2
|
-
// category: unsafe_block
|
|
3
|
-
// severity: critical
|
|
4
|
-
// language: rust
|
|
5
|
-
// expected: Raw pointer dereference in unsafe block without bounds checking
|
|
6
|
-
|
|
7
|
-
pub fn read_from_raw_ptr(ptr: *const u8, offset: usize) -> u8 {
|
|
8
|
-
unsafe {
|
|
9
|
-
*ptr.add(offset)
|
|
10
|
-
}
|
|
11
|
-
}
|
|
12
|
-
|
|
13
|
-
pub fn write_to_raw_ptr(ptr: *mut u8, offset: usize, value: u8) {
|
|
14
|
-
unsafe {
|
|
15
|
-
*ptr.add(offset) = value;
|
|
16
|
-
}
|
|
17
|
-
}
|
|
18
|
-
|
|
19
|
-
pub fn slice_from_raw(ptr: *const u8, len: usize) -> &'static [u8] {
|
|
20
|
-
unsafe {
|
|
21
|
-
std::slice::from_raw_parts(ptr, len)
|
|
22
|
-
}
|
|
23
|
-
}
|
|
24
|
-
|
|
25
|
-
pub fn null_ptr_deref_risk() -> u8 {
|
|
26
|
-
let ptr: *const u8 = 0x0 as *const u8;
|
|
27
|
-
unsafe { *ptr }
|
|
28
|
-
}
|
|
@@ -1,28 +0,0 @@
|
|
|
1
|
-
// [CRUCIBLE-SEED]
|
|
2
|
-
// category: unsafe_block
|
|
3
|
-
// severity: critical
|
|
4
|
-
// language: rust
|
|
5
|
-
// expected: std::mem::transmute misuse — reinterpret arbitrary bytes as typed reference
|
|
6
|
-
|
|
7
|
-
use std::mem;
|
|
8
|
-
|
|
9
|
-
pub fn transmute_bytes_to_struct<T>(bytes: &[u8]) -> &T {
|
|
10
|
-
unsafe {
|
|
11
|
-
mem::transmute(bytes.as_ptr())
|
|
12
|
-
}
|
|
13
|
-
}
|
|
14
|
-
|
|
15
|
-
pub fn reinterpret_as<S, D>(src: &S) -> &D {
|
|
16
|
-
unsafe { mem::transmute(src) }
|
|
17
|
-
}
|
|
18
|
-
|
|
19
|
-
pub fn bytes_to_u64(bytes: &[u8]) -> u64 {
|
|
20
|
-
unsafe {
|
|
21
|
-
let arr: [u8; 8] = *(bytes.as_ptr() as *const [u8; 8]);
|
|
22
|
-
mem::transmute(arr)
|
|
23
|
-
}
|
|
24
|
-
}
|
|
25
|
-
|
|
26
|
-
pub fn lifetime_extend<'a, 'b, T>(r: &'a T) -> &'b T {
|
|
27
|
-
unsafe { mem::transmute(r) }
|
|
28
|
-
}
|
|
@@ -1,25 +0,0 @@
|
|
|
1
|
-
// [CRUCIBLE-SEED]
|
|
2
|
-
// category: unsafe_block
|
|
3
|
-
// severity: critical
|
|
4
|
-
// language: rust
|
|
5
|
-
// expected: Unsafe foreign function interface call without input validation
|
|
6
|
-
|
|
7
|
-
extern "C" {
|
|
8
|
-
fn memcpy(dest: *mut u8, src: *const u8, n: usize) -> *mut u8;
|
|
9
|
-
fn strlen(s: *const u8) -> usize;
|
|
10
|
-
fn strcpy(dest: *mut u8, src: *const u8) -> *mut u8;
|
|
11
|
-
}
|
|
12
|
-
|
|
13
|
-
pub fn raw_memcpy(src: &[u8], dest: &mut Vec<u8>, n: usize) {
|
|
14
|
-
unsafe {
|
|
15
|
-
memcpy(dest.as_mut_ptr(), src.as_ptr(), n);
|
|
16
|
-
}
|
|
17
|
-
}
|
|
18
|
-
|
|
19
|
-
pub fn get_c_strlen(s: *const u8) -> usize {
|
|
20
|
-
unsafe { strlen(s) }
|
|
21
|
-
}
|
|
22
|
-
|
|
23
|
-
pub fn unsafe_string_copy(src: *const u8, dest: *mut u8) {
|
|
24
|
-
unsafe { strcpy(dest, src); }
|
|
25
|
-
}
|
|
@@ -1,31 +0,0 @@
|
|
|
1
|
-
// [CRUCIBLE-SEED]
|
|
2
|
-
// category: unsafe_block
|
|
3
|
-
// severity: high
|
|
4
|
-
// language: rust
|
|
5
|
-
// expected: Vec::set_len called without initializing memory — UB
|
|
6
|
-
|
|
7
|
-
pub fn create_uninitialized_vec(size: usize) -> Vec<u8> {
|
|
8
|
-
let mut v = Vec::with_capacity(size);
|
|
9
|
-
unsafe {
|
|
10
|
-
v.set_len(size);
|
|
11
|
-
}
|
|
12
|
-
v
|
|
13
|
-
}
|
|
14
|
-
|
|
15
|
-
pub fn extend_vec_unsafely(v: &mut Vec<u8>, extra: usize) {
|
|
16
|
-
let new_len = v.len() + extra;
|
|
17
|
-
if v.capacity() < new_len {
|
|
18
|
-
v.reserve(extra);
|
|
19
|
-
}
|
|
20
|
-
unsafe {
|
|
21
|
-
v.set_len(new_len);
|
|
22
|
-
}
|
|
23
|
-
}
|
|
24
|
-
|
|
25
|
-
pub fn read_uninitialized() -> u32 {
|
|
26
|
-
let x: u32;
|
|
27
|
-
unsafe {
|
|
28
|
-
x = std::mem::MaybeUninit::uninit().assume_init();
|
|
29
|
-
}
|
|
30
|
-
x
|
|
31
|
-
}
|
|
@@ -1,27 +0,0 @@
|
|
|
1
|
-
// [CRUCIBLE-SEED]
|
|
2
|
-
// category: unsafe_block
|
|
3
|
-
// severity: critical
|
|
4
|
-
// language: rust
|
|
5
|
-
// expected: Mutable aliasing via raw pointers — violates Rust's aliasing rules
|
|
6
|
-
|
|
7
|
-
pub fn create_aliased_refs(data: &mut Vec<i32>) -> (*mut i32, *mut i32) {
|
|
8
|
-
let ptr1 = data.as_mut_ptr();
|
|
9
|
-
let ptr2 = data.as_mut_ptr();
|
|
10
|
-
(ptr1, ptr2)
|
|
11
|
-
}
|
|
12
|
-
|
|
13
|
-
pub fn alias_write(v: &mut Vec<u8>) {
|
|
14
|
-
unsafe {
|
|
15
|
-
let p1 = v.as_mut_ptr();
|
|
16
|
-
let p2 = v.as_mut_ptr();
|
|
17
|
-
*p1 = 1;
|
|
18
|
-
*p2 = 2;
|
|
19
|
-
}
|
|
20
|
-
}
|
|
21
|
-
|
|
22
|
-
pub fn double_free_risk(ptr: *mut u8, len: usize) {
|
|
23
|
-
unsafe {
|
|
24
|
-
let _v1 = Vec::from_raw_parts(ptr, len, len);
|
|
25
|
-
let _v2 = Vec::from_raw_parts(ptr, len, len);
|
|
26
|
-
}
|
|
27
|
-
}
|
|
@@ -1,30 +0,0 @@
|
|
|
1
|
-
// [CRUCIBLE-SEED]
|
|
2
|
-
// category: unsafe_block
|
|
3
|
-
// severity: high
|
|
4
|
-
// language: rust
|
|
5
|
-
// expected: Use of unsafe to bypass borrow checker — potential use-after-free
|
|
6
|
-
|
|
7
|
-
use std::collections::HashMap;
|
|
8
|
-
|
|
9
|
-
pub struct Cache {
|
|
10
|
-
data: HashMap<String, String>,
|
|
11
|
-
}
|
|
12
|
-
|
|
13
|
-
impl Cache {
|
|
14
|
-
pub fn get_or_insert(&mut self, key: &str, value: String) -> &str {
|
|
15
|
-
if !self.data.contains_key(key) {
|
|
16
|
-
self.data.insert(key.to_string(), value);
|
|
17
|
-
}
|
|
18
|
-
unsafe {
|
|
19
|
-
let s: *const String = self.data.get(key).unwrap();
|
|
20
|
-
&*s
|
|
21
|
-
}
|
|
22
|
-
}
|
|
23
|
-
|
|
24
|
-
pub fn dangling_ref(&mut self) -> &str {
|
|
25
|
-
let s = String::from("temporary");
|
|
26
|
-
let ptr = s.as_str() as *const str;
|
|
27
|
-
drop(s);
|
|
28
|
-
unsafe { &*ptr }
|
|
29
|
-
}
|
|
30
|
-
}
|
|
@@ -1,33 +0,0 @@
|
|
|
1
|
-
// [CRUCIBLE-SEED]
|
|
2
|
-
// category: unsafe_block
|
|
3
|
-
// severity: critical
|
|
4
|
-
// language: rust
|
|
5
|
-
// expected: Send/Sync implemented for non-thread-safe type via unsafe impl
|
|
6
|
-
|
|
7
|
-
use std::cell::Cell;
|
|
8
|
-
use std::rc::Rc;
|
|
9
|
-
|
|
10
|
-
pub struct SharedCounter {
|
|
11
|
-
value: Cell<i64>,
|
|
12
|
-
data: Rc<Vec<u8>>,
|
|
13
|
-
}
|
|
14
|
-
|
|
15
|
-
unsafe impl Send for SharedCounter {}
|
|
16
|
-
unsafe impl Sync for SharedCounter {}
|
|
17
|
-
|
|
18
|
-
impl SharedCounter {
|
|
19
|
-
pub fn new() -> Self {
|
|
20
|
-
SharedCounter {
|
|
21
|
-
value: Cell::new(0),
|
|
22
|
-
data: Rc::new(vec![]),
|
|
23
|
-
}
|
|
24
|
-
}
|
|
25
|
-
|
|
26
|
-
pub fn increment(&self) {
|
|
27
|
-
self.value.set(self.value.get() + 1);
|
|
28
|
-
}
|
|
29
|
-
|
|
30
|
-
pub fn get(&self) -> i64 {
|
|
31
|
-
self.value.get()
|
|
32
|
-
}
|
|
33
|
-
}
|