Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Update libraries to accept raw webhook secret #555

Merged
merged 29 commits into from
Jul 13, 2022
Merged
Show file tree
Hide file tree
Changes from 14 commits
Commits
Show all changes
29 commits
Select commit Hold shift + click to select a range
f748dbd
implement raw token option in js lib
svix-dylan Jul 12, 2022
979926e
account for base64 string
svix-dylan Jul 12, 2022
6d3a732
generalize and patch ui8a bug
svix-dylan Jul 12, 2022
ceaec95
feedback
svix-dylan Jul 12, 2022
5282289
reformat conditions check
svix-dylan Jul 12, 2022
b34dacb
go implementation
svix-dylan Jul 12, 2022
35b451c
patch go linter errors
svix-dylan Jul 12, 2022
153d865
god i hate java. attempt java impl.
svix-dylan Jul 12, 2022
79f7ac0
java remove trailing spaces for linter
svix-dylan Jul 12, 2022
64e426d
iterate per feedback
svix-dylan Jul 12, 2022
f7504df
kotlin impl
svix-dylan Jul 12, 2022
273f071
php impl
svix-dylan Jul 12, 2022
5e7776c
php linter patch
svix-dylan Jul 12, 2022
7dc40a7
python attempt
svix-dylan Jul 12, 2022
b989735
single overloaded “from raw” function Go
svix-dylan Jul 12, 2022
2c3eecf
use Union to solve python init (and remove stale enc_key)
svix-dylan Jul 12, 2022
ca47c1f
lint patch
svix-dylan Jul 12, 2022
b546141
python lint
svix-dylan Jul 12, 2022
1abff99
ruby attempt
svix-dylan Jul 12, 2022
0f02a78
rust impl
svix-dylan Jul 12, 2022
ad4eb57
patch rust
svix-dylan Jul 12, 2022
eeb4e56
patch rust
svix-dylan Jul 12, 2022
19f1f7f
csharp, a la java approach
svix-dylan Jul 12, 2022
579033b
patch Go
svix-dylan Jul 12, 2022
cd53be5
string->String->bytes
svix-dylan Jul 12, 2022
1efb72e
fml ok
svix-dylan Jul 12, 2022
1a12edf
ruby lint patch
svix-dylan Jul 12, 2022
e6d41d1
remove rawString construction, all libs except js
svix-dylan Jul 12, 2022
47f98f7
Update rust/src/webhooks.rs
tasn Jul 13, 2022
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
12 changes: 12 additions & 0 deletions go/webhook.go
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,18 @@ func NewWebhook(secret string) (*Webhook, error) {
}, nil
}

func NewWebhookFromRaw(secret []byte) (*Webhook, error) {
return &Webhook {
key: secret,
}, nil
}

func NewWebhookFromRawString(secret string) (*Webhook, error) {
return &Webhook {
key: []byte(secret),
}, nil
}
svix-dylan marked this conversation as resolved.
Show resolved Hide resolved

// Verify validates the payload against the svix signature headers
// using the webhooks signing secret.
//
Expand Down
8 changes: 8 additions & 0 deletions java/lib/src/main/java/com/svix/Webhook.java
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,14 @@ public Webhook(final String secret) {
this.key = Base64.getDecoder().decode(sec);
}

public WebhookRaw(final byte[] secret) {
this.key = secret;
}

public WebhookRaw(final String secret) {
this.key = secret.getBytes();
}

public void verify(final String payload, final HttpHeaders headers) throws WebhookVerificationException {
Optional<String> msgId = headers.firstValue(SVIX_MSG_ID_KEY);
Optional<String> msgSignature = headers.firstValue(SVIX_MSG_SIGNATURE_KEY);
Expand Down
23 changes: 19 additions & 4 deletions javascript/src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -590,18 +590,33 @@ export interface WebhookUnbrandedRequiredHeaders {
"webhook-signature": string;
}

export interface WebhookOptions {
format?: "raw";
}

export class Webhook {
private static prefix = "whsec_";
private readonly key: Uint8Array;

constructor(secret: string) {
constructor(secret: string | Uint8Array, options?: WebhookOptions) {
if (!secret) {
throw new Error("Secret can't be empty.");
}
if (secret.startsWith(Webhook.prefix)) {
secret = secret.substring(Webhook.prefix.length);
if (options?.format === "raw") {
if (secret instanceof Uint8Array) {
this.key = secret;
} else {
this.key = Uint8Array.from(secret, (c) => c.charCodeAt(0));
}
} else {
if (!(secret instanceof String)) {
throw new Error("Expected secret to be of type string");
}
if (secret.startsWith(Webhook.prefix)) {
secret = secret.substring(Webhook.prefix.length);
}
this.key = base64.decode(secret as string);
svix-dylan marked this conversation as resolved.
Show resolved Hide resolved
}
this.key = base64.decode(secret);
}

public verify(
Expand Down
19 changes: 14 additions & 5 deletions kotlin/lib/src/main/kotlin/Webhook.kt
Original file line number Diff line number Diff line change
Expand Up @@ -100,11 +100,20 @@ class Webhook(secret: String) {
}
}

init {
var sec = secret
if (sec.startsWith(SECRET_PREFIX)) {
sec = sec.substring(SECRET_PREFIX.length)
constructor(secret: String) {
if (secret.startsWith(SECRET_PREFIX)) {
secret = secret.substring(SECRET_PREFIX.length)
}
key = Base64.getDecoder().decode(sec)
key = Base64.getDecoder().decode(secret)
}

constructor(secret: String, format: String) {
svix-dylan marked this conversation as resolved.
Show resolved Hide resolved
if (format === "raw") {
key = secret.toByteArray()
}
}

constructor(secret: ByteArray) {
key = secret
}
}
7 changes: 7 additions & 0 deletions php/src/Webhook.php
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,13 @@ public function __construct($secret)
$this->secret = base64_decode($secret);
}

public static function fromRaw($secret)
{
$obj = new self();
$obj->secret = $secret;
return $obj;
}
svix-dylan marked this conversation as resolved.
Show resolved Hide resolved

public function verify($payload, $headers)
{
if (
Expand Down
10 changes: 10 additions & 0 deletions python/svix/webhooks.py
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,16 @@ def __init__(self, whsecret: str, *, enc_key: t.Optional[str] = None):
self._whsecret = base64.b64decode(whsecret)
self._enc_key = base64.b64decode(enc_key) if enc_key is not None else None

def from_raw(whsecret: bytes):
svix-dylan marked this conversation as resolved.
Show resolved Hide resolved
wh = Webhook()
wh._whsecret = whsecret
return wh

def from_raw(whsecret: str):
wh = Webhook()
wh._whsecret = str.encode(whsecret)
svix-dylan marked this conversation as resolved.
Show resolved Hide resolved
return wh

def verify(self, data: t.Union[bytes, str], headers: t.Dict[str, str]) -> t.Any:
data = data if isinstance(data, str) else data.decode()
headers = {k.lower(): v for (k, v) in headers.items()}
Expand Down