Fix OAuth2 pk12 key download prompt.
[xtuple] / enyo-client / extensions / source / oauth2 / client / models / oauth2.js
1 /*jshint indent:2, curly:true, eqeqeq:true, immed:true, latedef:true,
2 newcap:true, noarg:true, regexp:true, undef:true, strict:true, trailing:true,
3 white:true*/
4 /*global XT:true, XM:true, Backbone:true, _:true, window:true */
5
6 (function () {
7   "use strict";
8
9   XT.extensions.oauth2.initModels = function () {
10
11     //
12     // MODELS
13     //
14
15     XM.Oauth2client = XM.Model.extend({
16
17       recordType: "XM.Oauth2client",
18
19       autoFetchId: true,
20
21       defaults: function () {
22         return {
23           isActive: true
24         };
25       },
26
27       readOnlyAttributes: [
28         "clientID",
29         "clientSecret",
30         "issued",
31         "organization"
32       ],
33
34       bindEvents: function () {
35         XM.Model.prototype.bindEvents.apply(this, arguments);
36         this.on('statusChange', this.statusDidChange);
37       },
38
39       // clientType must not be editable once first saved.
40       statusDidChange: function () {
41         this.setReadOnly('clientType', this.getStatus() !== XM.Model.READY_NEW);
42
43         if (this.getStatus() === XM.Model.READY_NEW) {
44           this.set('clientID', XT.getOrganizationPath().substring(1) + "_" + XT.generateUUID());
45           // XXX the secret is only relevant for websites, but we generate it here
46           // for both because it's required to be unique on the DB level
47           // secret keys only seem to be applicable for website clients, so we might
48           // not want to make it unique
49           this.set('clientSecret', XT.generateUUID());
50           this.set('issued', new Date());
51         }
52       },
53
54       save: function (key, value, options) {
55         // Handle both `"key", value` and `{key: value}` -style arguments.
56         if (_.isObject(key) || _.isEmpty(key)) {
57           options = value;
58         }
59         options = options ? _.clone(options) : {};
60
61         var success = options.success,
62           status = this.getStatus(),
63           that = this;
64
65         options.success = function (model, resp, options) {
66           if (status === XM.Model.READY_NEW && that.get("clientType") === 'jwt bearer') {
67             // Download the private key.
68
69             // The javascript download method avoids target = "_blank" and the need to
70             // reload the app to see the new client. Pop up blockers should not be an issue.
71             // @See: http://stackoverflow.com/questions/3749231/download-file-using-javascript-jquery/3749395#3749395
72             var downloadURL = function downloadURL(url) {
73               var hiddenIFrameID = 'hiddenDownloader',
74                 iframe = document.getElementById(hiddenIFrameID);
75
76               if (iframe === null) {
77                 iframe = document.createElement('iframe');
78                 iframe.id = hiddenIFrameID;
79                 iframe.style.display = 'none';
80                 document.body.appendChild(iframe);
81               }
82
83               iframe.src = url;
84             };
85
86             downloadURL(XT.getOrganizationPath() + '/oauth/generate-key?id=' + that.id);
87
88             // This prompts for the download without using target = "_blank" and a new tab.
89             // It should avoid pop up blockers from preventing the download. It does warn about
90             // leaving the page, but it returns right back to the original path without needing to
91             // reload the app. Downside... it requires reloading the app to see the client just added.
92             //window.location.assign(XT.getOrganizationPath() + '/oauth/generate-key?id=' + that.id);
93
94             // This opens the download in a new tab and causes pop up blockers to block this action.
95             //window.open(XT.getOrganizationPath() + '/oauth/generate-key?id=' + that.id,
96             //  '_newtab');
97           }
98
99           if (success) { success(model, resp, options); }
100         };
101
102         // Handle both `"key", value` and `{key: value}` -style arguments.
103         if (_.isObject(key) || _.isEmpty(key)) {
104           value = options;
105         }
106
107         if (status === XM.Model.READY_NEW && that.get("clientType") === 'jwt bearer') {
108           // The order of operations for a new jwt bearer is
109           // 1. Notify the user that the download is coming
110           // 2. Save normally
111           // 3. Open the download tab.
112           //
113           // It's a little curious that 2 happens after 1, but the notify listener
114           // on the workspace gets destroyed by the time we would need it otherwise.
115           that.notify("_generatingPrivateKey".loc(), {callback: function () {
116             XM.Model.prototype.save.call(that, key, value, options);
117           }});
118         } else {
119           XM.Model.prototype.save.call(this, key, value, options);
120         }
121       }
122
123     });
124
125     XM.Oauth2clientRedirs = XM.Model.extend({
126
127       recordType: "XM.Oauth2clientRedirs",
128
129       autoFetchId: true
130
131     });
132
133     //
134     // COLLECTIONS
135     //
136
137     XM.Oauth2clientCollection = XM.Collection.extend({
138       model: XM.Oauth2client
139     });
140
141     XM.Oauth2clientRedirsCollection = XM.Collection.extend({
142       model: XM.Oauth2clientRedirs
143     });
144   };
145 }());