• Home
  • Features
  • Pricing
  • Docs
  • Announcements
  • Sign In

rwjdk / TrelloDotNet / 6393576553

03 Oct 2023 01:20PM UTC coverage: 67.061% (-0.4%) from 67.435%
6393576553

push

github

web-flow
Implement webhook signature validation (#26)

* implement webhook signature validation

* Requested changes and some optimizations

- add webhook signature validation to AutomationController
- add Secret to TrelloClientOptions
- reduce memory allocations in WebhookSignatureValidator.ValidateSignature from ~15KB to ~5KB

* WebhookSignatureValidator: try to validate signatures when signature or webhookUrl is set. Throw an exception if one of signature, webhookUrl, secret is missing

871 of 1623 branches covered (0.0%)

Branch coverage included in aggregate %.

37 of 37 new or added lines in 5 files covered. (100.0%)

2246 of 3025 relevant lines covered (74.25%)

60.93 hits per line

Source File
Press 'n' to go to next uncovered line, 'b' for previous

94.12
/TrelloDotNet/TrelloDotNet/WebhookDataReceiver.cs
1
using System.Text.Json;
2
using TrelloDotNet.Control.Webhook;
3
using TrelloDotNet.Model.Webhook;
4

5
namespace TrelloDotNet
6
{
7
    /// <summary>
8
    /// Class to help you process a Webhook event but either turning the JSON into classes or fire events based on the JSON given to it
9
    /// </summary>
10
    public class WebhookDataReceiver
11
    {
12
        private readonly TrelloClient _trelloClient;
13

14
        /// <summary>
15
        /// Constructor
16
        /// </summary>
17
        /// <param name="trelloClient">The base TrelloClient</param>
18
        public WebhookDataReceiver(TrelloClient trelloClient)
22✔
19
        {
20
            _trelloClient = trelloClient;
22✔
21
        }
22✔
22

23
        /// <summary>
24
        /// Class that can turn data from an into events based on what the data contain
25
        /// </summary>
26
        /// <param name="json">The raw incoming JSON</param>
27
        /// <param name="signature">Signature from X-Trello-Webhook header for signature validation</param>
28
        /// <param name="webhookUrl">Webhook URL for signature validation</param>
29
        /// <returns>If the Event was processed (aka it was a supported event)</returns>
30
        public async void ProcessJsonIntoEvents(string json, string signature = null, string webhookUrl = null)
31
        {
32
            if (string.IsNullOrWhiteSpace(json))
9✔
33
            {
34
                return; // Most Likely the Head Call when setting up webhook - Just ignore
1✔
35
            }
36

37
            if ((!string.IsNullOrEmpty(signature) || !string.IsNullOrEmpty(webhookUrl))
8!
38
                && !WebhookSignatureValidator.ValidateSignature(json, signature, webhookUrl, _trelloClient.Options.Secret))
8✔
39
            {
40
                return; // Invalid signature
×
41
            }
42
            
43
            var webhookNotification = JsonSerializer.Deserialize<WebhookNotification>(json);
8✔
44
            BasicEvents.FireEvent(webhookNotification.Action);
8✔
45
            await SmartEvents.FireEvent(webhookNotification.Action, _trelloClient);
8✔
46
        }
9✔
47

48
        /// <summary>
49
        /// Convert JSON for the webhook into a Notification
50
        /// </summary>
51
        /// <param name="json">Raw JSON from the webhook</param>
52
        /// <returns>C# Class representing the JSON</returns>
53
        public WebhookNotification ConvertJsonToWebhookNotification(string json)
54
        {
55
            var result = JsonSerializer.Deserialize<WebhookNotification>(json);
15✔
56
            SetTrelloClientAndParents(result.Action);
15✔
57
            return result;
15✔
58
        }
59

60
        private void SetTrelloClientAndParents(WebhookAction action)
61
        {
62
            action.TrelloClient = _trelloClient;
26✔
63
            action.Data.Parent = action;
26✔
64
            if (action.Data.Board != null)
26✔
65
            {
66
                action.Data.Board.Parent = action.Data;
26✔
67
            }
68
            if (action.Data.Card != null)
26✔
69
            {
70
                action.Data.Card.Parent = action.Data;
26✔
71
            }
72
            if (action.Data.List != null)
26✔
73
            {
74
                action.Data.List.Parent = action.Data;
6✔
75
            }
76
            if (action.Data.ListAfter != null)
26✔
77
            {
78
                action.Data.ListAfter.Parent = action.Data;
15✔
79
            }
80
            if (action.Data.ListBefore != null)
26✔
81
            {
82
                action.Data.ListBefore.Parent = action.Data;
15✔
83
            }
84
            if (action.Data.Checklist != null)
26✔
85
            {
86
                action.Data.Checklist.Parent = action.Data;
1✔
87
            }
88
            if (action.Data.Member != null)
26✔
89
            {
90
                action.Data.Member.Parent = action.Data;
2✔
91
            }
92
        }
26✔
93

94
        /// <summary>
95
        /// Convert JSON for the webhook into a Board Notification (require that you webhook set it idModel to a BoardId)
96
        /// </summary>
97
        /// <param name="json">Raw JSON from the webhook</param>
98
        /// <returns>C# Class representing the JSON</returns>
99
        public WebhookNotificationBoard ConvertJsonToWebhookNotificationBoard(string json)
100
        {
101
            var result = JsonSerializer.Deserialize<WebhookNotificationBoard>(json);
8✔
102
            SetTrelloClientAndParents(result.Action);
8✔
103
            return result;
8✔
104
        }
105

106
        /// <summary>
107
        /// Convert JSON for the webhook into a Card Notification (require that you webhook set it idModel to a CardId)
108
        /// </summary>
109
        /// <param name="json">Raw JSON from the webhook</param>
110
        /// <returns>C# Class representing the JSON</returns>
111
        public WebhookNotificationCard ConvertJsonToWebhookNotificationCard(string json)
112
        {
113
            var result = JsonSerializer.Deserialize<WebhookNotificationCard>(json);
1✔
114
            SetTrelloClientAndParents(result.Action);
1✔
115
            return result;
1✔
116
        }
117

118
        /// <summary>
119
        /// Convert JSON for the webhook into a List Notification (require that you webhook set it idModel to a ListId)
120
        /// </summary>
121
        /// <param name="json">Raw JSON from the webhook</param>
122
        /// <returns>C# Class representing the JSON</returns>
123
        public WebhookNotificationList ConvertJsonToWebhookNotificationList(string json)
124
        {
125
            var result = JsonSerializer.Deserialize<WebhookNotificationList>(json);
1✔
126
            SetTrelloClientAndParents(result.Action);
1✔
127
            return result;
1✔
128
        }
129

130
        /// <summary>
131
        /// Convert JSON for the webhook into a Member Notification (require that you webhook set it idModel to a MemberId)
132
        /// </summary>
133
        /// <param name="json">Raw JSON from the webhook</param>
134
        /// <returns>C# Class representing the JSON</returns>
135
        public WebhookNotificationMember ConvertJsonToWebhookNotificationMember(string json)
136
        {
137
            var result = JsonSerializer.Deserialize<WebhookNotificationMember>(json);
1✔
138
            SetTrelloClientAndParents(result.Action);
1✔
139
            return result;
1✔
140
        }
141

142
        /// <summary>
143
        /// Basic Webhook event where the arguments are generic (aka support everything but there is more work for you to use the event)
144
        /// </summary>
145
        public WebhookDataReceiverBasicEvents BasicEvents { get; } = new WebhookDataReceiverBasicEvents();
598✔
146

147
        /// <summary>
148
        /// Curated common events that most integrations need (aka much easier to use, but might not have the specific type event you need (ask on github for more events)) 
149
        /// </summary>
150
        public WebhookDataReceiverSmartEvents SmartEvents { get; } = new WebhookDataReceiverSmartEvents();
86✔
151
    }
152
}
STATUS · Troubleshooting · Open an Issue · Sales · Support · CAREERS · ENTERPRISE · START FREE · SCHEDULE DEMO
ANNOUNCEMENTS · TWITTER · TOS & SLA · Supported CI Services · What's a CI service? · Automated Testing

© 2025 Coveralls, Inc