-
Notifications
You must be signed in to change notification settings - Fork 8
/
server.js
124 lines (109 loc) · 3.88 KB
/
server.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
'use strict';
require('dotenv').config();
const express = require('express');
const session = require('express-session');
const path = require('path');
const morgan = require('morgan');
const encodeUrl = require('encodeurl');
const { nanoid } = require('nanoid');
const SmartApp = require('@smartthings/smartapp');
const port = process.env.PORT || 3000;
const serverUrl = process.env.SERVER_URL || 'http://localhost:3000';
const redirectUri = `${serverUrl}/oauth/callback`;
const scope = encodeUrl('r:locations:* r:scenes:* x:scenes:*');
const appId = process.env.APP_ID;
const clientId = process.env.CLIENT_ID;
const clientSecret = process.env.CLIENT_SECRET;
/* SmartThings API */
const smartApp = new SmartApp()
.appId(appId)
.clientId(clientId)
.clientSecret(clientSecret)
.redirectUri(redirectUri);
/* Webserver setup */
const server = express();
server.set('views', path.join(__dirname, 'views'));
server.set('view engine', 'ejs');
server.use(morgan('dev'));
server.use(express.json());
server.use(express.urlencoded({extended: false}));
server.use(session({
secret: 'oauth example secret',
resave: false,
saveUninitialized: true,
cookie: {secure: false}
}));
server.use(express.static(path.join(__dirname, 'public')));
/* Main page. Shows link to SmartThings if not authenticated and list of scenes afterwards */
server.get('/', function (req, res) {
if (req.session.smartThings) {
// Context cookie found, use it to list scenes
const data = req.session.smartThings;
smartApp.withContext(data).then(ctx => {
ctx.api.scenes.list().then(scenes => {
res.render('scenes', {
installedAppId: data.installedAppId,
locationName: data.locationName,
errorMessage: '',
scenes: scenes
});
}).catch(error => {
res.render('scenes', {
installedAppId: data.installedAppId,
locationName: data.locationName,
errorMessage: `${error.message}`,
scenes: {items:[]}
});
});
});
}
else {
// No context cookie. Display link to authenticate with SmartThings
const state = nanoid(24);
req.session.smartThingsState = state;
res.render('index', {
url: `https://api.smartthings.com/oauth/authorize?client_id=${clientId}&scope=${scope}&response_type=code&redirect_uri=${redirectUri}&state=${state}`
});
}
});
/* Uninstalls app and clears context cookie */
server.get('/logout', async function(req, res) {
const ctx = await smartApp.withContext(req.session.smartThings);
await ctx.api.installedApps.delete();
req.session.destroy(() => {
res.redirect('/');
});
});
/* Executes a scene */
server.post('/scenes/:sceneId', function (req, res) {
smartApp.withContext(req.session.smartThings).then(ctx => {
ctx.api.scenes.execute(req.params.sceneId).then(result => {
res.send(result);
});
});
});
/* Handles OAuth redirect */
server.get('/oauth/callback', async (req, res) => {
// Validate the state
if (req.query.state !== req.session.smartThingsState) {
res.status(400).send('Invalid state');
return;
}
// Exchange the code for the auth token. Returns an API context that can be used for subsequent calls
const ctx = await smartApp.handleOAuthCallback(req);
// Get the location name
const location = await ctx.api.locations.get();
// Set the cookie with the context, including the location ID and name
req.session.smartThings = {
locationId: ctx.locationId,
locationName: location.name,
installedAppId: ctx.installedAppId,
authToken: ctx.authToken,
refreshToken: ctx.refreshToken
};
// Redirect back to the main mage
res.redirect('/');
});
server.listen(port);
console.log(`\nWebsite URL -- Use this URL to log into SmartThings and connect this app to your account:\n${serverUrl}\n`);
console.log(`Redirect URI -- Copy this value into the "Redirection URI(s)" field in the Developer Workspace:\n${redirectUri}`);