forked from PipedreamHQ/pipedream
-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathnetlify.app.js
155 lines (148 loc) · 4.15 KB
/
netlify.app.js
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
const axios = require("axios");
const crypto = require("crypto");
const jwt = require('jwt-simple');
const NetlifyAPI = require("netlify");
const parseLinkHeader = require('parse-link-header');
module.exports = {
type: "app",
app: "netlify",
propDefinitions: {
siteId: {
type: "string",
label: "Site ID",
description: "The site for which events must be captured",
async options(context) {
// At the moment we need to "manually" query these items
// instead of using the Netlify client, since it doesn't support
// pagination.
const url = this._sitesEndpoint();
const params = {
per_page: 10,
};
const { data, next } = await this._propDefinitionsOptions(url, params, context);
const options = data.map(site => ({
label: site.name,
value: site.id,
}));
return {
options,
context: {
nextPage: next,
},
};
},
},
},
methods: {
_apiUrl() {
return "https://api.netlify.com/api/v1";
},
_sitesEndpoint() {
const baseUrl = this._apiUrl();
return `${baseUrl}/sites`;
},
_authToken() {
return this.$auth.oauth_access_token;
},
_makeRequestConfig() {
const authToken = this._authToken();
const headers = {
"Authorization": `Bearer ${authToken}`,
"User-Agent": "@PipedreamHQ/pipedream v0.1",
};
return {
headers,
};
},
async _propDefinitionsOptions(url, params, { page, prevContext }) {
let requestConfig = this._makeRequestConfig(); // Basic axios request config
if (page === 0) {
// First time the options are being retrieved.
// Include the parameters provided, which will be persisted
// across the different pages.
requestConfig = {
...requestConfig,
params,
};
} else if (prevContext.nextPage) {
// Retrieve next page of options.
url = prevContext.nextPage.url;
} else {
// No more options available.
return { data: [] };
}
const { data, headers } = await axios.get(url, requestConfig);
// https://docs.netlify.com/api/get-started/#link-header
const { next } = parseLinkHeader(headers.link);
return {
data,
next,
};
},
generateToken() {
return crypto.randomBytes(32).toString("hex");
},
createClient() {
const opts = {
userAgent: "@PipedreamHQ/pipedream v0.1",
pathPrefix: "/api/v1",
accessToken: this._authToken(),
};
return new NetlifyAPI(opts);
},
async createHook(opts) {
const {
event,
url,
siteId,
} = opts;
const token = this.generateToken();
const hookOpts = {
type: "url",
event,
data: {
url,
signature_secret: token,
},
};
const requestParams = {
site_id: siteId,
body: hookOpts,
};
const netlifyClient = this.createClient();
const { id } = await netlifyClient.createHookBySiteId(requestParams);
console.log(
`Created "${event}" webhook for site ID ${siteId}.
(Hook ID: ${id}, endpoint: ${url})`
);
return {
hookId: id,
token,
};
},
async deleteHook(opts) {
const { hookId, siteId } = opts;
const requestParams = {
hook_id: hookId,
};
const netlifyClient = this.createClient();
await netlifyClient.deleteHook(requestParams);
console.log(
`Deleted webhook for site ID ${siteId}.
(Hook ID: ${hookId})`
);
},
isValidSource(headers, bodyRaw, db) {
// Verifies that the event is really coming from Netlify.
// See https://docs.netlify.com/site-deploys/notifications/#payload-signature
const signature = headers["x-webhook-signature"];
const token = db.get("token");
const { sha256 } = jwt.decode(signature, token);
const encoded = crypto
.createHash('sha256')
.update(bodyRaw)
.digest('hex');
return sha256 === encoded;
},
},
};