127.0.0.1:8000 smart-home-server / master server / utils / hue / auth.js
master

Tree @master (Download .tar.gz)

auth.js @masterraw · history · blame

const utils = require('..');
const ifttt = require('../ifttt');
const v3 = require('node-hue-api').v3;
const time = require('../time');

// Values for the ClientId, ClientSecret and AppId from the Hue Remote Application you create in your developer account.
const remoteBootstrap = v3.api.createRemote(
    process.env.HUE_CLIENT_ID,
    process.env.HUE_CLIENT_SECRET
);

let hue_api;
let update_access_token_timeout;

function authenticate() {
    return utils.query("SELECT access_token, refresh_token, username FROM hue_auth").then(function(rows) {
        if (rows.length) {
            const auth = rows[0];
            if (auth.access_token && auth.refresh_token && auth.username) {
                remoteBootstrap.connectWithTokens(
                    auth.access_token,
                    auth.refresh_token,
                    auth.username
                ).catch(function(error) {
                    console.warn("Failed to get a remote connection using existing tokens");
                    console.error(error);
                }).then(function(api) {
                    hue_api = api;
                    console.log("Philips Hue authentication successful");
                }).finally(schedule_refresh_tokens);
            }
        } else {
            console.log("Cannot authenticate Philips Hue, obtain tokens using init_hue_auth.js");
        }
    });
}

function schedule_refresh_tokens() {
    return utils.query("SELECT access_token_expires, refresh_token_expires FROM hue_auth").then(function(rows) {
        const expirations = rows[0];
        let now = Date.now();
        let time_until_access_token_expires = Math.max(expirations.access_token_expires - now, 0);
        let time_until_refresh_token_expires = Math.max(expirations.refresh_token_expires - now, 0);

        console.log("Days until access token expires:", time_until_access_token_expires / time.one_day);
        console.log("Days until refresh token expires:", time_until_refresh_token_expires / time.one_day);

        return [time_until_access_token_expires, time_until_refresh_token_expires];
    }).then(function([time_until_access_token_expires, time_until_refresh_token_expires]) {
        // Conditional on hue_api being truthy because that means even if we
        // do not have expiration data, the tokens still worked. We should
        // immediately refresh so that we can get new expiration data. In
        // general, the expirations data should not be empty. Still testing.
        if (time_until_refresh_token_expires > 0 || hue_api) {
            clearTimeout(update_access_token_timeout);
            update_access_token_timeout = setTimeout(function() {
                console.log("Time to refresh Philips Hue tokens", time.toString());
                refresh_tokens().then(function() {
                    console.log("Philips Hue tokens updated on", time.toString());
                }).catch(function(error) {
                    console.error("Failed refresh tokens using existing tokens");
                    console.error(error);
                });
            }, time_until_access_token_expires);
            console.log("Token refresh scheduled");
        } else {
            console.error("Philips Hue API tokens expired!");
            ifttt({
                type: "notification",
                data: "Philips Hue API tokens expired!"
            });
        }
    });
}

function refresh_tokens() {
    return hue_api.remote.refreshTokens().then(function(tokens) {
        console.log(tokens);
        console.log(tokens.accessToken);
        console.log(tokens.accessTokenExpiresAt);
        return store_auth({
            access_token: tokens.accessToken,
            access_token_expires: tokens.accessTokenExpiresAt,
            refresh_token: tokens.refreshToken,
            refresh_token_expires: tokens.refreshTokenExpiresAt
        });
    }).then(authenticate);
}

function store_auth(data) {
    console.log(`The new Access Token is valid until:  ${time.toString(time.now(data.access_token_expires))}`);
    console.log(`The new Refresh Token is valid until: ${time.toString(time.now(data.refresh_token_expires))}`);

    return utils.query("UPDATE hue_auth SET ?", data);
}

module.exports = {
    authenticate: authenticate,
    store_auth: store_auth,
    schedule_refresh_tokens: schedule_refresh_tokens,
    get_api: function() {
        return hue_api;
    }
};