@suveren/gateway 0.2.5 → 0.2.6
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/content/integrations/calendar.json +2 -0
- package/content/integrations/gmail.json +2 -0
- package/dist/control-plane/index.mjs +76 -1
- package/dist/ui/assets/index-Cg93zQWk.js +102 -0
- package/dist/ui/assets/index-Ch-vXKVZ.css +1 -0
- package/dist/ui/index.html +2 -2
- package/package.json +1 -1
- package/dist/ui/assets/index-B8OeLWqp.css +0 -1
- package/dist/ui/assets/index-CIhRJ6MD.js +0 -102
|
@@ -25,6 +25,8 @@
|
|
|
25
25
|
"authUrl": "https://accounts.google.com/o/oauth2/v2/auth",
|
|
26
26
|
"tokenUrl": "https://oauth2.googleapis.com/token",
|
|
27
27
|
"scopes": [
|
|
28
|
+
"openid",
|
|
29
|
+
"https://www.googleapis.com/auth/userinfo.email",
|
|
28
30
|
"https://www.googleapis.com/auth/calendar.events",
|
|
29
31
|
"https://www.googleapis.com/auth/calendar.readonly"
|
|
30
32
|
],
|
|
@@ -26,6 +26,8 @@
|
|
|
26
26
|
"authUrl": "https://accounts.google.com/o/oauth2/v2/auth",
|
|
27
27
|
"tokenUrl": "https://oauth2.googleapis.com/token",
|
|
28
28
|
"scopes": [
|
|
29
|
+
"openid",
|
|
30
|
+
"https://www.googleapis.com/auth/userinfo.email",
|
|
29
31
|
"https://www.googleapis.com/auth/gmail.modify",
|
|
30
32
|
"https://www.googleapis.com/auth/gmail.send"
|
|
31
33
|
],
|
|
@@ -1583,6 +1583,18 @@ function resolveOrigin(req) {
|
|
|
1583
1583
|
}
|
|
1584
1584
|
var oauthRedirectUris = /* @__PURE__ */ new Map();
|
|
1585
1585
|
var manifestCache = null;
|
|
1586
|
+
function decodeJwtEmail(idToken) {
|
|
1587
|
+
if (!idToken) return void 0;
|
|
1588
|
+
try {
|
|
1589
|
+
const payload = idToken.split(".")[1];
|
|
1590
|
+
if (!payload) return void 0;
|
|
1591
|
+
const json = Buffer.from(payload.replace(/-/g, "+").replace(/_/g, "/"), "base64").toString("utf8");
|
|
1592
|
+
const claims = JSON.parse(json);
|
|
1593
|
+
return typeof claims.email === "string" ? claims.email : void 0;
|
|
1594
|
+
} catch {
|
|
1595
|
+
return void 0;
|
|
1596
|
+
}
|
|
1597
|
+
}
|
|
1586
1598
|
async function getOAuthManifest(integrationId) {
|
|
1587
1599
|
if (!manifestCache) {
|
|
1588
1600
|
try {
|
|
@@ -1660,7 +1672,13 @@ app.get("/auth/oauth/:integrationId/callback", async (req, res) => {
|
|
|
1660
1672
|
res.status(400).send(`<html><body><h2>Token exchange failed</h2><p>${String(tokens.error || "No token received")}</p><script>setTimeout(()=>window.close(),3000)</script></body></html>`);
|
|
1661
1673
|
return;
|
|
1662
1674
|
}
|
|
1663
|
-
const
|
|
1675
|
+
const account = decodeJwtEmail(tokens.id_token);
|
|
1676
|
+
const updatedCreds = {
|
|
1677
|
+
...creds,
|
|
1678
|
+
[oauth.tokenStorage]: tokenValue,
|
|
1679
|
+
_oauthConnectedAt: (/* @__PURE__ */ new Date()).toISOString()
|
|
1680
|
+
};
|
|
1681
|
+
if (account) updatedCreds._oauthAccount = account;
|
|
1664
1682
|
vault.setCredential(integrationId, updatedCreds);
|
|
1665
1683
|
console.log(`[Control Plane] ${integrationId} OAuth tokens stored in vault`);
|
|
1666
1684
|
try {
|
|
@@ -1683,6 +1701,52 @@ app.get("/auth/gmail/callback", (req, res) => {
|
|
|
1683
1701
|
res.redirect(`/auth/oauth/gmail/callback${qs ? "?" + qs : ""}`);
|
|
1684
1702
|
});
|
|
1685
1703
|
var authGuard = requireAuth(vault);
|
|
1704
|
+
app.get("/auth/oauth/:integrationId/health", authGuard, async (req, res) => {
|
|
1705
|
+
const integrationId = String(req.params.integrationId);
|
|
1706
|
+
const manifest = await getOAuthManifest(integrationId);
|
|
1707
|
+
if (!manifest?.oauth) {
|
|
1708
|
+
res.json({ status: "not_configured" });
|
|
1709
|
+
return;
|
|
1710
|
+
}
|
|
1711
|
+
const oauth = manifest.oauth;
|
|
1712
|
+
const creds = vault.getCredential(integrationId);
|
|
1713
|
+
const clientIdKey = oauth.credentialKeys.clientId ?? "clientId";
|
|
1714
|
+
const clientSecretKey = oauth.credentialKeys.clientSecret ?? "clientSecret";
|
|
1715
|
+
const account = creds?._oauthAccount;
|
|
1716
|
+
if (!creds?.[clientIdKey] || !creds?.[clientSecretKey]) {
|
|
1717
|
+
res.json({ status: "not_configured", account });
|
|
1718
|
+
return;
|
|
1719
|
+
}
|
|
1720
|
+
const token = creds[oauth.tokenStorage];
|
|
1721
|
+
if (!token) {
|
|
1722
|
+
res.json({ status: "not_connected", account });
|
|
1723
|
+
return;
|
|
1724
|
+
}
|
|
1725
|
+
if (!/refresh/i.test(oauth.tokenStorage)) {
|
|
1726
|
+
res.json({ status: "unverified", account });
|
|
1727
|
+
return;
|
|
1728
|
+
}
|
|
1729
|
+
try {
|
|
1730
|
+
const r = await fetch(oauth.tokenUrl, {
|
|
1731
|
+
method: "POST",
|
|
1732
|
+
headers: { "Content-Type": "application/x-www-form-urlencoded" },
|
|
1733
|
+
body: new URLSearchParams({
|
|
1734
|
+
grant_type: "refresh_token",
|
|
1735
|
+
refresh_token: token,
|
|
1736
|
+
client_id: creds[clientIdKey],
|
|
1737
|
+
client_secret: creds[clientSecretKey]
|
|
1738
|
+
})
|
|
1739
|
+
});
|
|
1740
|
+
const body = await r.json().catch(() => ({}));
|
|
1741
|
+
if (r.ok && body.access_token) {
|
|
1742
|
+
res.json({ status: "ok", account });
|
|
1743
|
+
return;
|
|
1744
|
+
}
|
|
1745
|
+
res.json({ status: "failed", account, error: body.error_description || body.error || `HTTP ${r.status}` });
|
|
1746
|
+
} catch (err) {
|
|
1747
|
+
res.json({ status: "failed", account, error: err instanceof Error ? err.message : "probe failed" });
|
|
1748
|
+
}
|
|
1749
|
+
});
|
|
1686
1750
|
app.get("/events", requireAuthQueryOrHeader(vault), createEventsHandler());
|
|
1687
1751
|
app.use("/vault", jsonParser, authGuard, createVaultRouter(vault));
|
|
1688
1752
|
app.use("/ai", jsonParser, authGuard, createAIRouter(vault));
|
|
@@ -1943,5 +2007,16 @@ app.listen(port, "0.0.0.0", () => {
|
|
|
1943
2007
|
console.error(`[Control Plane] SP proxy: ${SP_URL2}`);
|
|
1944
2008
|
console.error(`[Control Plane] UI dist: ${UI_DIST}`);
|
|
1945
2009
|
console.error(`[Control Plane] Internal secret: configured`);
|
|
2010
|
+
console.error(`[Control Plane] MCP server: ${MCP_BASE}`);
|
|
2011
|
+
getManifests().then((d) => {
|
|
2012
|
+
const n = d?.manifests?.length ?? 0;
|
|
2013
|
+
if (n === 0) {
|
|
2014
|
+
console.error(`[Control Plane] \u26A0 MCP server at ${MCP_BASE} returned 0 integration manifests \u2014 wrong SUVEREN_MCP_INTERNAL_URL? (dev MCP is :3431, npm is :3430)`);
|
|
2015
|
+
} else {
|
|
2016
|
+
console.error(`[Control Plane] Integrations: ${n} manifests loaded from ${MCP_BASE}`);
|
|
2017
|
+
}
|
|
2018
|
+
}).catch((err) => {
|
|
2019
|
+
console.error(`[Control Plane] \u26A0 Could not reach MCP server at ${MCP_BASE} for manifests \u2014 wrong SUVEREN_MCP_INTERNAL_URL? (dev=:3431, npm=:3430). ${err instanceof Error ? err.message : err}`);
|
|
2020
|
+
});
|
|
1946
2021
|
startUpdateChecker(INSTALL_METHOD, RUNNING_VERSION);
|
|
1947
2022
|
});
|