diff --git a/Third party auth/com.cep.auth/.debug b/Third party auth/com.cep.auth/.debug new file mode 100644 index 0000000..8886999 --- /dev/null +++ b/Third party auth/com.cep.auth/.debug @@ -0,0 +1,29 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/Third party auth/com.cep.auth/.gitignore b/Third party auth/com.cep.auth/.gitignore new file mode 100644 index 0000000..883aea4 --- /dev/null +++ b/Third party auth/com.cep.auth/.gitignore @@ -0,0 +1,3 @@ +.DS_Store +node_modules +client/js/lib/CSInterface.js diff --git a/Third party auth/com.cep.auth/CSXS/manifest.xml b/Third party auth/com.cep.auth/CSXS/manifest.xml new file mode 100644 index 0000000..7604183 --- /dev/null +++ b/Third party auth/com.cep.auth/CSXS/manifest.xml @@ -0,0 +1,78 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + ./client/index.html + ./host/index.jsx + + + true + + + Panel + test-dropbox-example-app + + + 500 + 350 + + + 200 + 200 + + + 600 + 400 + + + + + + + + + + ./client/localServer.html + + --enable-nodejs + --mixed-context + + + + false + + + Custom + + + 500 + 350 + + + + + + + + \ No newline at end of file diff --git a/Third party auth/com.cep.auth/client/css/style.css b/Third party auth/com.cep.auth/client/css/style.css new file mode 100644 index 0000000..a6cf4ac --- /dev/null +++ b/Third party auth/com.cep.auth/client/css/style.css @@ -0,0 +1,3 @@ +* { + font-family: sans-serif; +} diff --git a/Third party auth/com.cep.auth/client/index.html b/Third party auth/com.cep.auth/client/index.html new file mode 100644 index 0000000..c4164d8 --- /dev/null +++ b/Third party auth/com.cep.auth/client/index.html @@ -0,0 +1,20 @@ + + + + + Dropbox Example App + + + +

Dropbox Example App

+
+ + +
+
+
+ + + + + diff --git a/Third party auth/com.cep.auth/client/js/config.js b/Third party auth/com.cep.auth/client/js/config.js new file mode 100644 index 0000000..6cd3796 --- /dev/null +++ b/Third party auth/com.cep.auth/client/js/config.js @@ -0,0 +1,12 @@ +const CLIENT_ID = "YOUR_DROPBOX_CLIENT_ID"; +const CLIENT_SECRET = "YOUR_DROPBOX_SECRET"; + +try { + if (module) { + module.exports = { + CLIENT_ID: CLIENT_ID, + CLIENT_SECRET: CLIENT_SECRET + } + } +} +catch (err) {} diff --git a/Third party auth/com.cep.auth/client/js/index.js b/Third party auth/com.cep.auth/client/js/index.js new file mode 100644 index 0000000..baf6743 --- /dev/null +++ b/Third party auth/com.cep.auth/client/js/index.js @@ -0,0 +1,55 @@ + +/* + CSInterface +*/ +var csInterface = new CSInterface(); +/* + Linking Server +*/ +csInterface.requestOpenExtension("com.cep.auth.localserver", ""); + +/* + UI Elements +*/ +var loginButton = document.querySelector("#login-button"); +var userButton = document.querySelector("#user-button"); +var canvas = document.querySelector("#canvas"); + +/* + Event listeners +*/ +loginButton.addEventListener("click", login); +userButton.addEventListener("click", getUserInfo); + +/* + Helper methods +*/ + +function login() { + $.ajax({ + type: "GET", + url: "http://localhost:3000/glogin", + success: response => { + window.location.href = response; + }, + error: (jqXHR, textStatus, errorThrown) => { + console.log("error"); + alert(JSON.parse(jqXHR.responseText).error); + } + }) +} + +function getUserInfo() { + $.ajax({ + type: "GET", + url: "http://localhost:3000/user", + success: response => { + canvas.innerHTML = JSON.stringify(response.data); + }, + error: (jqXHR, textStatus, errorThrown) => { + console.log("error"); + alert(JSON.parse(jqXHR.responseText).error); + } + }) + +} diff --git a/Third party auth/com.cep.auth/client/localServer.html b/Third party auth/com.cep.auth/client/localServer.html new file mode 100644 index 0000000..a066d73 --- /dev/null +++ b/Third party auth/com.cep.auth/client/localServer.html @@ -0,0 +1,13 @@ + + + + + + Dropbox Example App + + + + + diff --git a/Third party auth/com.cep.auth/host/index.jsx b/Third party auth/com.cep.auth/host/index.jsx new file mode 100644 index 0000000..e69de29 diff --git a/Third party auth/com.cep.auth/package-lock.json b/Third party auth/com.cep.auth/package-lock.json new file mode 100644 index 0000000..94be03a --- /dev/null +++ b/Third party auth/com.cep.auth/package-lock.json @@ -0,0 +1,565 @@ +{ + "name": "panel-dropbox-example-app", + "version": "1.0.0", + "lockfileVersion": 1, + "requires": true, + "dependencies": { + "accepts": { + "version": "1.3.4", + "resolved": "https://registry.npmjs.org/accepts/-/accepts-1.3.4.tgz", + "integrity": "sha1-hiRnWMfdbSGmR0/whKR0DsBesh8=", + "requires": { + "mime-types": "2.1.17", + "negotiator": "0.6.1" + } + }, + "ansi-regex": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-2.1.1.tgz", + "integrity": "sha1-w7M6te42DYbg5ijwRorn7yfWVN8=" + }, + "array-flatten": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/array-flatten/-/array-flatten-1.1.1.tgz", + "integrity": "sha1-ml9pkFGx5wczKPKgCJaLZOopVdI=" + }, + "async": { + "version": "1.5.2", + "resolved": "https://registry.npmjs.org/async/-/async-1.5.2.tgz", + "integrity": "sha1-7GphrlZIDAw8skHJVhjiCJL5Zyo=" + }, + "axios": { + "version": "0.17.1", + "resolved": "https://registry.npmjs.org/axios/-/axios-0.17.1.tgz", + "integrity": "sha1-LY4+XQvb1zJ/kbyBT1xXZg+Bgk0=", + "requires": { + "follow-redirects": "1.4.1", + "is-buffer": "1.1.6" + } + }, + "basic-auth": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/basic-auth/-/basic-auth-2.0.0.tgz", + "integrity": "sha1-AV2z81PgLlY3d1X5YnQuiYHnu7o=", + "requires": { + "safe-buffer": "5.1.1" + } + }, + "body-parser": { + "version": "1.18.2", + "resolved": "https://registry.npmjs.org/body-parser/-/body-parser-1.18.2.tgz", + "integrity": "sha1-h2eKGdhLR9hZuDGZvVm84iKxBFQ=", + "requires": { + "bytes": "3.0.0", + "content-type": "1.0.4", + "debug": "2.6.9", + "depd": "1.1.2", + "http-errors": "1.6.2", + "iconv-lite": "0.4.19", + "on-finished": "2.3.0", + "qs": "6.5.1", + "raw-body": "2.3.2", + "type-is": "1.6.15" + } + }, + "bytes": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/bytes/-/bytes-3.0.0.tgz", + "integrity": "sha1-0ygVQE1olpn4Wk6k+odV3ROpYEg=" + }, + "camelcase": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/camelcase/-/camelcase-2.1.1.tgz", + "integrity": "sha1-fB0W1nmhu+WcoCys7PsBHiAfWh8=" + }, + "cliui": { + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/cliui/-/cliui-3.2.0.tgz", + "integrity": "sha1-EgYBU3qRbSmUD5NNo7SNWFo5IT0=", + "requires": { + "string-width": "1.0.2", + "strip-ansi": "3.0.1", + "wrap-ansi": "2.1.0" + } + }, + "code-point-at": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/code-point-at/-/code-point-at-1.1.0.tgz", + "integrity": "sha1-DQcLTQQ6W+ozovGkDi7bPZpMz3c=" + }, + "content-disposition": { + "version": "0.5.2", + "resolved": "https://registry.npmjs.org/content-disposition/-/content-disposition-0.5.2.tgz", + "integrity": "sha1-DPaLud318r55YcOoUXjLhdunjLQ=" + }, + "content-type": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/content-type/-/content-type-1.0.4.tgz", + "integrity": "sha512-hIP3EEPs8tB9AT1L+NUqtwOAps4mk2Zob89MWXMHjHWg9milF/j4osnnQLXBCBFBk/tvIG/tUc9mOUJiPBhPXA==" + }, + "cookie": { + "version": "0.3.1", + "resolved": "https://registry.npmjs.org/cookie/-/cookie-0.3.1.tgz", + "integrity": "sha1-5+Ch+e9DtMi6klxcWpboBtFoc7s=" + }, + "cookie-signature": { + "version": "1.0.6", + "resolved": "https://registry.npmjs.org/cookie-signature/-/cookie-signature-1.0.6.tgz", + "integrity": "sha1-4wOogrNCzD7oylE6eZmXNNqzriw=" + }, + "debug": { + "version": "2.6.9", + "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", + "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", + "requires": { + "ms": "2.0.0" + } + }, + "decamelize": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/decamelize/-/decamelize-1.2.0.tgz", + "integrity": "sha1-9lNNFRSCabIDUue+4m9QH5oZEpA=" + }, + "depd": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/depd/-/depd-1.1.2.tgz", + "integrity": "sha1-m81S4UwJd2PnSbJ0xDRu0uVgtak=" + }, + "destroy": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/destroy/-/destroy-1.0.4.tgz", + "integrity": "sha1-l4hXRCxEdJ5CBmE+N5RiBYJqvYA=" + }, + "ee-first": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/ee-first/-/ee-first-1.1.1.tgz", + "integrity": "sha1-WQxhFWsK4vTwJVcyoViyZrxWsh0=" + }, + "encodeurl": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/encodeurl/-/encodeurl-1.0.2.tgz", + "integrity": "sha1-rT/0yG7C0CkyL1oCw6mmBslbP1k=" + }, + "escape-html": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/escape-html/-/escape-html-1.0.3.tgz", + "integrity": "sha1-Aljq5NPQwJdN4cFpGI7wBR0dGYg=" + }, + "etag": { + "version": "1.8.1", + "resolved": "https://registry.npmjs.org/etag/-/etag-1.8.1.tgz", + "integrity": "sha1-Qa4u62XvpiJorr/qg6x9eSmbCIc=" + }, + "express": { + "version": "4.16.2", + "resolved": "https://registry.npmjs.org/express/-/express-4.16.2.tgz", + "integrity": "sha1-41xt/i1kt9ygpc1PIXgb4ymeB2w=", + "requires": { + "accepts": "1.3.4", + "array-flatten": "1.1.1", + "body-parser": "1.18.2", + "content-disposition": "0.5.2", + "content-type": "1.0.4", + "cookie": "0.3.1", + "cookie-signature": "1.0.6", + "debug": "2.6.9", + "depd": "1.1.2", + "encodeurl": "1.0.2", + "escape-html": "1.0.3", + "etag": "1.8.1", + "finalhandler": "1.1.0", + "fresh": "0.5.2", + "merge-descriptors": "1.0.1", + "methods": "1.1.2", + "on-finished": "2.3.0", + "parseurl": "1.3.2", + "path-to-regexp": "0.1.7", + "proxy-addr": "2.0.2", + "qs": "6.5.1", + "range-parser": "1.2.0", + "safe-buffer": "5.1.1", + "send": "0.16.1", + "serve-static": "1.13.1", + "setprototypeof": "1.1.0", + "statuses": "1.3.1", + "type-is": "1.6.15", + "utils-merge": "1.0.1", + "vary": "1.1.2" + } + }, + "finalhandler": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/finalhandler/-/finalhandler-1.1.0.tgz", + "integrity": "sha1-zgtoVbRYU+eRsvzGgARtiCU91/U=", + "requires": { + "debug": "2.6.9", + "encodeurl": "1.0.2", + "escape-html": "1.0.3", + "on-finished": "2.3.0", + "parseurl": "1.3.2", + "statuses": "1.3.1", + "unpipe": "1.0.0" + } + }, + "follow-redirects": { + "version": "1.4.1", + "resolved": "https://registry.npmjs.org/follow-redirects/-/follow-redirects-1.4.1.tgz", + "integrity": "sha512-uxYePVPogtya1ktGnAAXOacnbIuRMB4dkvqeNz2qTtTQsuzSfbDolV+wMMKxAmCx0bLgAKLbBOkjItMbbkR1vg==", + "requires": { + "debug": "3.1.0" + }, + "dependencies": { + "debug": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/debug/-/debug-3.1.0.tgz", + "integrity": "sha512-OX8XqP7/1a9cqkxYw2yXss15f26NKWBpDXQd0/uK/KPqdQhxbPa994hnzjcE2VqQpDslf55723cKPUOGSmMY3g==", + "requires": { + "ms": "2.0.0" + } + } + } + }, + "forwarded": { + "version": "0.1.2", + "resolved": "https://registry.npmjs.org/forwarded/-/forwarded-0.1.2.tgz", + "integrity": "sha1-mMI9qxF1ZXuMBXPozszZGw/xjIQ=" + }, + "fresh": { + "version": "0.5.2", + "resolved": "https://registry.npmjs.org/fresh/-/fresh-0.5.2.tgz", + "integrity": "sha1-PYyt2Q2XZWn6g1qx+OSyOhBWBac=" + }, + "http-errors": { + "version": "1.6.2", + "resolved": "https://registry.npmjs.org/http-errors/-/http-errors-1.6.2.tgz", + "integrity": "sha1-CgAsyFcHGSp+eUbO7cERVfYOxzY=", + "requires": { + "depd": "1.1.1", + "inherits": "2.0.3", + "setprototypeof": "1.0.3", + "statuses": "1.3.1" + }, + "dependencies": { + "depd": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/depd/-/depd-1.1.1.tgz", + "integrity": "sha1-V4O04cRZ8G+lyif5kfPQbnoxA1k=" + }, + "setprototypeof": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/setprototypeof/-/setprototypeof-1.0.3.tgz", + "integrity": "sha1-ZlZ+NwQ+608E2RvWWMDL77VbjgQ=" + } + } + }, + "iconv-lite": { + "version": "0.4.19", + "resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.4.19.tgz", + "integrity": "sha512-oTZqweIP51xaGPI4uPa56/Pri/480R+mo7SeU+YETByQNhDG55ycFyNLIgta9vXhILrxXDmF7ZGhqZIcuN0gJQ==" + }, + "inherits": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.3.tgz", + "integrity": "sha1-Yzwsg+PaQqUC9SRmAiSA9CCCYd4=" + }, + "ini": { + "version": "1.3.5", + "resolved": "https://registry.npmjs.org/ini/-/ini-1.3.5.tgz", + "integrity": "sha512-RZY5huIKCMRWDUqZlEi72f/lmXKMvuszcMBduliQ3nnWbx9X/ZBQO7DijMEYS9EhHBb2qacRUMtC7svLwe0lcw==" + }, + "invert-kv": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/invert-kv/-/invert-kv-1.0.0.tgz", + "integrity": "sha1-EEqOSqym09jNFXqO+L+rLXo//bY=" + }, + "ipaddr.js": { + "version": "1.5.2", + "resolved": "https://registry.npmjs.org/ipaddr.js/-/ipaddr.js-1.5.2.tgz", + "integrity": "sha1-1LUFvemUaYfM8PxY2QEP+WB+P6A=" + }, + "is-buffer": { + "version": "1.1.6", + "resolved": "https://registry.npmjs.org/is-buffer/-/is-buffer-1.1.6.tgz", + "integrity": "sha512-NcdALwpXkTm5Zvvbk7owOUSvVvBKDgKP5/ewfXEznmQFfs4ZRmanOeKBTjRVjka3QFoN6XJ+9F3USqfHqTaU5w==" + }, + "is-fullwidth-code-point": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-1.0.0.tgz", + "integrity": "sha1-754xOG8DGn8NZDr4L95QxFfvAMs=", + "requires": { + "number-is-nan": "1.0.1" + } + }, + "lcid": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/lcid/-/lcid-1.0.0.tgz", + "integrity": "sha1-MIrMr6C8SDo4Z7S28rlQYlHRuDU=", + "requires": { + "invert-kv": "1.0.0" + } + }, + "media-typer": { + "version": "0.3.0", + "resolved": "https://registry.npmjs.org/media-typer/-/media-typer-0.3.0.tgz", + "integrity": "sha1-hxDXrwqmJvj/+hzgAWhUUmMlV0g=" + }, + "merge-descriptors": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/merge-descriptors/-/merge-descriptors-1.0.1.tgz", + "integrity": "sha1-sAqqVW3YtEVoFQ7J0blT8/kMu2E=" + }, + "methods": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/methods/-/methods-1.1.2.tgz", + "integrity": "sha1-VSmk1nZUE07cxSZmVoNbD4Ua/O4=" + }, + "mime": { + "version": "1.4.1", + "resolved": "https://registry.npmjs.org/mime/-/mime-1.4.1.tgz", + "integrity": "sha512-KI1+qOZu5DcW6wayYHSzR/tXKCDC5Om4s1z2QJjDULzLcmf3DvzS7oluY4HCTrc+9FiKmWUgeNLg7W3uIQvxtQ==" + }, + "mime-db": { + "version": "1.30.0", + "resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.30.0.tgz", + "integrity": "sha1-dMZD2i3Z1qRTmZY0ZbJtXKfXHwE=" + }, + "mime-types": { + "version": "2.1.17", + "resolved": "https://registry.npmjs.org/mime-types/-/mime-types-2.1.17.tgz", + "integrity": "sha1-Cdejk/A+mVp5+K+Fe3Cp4KsWVXo=", + "requires": { + "mime-db": "1.30.0" + } + }, + "morgan": { + "version": "1.9.0", + "resolved": "https://registry.npmjs.org/morgan/-/morgan-1.9.0.tgz", + "integrity": "sha1-0B+mxlhZt2/PMbPLU6OCGjEdgFE=", + "requires": { + "basic-auth": "2.0.0", + "debug": "2.6.9", + "depd": "1.1.2", + "on-finished": "2.3.0", + "on-headers": "1.0.1" + } + }, + "ms": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", + "integrity": "sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g=" + }, + "nconf": { + "version": "0.10.0", + "resolved": "https://registry.npmjs.org/nconf/-/nconf-0.10.0.tgz", + "integrity": "sha512-fKiXMQrpP7CYWJQzKkPPx9hPgmq+YLDyxcG9N8RpiE9FoCkCbzD0NyW0YhE3xn3Aupe7nnDeIx4PFzYehpHT9Q==", + "requires": { + "async": "1.5.2", + "ini": "1.3.5", + "secure-keys": "1.0.0", + "yargs": "3.32.0" + } + }, + "negotiator": { + "version": "0.6.1", + "resolved": "https://registry.npmjs.org/negotiator/-/negotiator-0.6.1.tgz", + "integrity": "sha1-KzJxhOiZIQEXeyhWP7XnECrNDKk=" + }, + "number-is-nan": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/number-is-nan/-/number-is-nan-1.0.1.tgz", + "integrity": "sha1-CXtgK1NCKlIsGvuHkDGDNpQaAR0=" + }, + "oauth": { + "version": "0.9.15", + "resolved": "https://registry.npmjs.org/oauth/-/oauth-0.9.15.tgz", + "integrity": "sha1-vR/vr2hslrdUda7VGWQS/2DPucE=" + }, + "on-finished": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/on-finished/-/on-finished-2.3.0.tgz", + "integrity": "sha1-IPEzZIGwg811M3mSoWlxqi2QaUc=", + "requires": { + "ee-first": "1.1.1" + } + }, + "on-headers": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/on-headers/-/on-headers-1.0.1.tgz", + "integrity": "sha1-ko9dD0cNSTQmUepnlLCFfBAGk/c=" + }, + "os-locale": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/os-locale/-/os-locale-1.4.0.tgz", + "integrity": "sha1-IPnxeuKe00XoveWDsT0gCYA8FNk=", + "requires": { + "lcid": "1.0.0" + } + }, + "parseurl": { + "version": "1.3.2", + "resolved": "https://registry.npmjs.org/parseurl/-/parseurl-1.3.2.tgz", + "integrity": "sha1-/CidTtiZMRlGDBViUyYs3I3mW/M=" + }, + "path-to-regexp": { + "version": "0.1.7", + "resolved": "https://registry.npmjs.org/path-to-regexp/-/path-to-regexp-0.1.7.tgz", + "integrity": "sha1-32BBeABfUi8V60SQ5yR6G/qmf4w=" + }, + "proxy-addr": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/proxy-addr/-/proxy-addr-2.0.2.tgz", + "integrity": "sha1-ZXFQT0e7mI7IGAJT+F3X4UlSvew=", + "requires": { + "forwarded": "0.1.2", + "ipaddr.js": "1.5.2" + } + }, + "qs": { + "version": "6.5.1", + "resolved": "https://registry.npmjs.org/qs/-/qs-6.5.1.tgz", + "integrity": "sha512-eRzhrN1WSINYCDCbrz796z37LOe3m5tmW7RQf6oBntukAG1nmovJvhnwHHRMAfeoItc1m2Hk02WER2aQ/iqs+A==" + }, + "range-parser": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/range-parser/-/range-parser-1.2.0.tgz", + "integrity": "sha1-9JvmtIeJTdxA3MlKMi9hEJLgDV4=" + }, + "raw-body": { + "version": "2.3.2", + "resolved": "https://registry.npmjs.org/raw-body/-/raw-body-2.3.2.tgz", + "integrity": "sha1-vNYMd9Prk83gBQKVw/N5OJvIj4k=", + "requires": { + "bytes": "3.0.0", + "http-errors": "1.6.2", + "iconv-lite": "0.4.19", + "unpipe": "1.0.0" + } + }, + "safe-buffer": { + "version": "5.1.1", + "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.1.tgz", + "integrity": "sha512-kKvNJn6Mm93gAczWVJg7wH+wGYWNrDHdWvpUmHyEsgCtIwwo3bqPtV4tR5tuPaUhTOo/kvhVwd8XwwOllGYkbg==" + }, + "secure-keys": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/secure-keys/-/secure-keys-1.0.0.tgz", + "integrity": "sha1-8MgtmKOxOah3aogIBQuCRDEIf8o=" + }, + "send": { + "version": "0.16.1", + "resolved": "https://registry.npmjs.org/send/-/send-0.16.1.tgz", + "integrity": "sha512-ElCLJdJIKPk6ux/Hocwhk7NFHpI3pVm/IZOYWqUmoxcgeyM+MpxHHKhb8QmlJDX1pU6WrgaHBkVNm73Sv7uc2A==", + "requires": { + "debug": "2.6.9", + "depd": "1.1.2", + "destroy": "1.0.4", + "encodeurl": "1.0.2", + "escape-html": "1.0.3", + "etag": "1.8.1", + "fresh": "0.5.2", + "http-errors": "1.6.2", + "mime": "1.4.1", + "ms": "2.0.0", + "on-finished": "2.3.0", + "range-parser": "1.2.0", + "statuses": "1.3.1" + } + }, + "serve-static": { + "version": "1.13.1", + "resolved": "https://registry.npmjs.org/serve-static/-/serve-static-1.13.1.tgz", + "integrity": "sha512-hSMUZrsPa/I09VYFJwa627JJkNs0NrfL1Uzuup+GqHfToR2KcsXFymXSV90hoyw3M+msjFuQly+YzIH/q0MGlQ==", + "requires": { + "encodeurl": "1.0.2", + "escape-html": "1.0.3", + "parseurl": "1.3.2", + "send": "0.16.1" + } + }, + "setprototypeof": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/setprototypeof/-/setprototypeof-1.1.0.tgz", + "integrity": "sha512-BvE/TwpZX4FXExxOxZyRGQQv651MSwmWKZGqvmPcRIjDqWub67kTKuIMx43cZZrS/cBBzwBcNDWoFxt2XEFIpQ==" + }, + "statuses": { + "version": "1.3.1", + "resolved": "https://registry.npmjs.org/statuses/-/statuses-1.3.1.tgz", + "integrity": "sha1-+vUbnrdKrvOzrPStX2Gr8ky3uT4=" + }, + "string-width": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/string-width/-/string-width-1.0.2.tgz", + "integrity": "sha1-EYvfW4zcUaKn5w0hHgfisLmxB9M=", + "requires": { + "code-point-at": "1.1.0", + "is-fullwidth-code-point": "1.0.0", + "strip-ansi": "3.0.1" + } + }, + "strip-ansi": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-3.0.1.tgz", + "integrity": "sha1-ajhfuIU9lS1f8F0Oiq+UJ43GPc8=", + "requires": { + "ansi-regex": "2.1.1" + } + }, + "type-is": { + "version": "1.6.15", + "resolved": "https://registry.npmjs.org/type-is/-/type-is-1.6.15.tgz", + "integrity": "sha1-yrEPtJCeRByChC6v4a1kbIGARBA=", + "requires": { + "media-typer": "0.3.0", + "mime-types": "2.1.17" + } + }, + "unpipe": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/unpipe/-/unpipe-1.0.0.tgz", + "integrity": "sha1-sr9O6FFKrmFltIF4KdIbLvSZBOw=" + }, + "utils-merge": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/utils-merge/-/utils-merge-1.0.1.tgz", + "integrity": "sha1-n5VxD1CiZ5R7LMwSR0HBAoQn5xM=" + }, + "vary": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/vary/-/vary-1.1.2.tgz", + "integrity": "sha1-IpnwLG3tMNSllhsLn3RSShj2NPw=" + }, + "window-size": { + "version": "0.1.4", + "resolved": "https://registry.npmjs.org/window-size/-/window-size-0.1.4.tgz", + "integrity": "sha1-+OGqHuWlPsW/FR/6CXQqatdpeHY=" + }, + "wrap-ansi": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-2.1.0.tgz", + "integrity": "sha1-2Pw9KE3QV5T+hJc8rs3Rz4JP3YU=", + "requires": { + "string-width": "1.0.2", + "strip-ansi": "3.0.1" + } + }, + "y18n": { + "version": "3.2.1", + "resolved": "https://registry.npmjs.org/y18n/-/y18n-3.2.1.tgz", + "integrity": "sha1-bRX7qITAhnnA136I53WegR4H+kE=" + }, + "yargs": { + "version": "3.32.0", + "resolved": "https://registry.npmjs.org/yargs/-/yargs-3.32.0.tgz", + "integrity": "sha1-AwiOnr+edWtpdRYR0qXvWRSCyZU=", + "requires": { + "camelcase": "2.1.1", + "cliui": "3.2.0", + "decamelize": "1.2.0", + "os-locale": "1.4.0", + "string-width": "1.0.2", + "window-size": "0.1.4", + "y18n": "3.2.1" + } + } + } +} diff --git a/Third party auth/com.cep.auth/package.json b/Third party auth/com.cep.auth/package.json new file mode 100644 index 0000000..abc12b4 --- /dev/null +++ b/Third party auth/com.cep.auth/package.json @@ -0,0 +1,23 @@ +{ + "name": "panel-dropbox-example-app", + "version": "1.0.0", + "description": "", + "main": "index.js", + "scripts": { + "test": "echo \"Error: no test specified\" && exit 1" + }, + "repository": { + "type": "git", + "url": "https://git.corp.adobe.com/kwak/panel-trello-example-app.git" + }, + "author": "", + "license": "ISC", + "dependencies": { + "axios": "^0.17.1", + "body-parser": "^1.18.2", + "express": "^4.16.2", + "morgan": "^1.9.0", + "nconf": "^0.10.0", + "oauth": "^0.9.15" + } +} diff --git a/Third party auth/com.cep.auth/readme.md b/Third party auth/com.cep.auth/readme.md new file mode 100644 index 0000000..de7180f --- /dev/null +++ b/Third party auth/com.cep.auth/readme.md @@ -0,0 +1,276 @@ +# panel-thirdparty-auth-example-app + +Many Creative Cloud app extensions require the ability to talk to API services on the web. With both Chromium Embedded Framework (CEF) and Node.js at its core, CEP gives you the flexibility to make network calls from within your extension in the way that makes sense for your workflow + +This sample panel is built to show developers how they can create a Node JS and Express JS based panel to allow users to authenticate using a third party auth (Dropbox in this example) and make basic API calls. + +By the end of this guide, we will have a panel that: + +1. lets users authenticate using their Dropbox credentials +1. makes simple Dropbox API calls like retrieving basic user info using the token retrieved from step #1 + + + + + + +## Contents + +1. [Technology Used](#technology-used) +1. [Prerequisites](#prerequisites) +1. [Configuration Setup](#configuration-setup) + 1. [Set up to sample extension](#set-up-to-sample-extension) + 1. [Configure `mainfest.xml`](#configure-mainfestxml) +1. [Client-side: HTML Markup](#client-side-html-markup) + 1. [`index.html`](#indexhtml) + 1. [`localServer.html`](#localserverhtml) +1. [Client-side: Service API interaction](#client-side-service-api-interaction) + 1. [Instantiate `CSInterface`](#instantiate-csinterface) + 1. [Load the second extension for running an Express server](#load-the-second-extension-for-running-an-express-server) + 1. [Create references to the UI elements](#create-references-to-the-ui-elements) + 1. [Add a click handler to the button](#add-a-click-handler-to-the-button) + 1. [Communicating with the server](#communicating-with-the-server) +1. [Server-side Setup](#server-side-setup) + 1. [Install node modules](#install-node-modules) + 1. [Write server logic in `main.js`](#write-server-logic-in-mainjs) + + + +## Technology Used +- Supported Host Applications: Photoshop, Illustrator, Indesing, Premier Pro +- Libraries/Frameworks/APIs: + - Adobe-specific: [CEP](https://github.com/Adobe-CEP/CEP-Resources) + - Other: [jQuery](https://jquery.com/), [Dropbox Auth API](https://www.dropbox.com/developers/reference/oauth-guide) + +## Prerequisites +This guide will assume that you have installed all software and completed all steps in the following guides: + +- [Getting Started]() +- [Debugging]() + +## Configuration Setup +### Set up to sample extension +The following steps will help you get the sample extension for this guide up and running: + +1. Install the `./com.cep.auth/` directory in your `extensions` folder. ([See the Cookbook](https://github.com/Adobe-CEP/CEP-Resources/blob/master/CEP_8.x/Documentation/CEP%208.0%20HTML%20Extension%20Cookbook.md#extension-folders) if you are unsure where your `extensions` folder is.) +1. [Download CEP's `CSInterface.js` library](https://github.com/Adobe-CEP/CEP-Resources/blob/master/CEP_8.x/CSInterface.js) and move it to `./com.cep.auth/client/js/lib/CSInterface.js`. +1. [Register your app for Dropbox](https://www.dropbox.com/developers/apps/create) + 1. Add the redirect URI configured for this app - `http://localhost:3000/gcallback` + 1. Get the API Key and Secret +1. Find `config.js` at this path: `./com.cep.auth/client/js/config.js`. +1. In `config.js` file, substitute the default strings with your credentials: + +```javascript +const CLIENT_ID = "YOUR_DROPBOX_CLIENT_ID"; +const CLIENT_SECRET = "YOUR_DROPBOX_SECRET"; +``` + +After following these steps, you'll be able to run the sample extension within the host apps indicated in the [Technology Used](#technology-used) section of this guide. + +### Configure `mainfest.xml` +As noted in the [Getting Started guide](), the `manifest.xml` file is where, among other things, you indicate which Creative Cloud host apps and version numbers your extension supports. For this guide, we'll make an extension that supports Photoshop, Illustrator, InDesign, and Premier Pro. So in the `manifest.xml`, make sure you list the supported host apps within the `` element: + +```xml + + + + + + + + + + + + + + + +``` + +Note that the versions indicted in the example code above only target a single version of each host app, for the sake of demo simplicity. Most extension developers will want to target a range of host app versions. To learn how to support multiple host app versions, [see the Cookbook](https://github.com/Adobe-CEP/CEP-Resources/blob/master/CEP_8.x/Documentation/CEP%208.0%20HTML%20Extension%20Cookbook.md#extension-manifest). + +There are more configurations to write in `manifest.xml` since this sample has two separate extensions inside the panel. However, this does not mean that users will have to load two separate panels. The second extension will be loaded automatically in the background when the main extension loads. + +As you can see, `` has two different ``s listed. `com.cep.auth.panel` is the main panel that includes the front-end code and the host application code, `index.jsx` (this sample does not use the host application code). `com.cep.auth.localserver` contains the Node/Express server logic. + +```xml + + + + +``` + +Note that since `com.cep.auth.localserver` will be using Node, two parameters below need to be added to ``. + +```xml + + --enable-nodejs + --mixed-context + +``` + +Also note that while the type of the main extension, `com.cep.auth.panel`, is `Panel`, the type of the server extension, `com.cep.auth.localserver`, is `Custom`. + +```xml + + + + Panel + + + + + Custom + + + +``` +This setting makes the main extension visible to the user and hides the server extension. + +## Client-side: HTML Markup +The user interface for CEP extensions is written in HTML. For this sample, there are two HTML documents. As configured in `manifest.xml`, the main HTML, located at `./com.cep.auth/client/index.html`, is visible to the user while the other, located at `./com.cep.auth/client/localServer.html`, is not. + +### `index.html` +see comments **#1-3**: + +```html + + + + + Dropbox Example App + + + +

Dropbox Example App

+ +
+ + +
+ +
+
+ + + + + + +``` + +### `localServer.html` +see comments **#1**: + +```html + + + + + + Dropbox Example App + + + + +``` + +Note that, while this guide will not cover styling an extension with CSS, the CSS stylesheet for this sample panel can be found at `./com.cep.auth/client/styles/style.css` + +## Client-side: Service API interaction +As we saw in the previous section's `index.html` code, the client-side JavaScript for this extension is located at `./com.cep.auth/client/js/index.js`. We will look at this `index.js` file in this section. + +### Instantiate `CSInterface` + +For any CEP panel, you'll need an instance of `CSInterface`, which, among other things, gives you a way to communicate with the host app's scripting engine: + +```javascript +var csInterface = new CSInterface(); +``` + +We'll make use of this `csInterface` constant later on. + +### Load the second extension for running an Express server +`csInterface` has a method called `requestOpenExtension`, which opens another extension given an extension ID: + +```javascript +csInterface.requestOpenExtension("com.cep.auth.localserver", ""); +``` + +Once the second extension is loaded, the Express located at `/server/main.js` will start as noted in the script in `/client/localServer.html`. + +### Create references to the UI elements +In `index.js`, we'll first reference the elements in our `index.html`: + +```javascript +var loginButton = document.querySelector("#login-button"); +var userButton = document.querySelector("#user-button"); +var canvas = document.querySelector("#canvas"); +``` + +We'll work with these UI elements in the next step. + +### Add a click handler to the button +We'll add a click handler to the buttons: + +```javascript +loginButton.addEventListener("click", login); +userButton.addEventListener("click", getUserInfo); +``` + +We'll make the `login()` and `getUserInfo()` helper methods in the next step. + +### Communicating with the server +In this sample, `jQuery` is used to communicate with the server. (see comments **#1-3**:) +```javascript +function login() { + $.ajax({ + type: "GET", + /* 1) Make sure to target the correct port, `3000` in this case, + and do include the entire url, `http://localhost...` */ + url: "http://localhost:3000/glogin", + success: response => { + /* 2) Server will respond with the auth url, which is used to redirect the user to */ + window.location.href = response; + }, + error: (jqXHR, textStatus, errorThrown) => { + console.log("error"); + alert(JSON.parse(jqXHR.responseText).error); + } + }) +} + +function getUserInfo() { + $.ajax({ + type: "GET", + url: "http://localhost:3000/user", + success: response => { + /* 3) Server will respond with the user's profile data, which will be displayed in the UI*/ + canvas.innerHTML = JSON.stringify(response.data); + }, + error: (jqXHR, textStatus, errorThrown) => { + console.log("error"); + alert(JSON.parse(jqXHR.responseText).error); + } + }) + +} +``` + +## Server-side Setup +### Install node modules +Make sure to install all node dependencies required by this panel. +``` +npm install +``` + +### Write server logic in `main.js` +This sample panel uses `express` and `http` to set up a server. Make sure to use the same port, in this case, `3000`. All of the following endpoints use `axios` library to make API calls. +- `/glogin` endpoint simple constructs the url to hit Dropbox auth endpoint and sends it to the client-side which will redirect to the url. +- `/gcallback` endpoint is designed to receive callback from Dropbox after user successfully gives consent to the app and to retrive `access_token` which is required for making further API calls to Dropbox. +- `/user` endpoint uses the token received from `/gcallback` and sends an API call to Dropbox to retrive user's information. + diff --git a/Third party auth/com.cep.auth/server/main.js b/Third party auth/com.cep.auth/server/main.js new file mode 100644 index 0000000..1b7fa36 --- /dev/null +++ b/Third party auth/com.cep.auth/server/main.js @@ -0,0 +1,73 @@ +const express = require("express"); +const app = express(); +const axios = require("axios"); +const path = require("path"); +const bodyParser = require("body-parser"); +const logger = require("morgan"); +const port = 3000; +const CLIENT_ID = require("../client/js/config.js").CLIENT_ID; +const CLIENT_SECRET = require("../client/js/config.js").CLIENT_SECRET; +const REDIRECT_URL = `http://localhost:${port}/gcallback`; + +module.exports = run + +var token; + +function run(){ + var server = require('http').createServer(); + server.on('request', app); + server.listen(port, function(){ + console.log('Server running'); + }); + + app.use(logger("dev")); + app.use(bodyParser.json()); + app.use(bodyParser.urlencoded({ limit: '50mb',extended: true })); + app.use(express.static(path.join(__dirname, "../client"))); + + + app.get("/glogin", (req, res, next) => { + let url = `https://www.dropbox.com/oauth2/authorize?response_type=code&client_id=${CLIENT_ID}&redirect_uri=${REDIRECT_URL}` + res.status(200).send(url); + }); + + app.get("/gcallback", (req, res, next) => { + let code = req.query.code; + let url = `https://api.dropboxapi.com/oauth2/token?grant_type=authorization_code&code=${code}&client_id=${CLIENT_ID}&client_secret=${CLIENT_SECRET}&redirect_uri=${REDIRECT_URL}` + axios.post(url) + .then(ccResponse => { + token = ccResponse.data.access_token; + res.redirect('/'); + }) + .catch(err => { + if (err.response) { + alert("error!") + alert(err.response) + res.status(err.response.status).json(err.response.data) + } + else if (err.request) { res.status(504).json({"error": err.message}) } + else res.status(500).json({"error": err.message}); + }); + }); + + app.get("/user", (req, res, next) => { + if (token){ + let url = `https://api.dropboxapi.com/2/users/get_current_account?authorization=Bearer ${token}` + axios.post(url) + .then(userResponse => { + res.send(userResponse); + }) + .catch(err => { + if (err.response) { + alert("error!") + console.log(err.response) + res.status(err.response.status).json(err.response.data) + } + else if (err.request) { res.status(504).json({"error": err.message}) } + else res.status(500).json({"error": err.message}); + }); + } else { + res.json(500, {error: "token not found. Please login first"}) + } + }) +} \ No newline at end of file diff --git a/Third party auth/readme-assets/folder-structure.png b/Third party auth/readme-assets/folder-structure.png new file mode 100644 index 0000000..9a0a0e1 Binary files /dev/null and b/Third party auth/readme-assets/folder-structure.png differ diff --git a/Third party auth/readme.md b/Third party auth/readme.md new file mode 100644 index 0000000..a40f829 --- /dev/null +++ b/Third party auth/readme.md @@ -0,0 +1,355 @@ +# panel-thirdparty-auth-example-app + +Many Creative Cloud app extensions require the ability to talk to API services on the web. With both Chromium Embedded Framework (CEF) and Node.js at its core, CEP gives you the flexibility to make network calls from within your extension in the way that makes sense for your workflow + +This sample panel is built to show developers how they can create a Node JS and Express JS based panel to allow users to authenticate using a third party auth (Dropbox in this example) and make basic API calls. + +By the end of this guide, we will have a panel that: + +1. lets users authenticate using their Dropbox credentials +1. makes simple Dropbox API calls like retrieving basic user info using the token retrieved from step #1 + + + + + + +**Contents** + +1. [Technology Used](#technology-used) +1. [Prerequisites](#prerequisites) +1. [Folder Structure](#folder-structure) +1. [Configuration Setup](#configuration-setup) +1. [Client-side: HTML Markup for user-facing extension](#client-side-html-markup-for-user-facing-extension) +1. [Client-side: HTML Markup for Node.js server extension](#client-side-html-markup-for-nodejs-server-extension) +1. [Client-side: Service API interaction](#client-side-service-api-interaction) +1. [Server-side Setup](#server-side-setup) + + + +## Technology Used +- Supported Host Applications: Photoshop, Illustrator, Indesing, Premier Pro +- Libraries/Frameworks/APIs: + - Adobe-specific: [CEP](https://github.com/Adobe-CEP/CEP-Resources) + - Other: [jQuery](https://jquery.com/), [Dropbox Auth API](https://www.dropbox.com/developers/reference/oauth-guide) + +## Prerequisites +This guide will assume that you have installed all software and completed all steps in the following guides: + +- [Getting Started](../readme.md) + +## Folder Structure +If you have a directory structure similar to the one suggested in the [Getting Started Guide](https://github.com/Adobe-CEP/Getting-Started-guides), all you have to add is a folder designated for your server, a Node.js file, a `main.js` file inside the server folder, and another HTML file, `localServer.html`, all under the existing client folder: + +![](readme-assets/folder-structure.png) + +The `main.js` file is a Node.js file where write server logic. The root directory can be saved either at the root level or at the user level, depending on who’s allowed to use the extension (refer to the [CEP 8 HTML Extension Cookbook](https://github.com/Adobe-CEP/CEP-Resources/blob/master/CEP_8.x/Documentation/CEP%208.0%20HTML%20Extension%20Cookbook.md#extension-folders) for the exact paths). + +Note that except for the required `CSXS` folder, which must contain manifest.xml, the folder structure is flexible. + +## Configuration Setup +### Set up to sample extension +The following steps will help you get the sample extension for this guide up and running: + +1. Install the `./com.cep.auth/` directory in your `extensions` folder. ([See the Cookbook](https://github.com/Adobe-CEP/CEP-Resources/blob/master/CEP_8.x/Documentation/CEP%208.0%20HTML%20Extension%20Cookbook.md#extension-folders) if you are unsure where your `extensions` folder is.) +1. [Download CEP's `CSInterface.js` library](https://github.com/Adobe-CEP/CEP-Resources/blob/master/CEP_8.x/CSInterface.js) and move it to `./com.cep.auth/client/js/lib/CSInterface.js`. +1. [Register your app for Dropbox](https://www.dropbox.com/developers/apps/create) + 1. Add the redirect URI configured for this app - `http://localhost:3000/gcallback` + 1. Get the API Key and Secret +1. Find `config.js` at this path: `./com.cep.auth/client/js/config.js`. +1. In `config.js` file, substitute the default strings with your credentials: + +```javascript +const CLIENT_ID = "YOUR_DROPBOX_CLIENT_ID"; +const CLIENT_SECRET = "YOUR_DROPBOX_SECRET"; +``` + +After following these steps, you'll be able to run the sample extension within the host apps indicated in the [Technology Used](#technology-used) section of this guide. + +### Configure `mainfest.xml` +As noted in the [Getting Started guide](https://github.com/Adobe-CEP/Getting-Started-guides), the `manifest.xml` file is where you set various configurations for your panel, such as supported host apps, panel type, CEF parameters, main path, script path, default/minimum/maximum panel size, and others. Refer to the latest version of XML schema in [CEP Github](https://github.com/Adobe-CEP/CEP-Resources/). + +**List supported host apps and versions** + +The first configuration to set in `manifest.xml` is indicating which Creative Cloud host apps and version numbers your extension supports. For this guide, we'll make an extension that supports Photoshop. So in the `manifest.xml`, make sure you list the supported host names for Photoshop within the `` element: + +```xml + + + + + + + + + + +``` + +Note that the versions indicted in the example code above only target a single version of each host app, for the sake of demo simplicity. Most extension developers will want to target a range of host app versions. To learn how to support multiple host app versions, [see the Cookbook](https://github.com/Adobe-CEP/CEP-Resources/blob/master/CEP_8.x/Documentation/CEP%208.0%20HTML%20Extension%20Cookbook.md#extension-manifest). + +**Configure the user-facing extension** + +This sample panel is comprised of two separate extensions. However, this does not mean that users will have to load two separate extensions. Only the user-facing panel will be visible to the user while the second extension will be loaded automatically in the background when a simple JavaScript CEP method is called (This will be covered later). Let's configure the user facing extension first. + +In the `manifest.xml`, there is a tag called `` which lists all extensions used in the panel. Let's list the main extension, which includes the client side and the host application side logic. As configured in `manifest.xml`, this extension will be visible to the user. + +```xml + + + +``` + +The next step is to configure details for this main extension, `com.cep.auth.panel`. You can insert configurations for this extension by starting with the `` tag under the `` tag: + +```xml + + + ... + +``` + +Under this tag, you can provide details, such as type, script paths, menu name, and sizes: + +```xml + + + + ./client/index.html + ./host/index.jsx + + + true + + + Panel + Panel Auth Example + + + 500 + 350 + + + 200 + 200 + + + 600 + 400 + + + + + + +``` + +Now configurations for the main extension have been set up. The next step is to configure the invisible Node.js server extension. + +**Configure the invisible Node.js server extension** + +As mentioned above, there are two separate extensions in this sample panel. The purpose of the second extension,`com.cep.auth.localserver`, is to set and start the Node.js server. + +Let's add this second extension to the `` tag. + +```xml + + + + +``` + +Similar to setting the main extension, you need to configure details for this invisible extension, `com.cep.auth.localserver`. Note that you can insert multiple `` tags under the `` tag. You need to simply insert another `` tag for this server extension. + +```xml + +``` + +Under this tag, you can provide details, such as type, script paths, menu name, and sizes: + +```xml + + + + ./client/localServer.html + + --enable-nodejs + --mixed-context + + + + false + + + Custom + + + 500 + 350 + + + + + + +``` + +Note that since `com.cep.auth.localserver` will be using Node.js, the two parameters, `--enable-nodejs` and `--mixed-context`, are added within `` as seen above. Also, the `` tag is set to `false` and the `` of the extension is set to `Custom`. This setting makes this server extension invisible to the user. + +## Client-side: HTML Markup for user-facing extension +The user interface for CEP extensions is written in HTML. For this sample, you will need to create two HTML documents, one for each extension. Let's create a HTML for the main extension first. + +As written in the `` tag of the extension in the `manifest.xml` file, you will find the main HTML located at `./com.cep.auth/client/index.html`. This HTML will be loaded and be visible to the user. + +see comments **#1-3**: + +```html + + + + + Dropbox Example App + + + +

Dropbox Example App

+ + +
+ + +
+ + +
+
+ + + + + + + +``` + +## Client-side: HTML Markup for Node.js server extension + +As written in the `` tag of the server extension, another HTML markup will be loaded from `./com.cep.auth/client/localServer.html` in the background and run the `cep_node` method to start the Node.JS server at `/server/main.js`. This HTML will be invisible to users as mentioned above. + +_Note: the server extension will load only after the main extension's JavaScript invokes `csInterface.requestOpenExtension()` function. This will be explained shortly in [the later section](#load-the-second-extension-for-running-an-express-server)_ + +see comments **#1**: + +```html + + + + + + Dropbox Example App + + + + +``` + +The sole purpose of this HTML markup for the server extension, `com.cep.import.localserver`, is to start the Node.js server. This page will not be visible to users. + +## Client-side: Service API interaction +As we saw in the previous section's `index.html` code, the client-side JavaScript for this extension is located at `./com.cep.auth/client/js/index.js`. We will look at this `index.js` file in this section. + +### Instantiate `CSInterface` + +For any CEP panel, you'll need an instance of `CSInterface`, which, among other things, gives you a way to communicate with the host app's scripting engine: + +```javascript +var csInterface = new CSInterface(); +``` + +We'll make use of this `csInterface` constant later on. + +### Load the second extension for running an Express server +`csInterface` has a method called `requestOpenExtension`, which opens another extension given an extension ID. In this sample, this method is used to launch the server extension: + +```javascript +csInterface.requestOpenExtension("com.cep.auth.localserver", ""); +``` + +Simply include the line above in your main extension’s JavaScript file, `client/index.js`. This will open the HTML markup of the invisible server extension. Then, JavaScript written in the HTML markup will start the Node.js server located at `/server/main.js`. Once the second extension is loaded, the Express located at `/server/main.js` will start as written in `/client/localServer.html`. + +### Create references to the UI elements +In `index.js`, we'll first reference the elements in our `index.html`: + +```javascript +var loginButton = document.querySelector("#login-button"); +var userButton = document.querySelector("#user-button"); +var canvas = document.querySelector("#canvas"); +``` + +We'll work with these UI elements in the next step. + +### Add a click handler to the button +We'll add a click handler to the buttons: + +```javascript +loginButton.addEventListener("click", login); +userButton.addEventListener("click", getUserInfo); +``` + +We'll make the `login()` and `getUserInfo()` helper methods in the next step. + +### Communicating with the server +In this sample, `jQuery` is used to communicate with the server. (see comments **#1-3**:) +```javascript +function login() { + $.ajax({ + type: "GET", + /* 1) Make sure to target the correct port, `3000` in this case, + and do include the entire url, `http://localhost...` */ + url: "http://localhost:3000/glogin", + success: response => { + /* 2) Server will respond with the auth url, which is used to redirect the user to */ + window.location.href = response; + }, + error: (jqXHR, textStatus, errorThrown) => { + console.log("error"); + alert(JSON.parse(jqXHR.responseText).error); + } + }) +} + +function getUserInfo() { + $.ajax({ + type: "GET", + url: "http://localhost:3000/user", + success: response => { + /* 3) Server will respond with the user's profile data, which will be displayed in the UI*/ + canvas.innerHTML = JSON.stringify(response.data); + }, + error: (jqXHR, textStatus, errorThrown) => { + console.log("error"); + alert(JSON.parse(jqXHR.responseText).error); + } + }) + +} +``` + +## Server-side Setup +### Install Node.js and npm +[Download and install Node.js and its package manager, npm](https://www.npmjs.com/get-npm), and make sure you have the `package.json` file in the root level directory of your panel. + +### Install node modules +Make sure to install all node dependencies required by this panel. +``` +npm install +``` + +### Write server logic in `main.js` +This sample panel uses `express` and `http` to set up a server. Make sure to use the same port, in this case, `3000`. All of the following endpoints use `axios` library to make API calls. +- `/glogin` endpoint simple constructs the url to hit Dropbox auth endpoint and sends it to the client-side which will redirect to the url. +- `/gcallback` endpoint is designed to receive callback from Dropbox after user successfully gives consent to the app and to retrive `access_token` which is required for making further API calls to Dropbox. +- `/user` endpoint uses the token received from `/gcallback` and sends an API call to Dropbox to retrive user's information.