├── .gitignore
├── IAMFox-src.app
└── Contents
│ ├── Info.plist
│ ├── MacOS
│ └── xulrunner
│ ├── PkgInfo
│ └── Resources
├── README
├── Resources
├── IAMFOX.icns
├── application.ini
├── chrome
│ ├── chrome.manifest
│ ├── content
│ │ ├── about-dialog.xul
│ │ ├── about.png
│ │ ├── account-dialog.xul
│ │ ├── account-tree-view.js
│ │ ├── error-dialog.xul
│ │ ├── exp_imp.js
│ │ ├── favicon.png
│ │ ├── group-add-dialog.xul
│ │ ├── group-detail-window.js
│ │ ├── group-detail-window.xul
│ │ ├── group-edit-dialog.xul
│ │ ├── group-tabpanel.xul
│ │ ├── group-tree-view.js
│ │ ├── iam-client.js
│ │ ├── iamfox.xul
│ │ ├── io.js
│ │ ├── loader.gif
│ │ ├── main.js
│ │ ├── main.xul
│ │ ├── preferences.js
│ │ ├── server-cert-add-window.js
│ │ ├── server-cert-add-window.xul
│ │ ├── server-cert-edit-dialog.xul
│ │ ├── server-cert-tabpanel.xul
│ │ ├── server-cert-tree-view.js
│ │ ├── sha1.js
│ │ ├── signing-cert-add-dialog.xul
│ │ ├── signing-cert-edit-dialog.xul
│ │ ├── user-add-dialog.xul
│ │ ├── user-cert-window.js
│ │ ├── user-cert-window.xul
│ │ ├── user-create-login-profile-dialog.xul
│ │ ├── user-detail-window.js
│ │ ├── user-detail-window.xul
│ │ ├── user-edit-dialog.xul
│ │ ├── user-group-window.js
│ │ ├── user-group-window.xul
│ │ ├── user-open-console-dialog.xul
│ │ ├── user-tabpanel.xul
│ │ ├── user-tree-view.js
│ │ ├── user-view-key-dialog.xul
│ │ ├── user-view-key-tree-view.js
│ │ └── utils.js
│ ├── icons
│ │ └── default
│ │ │ └── main-window.ico
│ ├── install.rdf
│ ├── locale
│ │ └── en-US
│ │ │ └── iamfox.dtd
│ └── skin
│ │ └── classic
│ │ ├── iamfox.css
│ │ └── menuicon.png
└── defaults
│ └── preferences
│ └── prefs.js
├── iam-fox.ci
├── pack-osx.sh
├── pack-win.sh
└── pack-xpi.sh
/.gitignore:
--------------------------------------------------------------------------------
1 | syntax: glob
2 | .DS_Store
3 | *.dmg
4 | IAMFox.app
5 | iam-fox_win
6 | *setup.exe
7 | *.log
8 | *.xpi
9 |
--------------------------------------------------------------------------------
/IAMFox-src.app/Contents/Info.plist:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | CFBundleExecutable
6 | xulrunner
7 | CFBundleGetInfoString
8 | IAMFox
9 | CFBundleIconFile
10 | IAMFOX.icns
11 | CFBundleIdentifier
12 | xulrunner.iamfox
13 | CFBundleInfoDictionaryVersion
14 | 6.0
15 | CFBundleName
16 | IAMFox
17 | CFBundlePackageType
18 | APPL
19 | CFBundleShortVersionString
20 | 0.3.0
21 | CFBundleSignature
22 | IAMFOX
23 | CFBundleVersion
24 | 0.1.6
25 | NSAppleScriptEnabled
26 |
27 |
28 |
29 |
--------------------------------------------------------------------------------
/IAMFox-src.app/Contents/MacOS/xulrunner:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/cookpad/iam-fox/675f751976bab0db79766bd03a76218c20122c8c/IAMFox-src.app/Contents/MacOS/xulrunner
--------------------------------------------------------------------------------
/IAMFox-src.app/Contents/PkgInfo:
--------------------------------------------------------------------------------
1 | APPLIAMFOX
2 |
--------------------------------------------------------------------------------
/IAMFox-src.app/Contents/Resources:
--------------------------------------------------------------------------------
1 | ../../Resources
--------------------------------------------------------------------------------
/README:
--------------------------------------------------------------------------------
1 | = IAM Fox
2 |
3 | == Description
4 |
5 | IAM Fox is a GUI client of AWS Identity and Access Management (IAM)
6 |
7 | see http://aws.amazon.com/iam/
8 |
9 | == Requires
10 |
11 | * OSX
12 | * Application bundle contains XULRunner runtime
13 | * If the application doesn't start, please install XULRunner runtime
14 | * http://releases.mozilla.org/pub/mozilla.org/xulrunner/releases/
15 | * Windows
16 | * Installer contains XULRunner runtime
17 |
18 | == Credit
19 |
20 | * Icon from 'PC 100 Icon Pack'
21 | * http://pc.de/icons/
22 |
--------------------------------------------------------------------------------
/Resources/IAMFOX.icns:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/cookpad/iam-fox/675f751976bab0db79766bd03a76218c20122c8c/Resources/IAMFOX.icns
--------------------------------------------------------------------------------
/Resources/application.ini:
--------------------------------------------------------------------------------
1 | [App]
2 | Vendor=winebarrel
3 | Name=IAM Fox
4 | Version=0.1.6
5 | BuildID=$BuildID: 537c6f9791b882a77d163b68781e979b24048a5f $
6 | Copyright=Copyright (c) 2011- Genki Sugawara
7 | ID=sgwr_dts@yahoo.co.jp
8 |
9 | [Gecko]
10 | MinVersion=1.8
11 | MaxVersion=1.9.*
12 |
--------------------------------------------------------------------------------
/Resources/chrome/chrome.manifest:
--------------------------------------------------------------------------------
1 | content iamfox content/
2 | locale iamfox en-US locale/en-US/
3 | skin iamfox classic/1.0 skin/classic/
4 | overlay chrome://browser/content/browser.xul chrome://iamfox/content/iamfox.xul
5 |
--------------------------------------------------------------------------------
/Resources/chrome/content/about-dialog.xul:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
41 |
--------------------------------------------------------------------------------
/Resources/chrome/content/about.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/cookpad/iam-fox/675f751976bab0db79766bd03a76218c20122c8c/Resources/chrome/content/about.png
--------------------------------------------------------------------------------
/Resources/chrome/content/account-dialog.xul:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
110 |
--------------------------------------------------------------------------------
/Resources/chrome/content/account-tree-view.js:
--------------------------------------------------------------------------------
1 | function AccountTreeView(userNameElement, accessKeyIdElement, secretAccessKeyElement) {
2 | this.userNameElement = userNameElement;
3 | this.accessKeyIdElement = accessKeyIdElement;
4 | this.secretAccessKeyElement = secretAccessKeyElement;
5 |
6 | this.rowCount = 0;
7 | this.selection = null;
8 | this.sorted = false;
9 | this.data = [];
10 | }
11 |
12 | AccountTreeView.prototype = {
13 | updateData: function() {
14 | var accounts = Prefs.getAccountList();
15 | var data = [];
16 |
17 | for (var i = 0; i < accounts.length; i++) {
18 | var account = accounts[i];
19 | data.push([account[0], account[1].accessKeyId, account[1].secretAccessKey]);
20 | }
21 |
22 | this.data = data;
23 | },
24 |
25 | getCellText: function(row, column) {
26 | if (column.id == 'account-tree-use') {
27 | return null;
28 | }
29 |
30 | var accounts = Prefs.getAccountList();
31 |
32 | var idx = column.id.toString().split('.');
33 | idx = idx[idx.length - 1];
34 |
35 | return this.data[row][idx];
36 | },
37 |
38 | getCellValue: function(row, column) {
39 | if (column.id != 'account-tree-use') {
40 | return null;
41 | }
42 |
43 | var userName = this.data[row][0];
44 | var currentUser = Prefs.currentUser;
45 |
46 | return (currentUser && (currentUser == userName));
47 | },
48 |
49 | setTree: function(tree) {
50 | this.tree = tree;
51 | },
52 |
53 | isEditable: function(row, column) {
54 | return (column.id == 'account-tree-use');
55 | },
56 |
57 | setCellValue: function(row, column, value) {
58 | if (!value) { return; }
59 |
60 | var userName = this.data[row][0];
61 | Prefs.currentUser = userName;
62 | this.refresh();
63 | },
64 |
65 | refresh: function() {
66 | this.updateData();
67 |
68 | if (this.rowCount != this.data.length) {
69 | this.tree.rowCountChanged(0, -this.rowCount);
70 | this.rowCount = this.data.length;
71 | this.tree.rowCountChanged(0, this.rowCount);
72 | }
73 |
74 | this.tree.invalidate();
75 | },
76 |
77 | selectedRow: function() {
78 | var idx = this.selection.currentIndex;
79 | return (idx != -1) ? this.data[idx] : null;
80 | },
81 |
82 | copyColumnToClipboard: function(name) {
83 | var row = this.selectedRow();
84 |
85 | if (row) {
86 | var value = (row[name] || '').toString().trim();
87 | if (!value) { value = '(empty)'; }
88 | copyToClipboard(value);
89 | }
90 | },
91 |
92 | addAccount: function(userName, accessKeyId, secretAccessKey) {
93 | Prefs.addAccount(userName, accessKeyId, secretAccessKey);
94 | this.refresh();
95 | },
96 |
97 | deleteAccount: function() {
98 | var row = this.selectedRow();
99 | if (!row) { return; }
100 |
101 | var userName = row[0];
102 |
103 | if (!confirm("Are you sure you want to delete '" + userName + "' ?")) {
104 | return;
105 | }
106 |
107 | Prefs.deleteAccount(userName);
108 | this.refresh();
109 | },
110 |
111 | onDblclick: function(event) {
112 | var row = this.selectedRow();
113 |
114 | if (!row || (event && event.target.tagName != 'treechildren')) {
115 | return;
116 | }
117 |
118 | this.userNameElement.value = row[0];
119 | this.accessKeyIdElement.value = row[1];
120 | this.secretAccessKeyElement.value = row[2];
121 | }
122 | };
123 |
--------------------------------------------------------------------------------
/Resources/chrome/content/error-dialog.xul:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
40 |
--------------------------------------------------------------------------------
/Resources/chrome/content/exp_imp.js:
--------------------------------------------------------------------------------
1 | function exportKeysToJson() {
2 | var fp = newFilePicker();
3 | fp.init(window, 'Export keys', Components.interfaces.nsIFilePicker.modeSave);
4 | fp.defaultString = 'awskeys.json';
5 | fp.appendFilter('JSON (*.json)', '*.json');
6 |
7 | var result = fp.show();
8 |
9 | switch (result) {
10 | case Components.interfaces.nsIFilePicker.returnOK:
11 | case Components.interfaces.nsIFilePicker.returnReplace:
12 | exportKeys(fp.file);
13 | break;
14 | }
15 | }
16 |
17 | function exportKeys(fout) {
18 | var data = {
19 | userAccessKeyIds: Prefs.userAccessKeyIds,
20 | userSecretAccessKeys: Prefs.userSecretAccessKeys
21 | };
22 |
23 | var rv = FileIO.write(fout, data.toSource());
24 |
25 | return rv;
26 | }
27 |
28 | function importJsonToKeys() {
29 | var fp = newFilePicker();
30 | fp.init(window, 'Import and Merge keys', Components.interfaces.nsIFilePicker.modeOpen);
31 | fp.appendFilter('JSON (*.json)', '*.json');
32 |
33 | var result = fp.show();
34 |
35 | switch (result) {
36 | case Components.interfaces.nsIFilePicker.returnOK:
37 | case Components.interfaces.nsIFilePicker.returnReplace:
38 | importKeys(fp.file);
39 | break;
40 | }
41 | }
42 |
43 | function importKeys(fin) {
44 | var new_data = FileIO.read(fin);
45 |
46 | if (!new_data) {
47 | alert("Cannnot read file.");
48 | return false;
49 | }
50 |
51 | try {
52 | new_data = eval(new_data);
53 | } catch (e) {
54 | alert(e);
55 | return false;
56 | }
57 |
58 | var newUserAccessKeyIds = new_data.userAccessKeyIds;
59 | var newUserSecretAccessKeys = new_data.userSecretAccessKeys;
60 |
61 | Prefs.mergeUserAccessKeyIds(newUserAccessKeyIds);
62 | Prefs.mergeUserSecretAccessKeys(newUserSecretAccessKeys);
63 |
64 | return true;
65 | }
66 |
--------------------------------------------------------------------------------
/Resources/chrome/content/favicon.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/cookpad/iam-fox/675f751976bab0db79766bd03a76218c20122c8c/Resources/chrome/content/favicon.png
--------------------------------------------------------------------------------
/Resources/chrome/content/group-add-dialog.xul:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
61 |
--------------------------------------------------------------------------------
/Resources/chrome/content/group-detail-window.js:
--------------------------------------------------------------------------------
1 | function windowOnLoad() {
2 | var args = window.arguments[0];
3 | document.title = 'Policies - ' + args.groupName;
4 | refreshGroupPolicy();
5 | }
6 |
7 | function listboxOnSelect(event) {
8 | var args = window.arguments[0];
9 | var iamcli = args.iamcli;
10 | var groupName = args.groupName;
11 |
12 | var item = event.currentTarget;
13 |
14 | if (!item || !item.value) {
15 | return;
16 | }
17 |
18 | var policyName = item.value;
19 |
20 | protect(function() {
21 | var xhr = inProgress(function() {
22 | var params = [['GroupName', groupName], ['PolicyName', policyName]];
23 | return iamcli.query_or_die('GetGroupPolicy', params);
24 | });
25 |
26 | var textbox = $('group-policy-textbox');
27 | var policy = xhr.xml().GetGroupPolicyResult;
28 | textbox.value = decodeURIComponent(policy.PolicyDocument);
29 | disableUpdateButton();
30 | });
31 | }
32 |
33 | function inProgress(callback) {
34 | var loader = $('group-policy-loader');
35 | loader.hidden = false;
36 |
37 | var retval = null;
38 | var exception = null;
39 |
40 | try {
41 | retval = callback();
42 | } catch (e) {
43 | exception = e;
44 | }
45 |
46 | loader.hidden = true;
47 |
48 | if (exception) {
49 | throw exception;
50 | }
51 |
52 | return retval;
53 | }
54 |
55 | function addGroupPolicy() {
56 | var args = window.arguments[0];
57 | var iamcli = args.iamcli;
58 | var groupName = args.groupName;
59 | var xhr = null;
60 |
61 | var policyName = prompt('Policy Name');
62 | policyName = (policyName || '').trim();
63 |
64 | if (policyName.length < 1) {
65 | return;
66 | }
67 |
68 | var listbox = $('group-policy-listbox');
69 |
70 | for (var i = 0; i < listbox.itemCount; i++) {
71 | var item = listbox.getItemAtIndex(i);
72 |
73 | if (item.value == policyName) {
74 | alert('Duplicate policy');
75 | return;
76 | }
77 | }
78 |
79 | protect(function() {
80 | inProgress(function() {
81 | var params = [
82 | ['GroupName', groupName],
83 | ['PolicyName', policyName],
84 | ['PolicyDocument', POLICY_ALLOW_ALL]
85 | ];
86 |
87 | iamcli.query_or_die('PutGroupPolicy', params);
88 | });
89 |
90 | var textbox = $('group-policy-textbox');
91 | var item = listbox.appendItem(policyName, policyName);
92 | listbox.selectItem(item);
93 | textbox.value = POLICY_ALLOW_ALL;
94 | disableUpdateButton();
95 | });
96 | }
97 |
98 | function deleteGroupPolicy() {
99 | var args = window.arguments[0];
100 | var iamcli = args.iamcli;
101 | var groupName = args.groupName;
102 |
103 | var listbox = $('group-policy-listbox');
104 | var item = listbox.selectedItem;
105 |
106 | if (!item || !item.value) {
107 | return;
108 | }
109 |
110 | var policyName = item.value;
111 |
112 | if (!confirm("Are you sure you want to delete '" + policyName + " ' ?")) {
113 | return;
114 | }
115 |
116 | protect(function() {
117 | inProgress(function() {
118 | var params = [['GroupName', groupName], ['PolicyName', policyName]];
119 | iamcli.query_or_die('DeleteGroupPolicy', params);
120 | });
121 |
122 | var textbox = $('group-policy-textbox');
123 | listbox.removeItemAt(listbox.currentIndex);
124 | listbox.clearSelection();
125 | textbox.value = null;
126 | });
127 | }
128 |
129 | function refreshGroupPolicy() {
130 | var args = window.arguments[0];
131 | var iamcli = args.iamcli;
132 | var groupName = args.groupName;
133 |
134 | protect(function() {
135 | var policyNames = [];
136 |
137 | var walk = function(marker) {
138 | var params = [['GroupName', groupName]];
139 |
140 | if (marker) {
141 | params.push(['Marker', marker])
142 | }
143 |
144 | var xhr = inProgress(function() {
145 | return iamcli.query_or_die('ListGroupPolicies', params);
146 | });
147 |
148 | var xml = xhr.xml();
149 |
150 | for each (var member in xml..PolicyNames.member) {
151 | policyNames.push(member);
152 | }
153 |
154 | var isTruncated = ((xml..IsTruncated || '').toString().trim().toLowerCase() == 'true');
155 |
156 | return isTruncated ? (xml..Marker || '').toString().trim() : null;
157 | }.bind(this);
158 |
159 | var marker = null;
160 |
161 | do {
162 | marker = walk(marker);
163 | } while (marker);
164 |
165 | var listbox = $('group-policy-listbox');
166 | var textbox = $('group-policy-textbox');
167 |
168 | listbox.clearSelection();
169 | textbox.value = null;
170 | disableUpdateButton();
171 |
172 | for (var i = listbox.itemCount - 1; i >= 0; i--) {
173 | listbox.removeItemAt(i);
174 | }
175 |
176 | for (var i = 0; i < policyNames.length; i++) {
177 | var policyName = policyNames[i];
178 | listbox.appendItem(policyName, policyName);
179 | }
180 | });
181 | }
182 |
183 | function updateGroupPolicy() {
184 | var args = window.arguments[0];
185 | var iamcli = args.iamcli;
186 | var groupName = args.groupName;
187 |
188 | var listbox = $('group-policy-listbox');
189 | var textbox = $('group-policy-textbox');
190 |
191 | var item = listbox.selectedItem;
192 |
193 | if (!item || !item.value) {
194 | return;
195 | }
196 |
197 | var policyName = item.value;
198 | var policyDocument = (textbox.value || '').trim();
199 |
200 | protect(function() {
201 | inProgress(function() {
202 | var params = [
203 | ['GroupName', groupName],
204 | ['PolicyName', policyName],
205 | ['PolicyDocument', policyDocument]
206 | ];
207 |
208 | iamcli.query_or_die('PutGroupPolicy', params);
209 | });
210 |
211 | textbox.value = policyDocument;
212 | disableUpdateButton();
213 | });
214 | }
215 |
216 | function enableUpdateButton() {
217 | $('group-policy-update-button').disabled = false;
218 | }
219 |
220 | function disableUpdateButton() {
221 | $('group-policy-update-button').disabled = true;
222 | }
223 |
--------------------------------------------------------------------------------
/Resources/chrome/content/group-detail-window.xul:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
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 |
--------------------------------------------------------------------------------
/Resources/chrome/content/group-edit-dialog.xul:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
68 |
--------------------------------------------------------------------------------
/Resources/chrome/content/group-tabpanel.xul:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
27 |
28 |
29 |
30 |
31 |
32 |
33 |
34 | Path:
35 |
36 |
37 |
38 |
39 |
40 | Search:
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 |
--------------------------------------------------------------------------------
/Resources/chrome/content/group-tree-view.js:
--------------------------------------------------------------------------------
1 | function GroupTreeView(iamcli) {
2 | this.iamcli = iamcli;
3 | this.rows = [];
4 | this.printRows = [];
5 | this.rowCount = 0;
6 | this.selection = null;
7 | this.sorted = false;
8 | }
9 |
10 | GroupTreeView.prototype = {
11 | getCellText: function(row, column) {
12 | var colkey = column.id.toString().split('.');
13 |
14 | if (colkey.length < 1) {
15 | return null;
16 | }
17 |
18 | colkey = colkey[colkey.length - 1];
19 |
20 | return this.printRows[row][colkey];
21 | },
22 |
23 | setTree: function(tree) {
24 | this.tree = tree;
25 | },
26 |
27 | isSorted: function() {
28 | return this.sorted;
29 | },
30 |
31 | cycleHeader: function(column) {
32 | var group = this.selectedRow();
33 | if (!group) { return; }
34 |
35 | if (sortRowsByColumn(column, this.rows)) {
36 | this.invalidate();
37 | this.sorted = true;
38 |
39 | if (group) {
40 | this.selectByName(group.GroupName);
41 | }
42 | }
43 | },
44 |
45 | invalidate: function() {
46 | this.printRows.length = 0;
47 |
48 | var pathFilter = $('group-tree-path-filter').selectedItem;
49 | var pathValue = pathFilter ? pathFilter.value : '/';
50 | var filterValue = ($('group-tree-filter').value || '').trim();
51 |
52 | function filter(elem) {
53 | var rp = new RegExp('^' + pathValue);
54 | var rv = new RegExp(filterValue);
55 |
56 | if (!rp.test(elem.Path.toString())) {
57 | return false;
58 | }
59 |
60 | for each (var child in elem.*) {
61 | if (rv.test(child.toString())) {
62 | return true;
63 | }
64 | }
65 |
66 | return false;
67 | };
68 |
69 | for (var i = 0; i < this.rows.length; i++) {
70 | var row = this.rows[i];
71 |
72 | if (filter(row)) {
73 | this.printRows.push(row);
74 | }
75 | }
76 |
77 | if (this.rowCount != this.printRows.length) {
78 | this.tree.rowCountChanged(0, -this.rowCount);
79 | this.rowCount = this.printRows.length;
80 | this.tree.rowCountChanged(0, this.rowCount);
81 | }
82 |
83 | this.tree.invalidate();
84 | },
85 |
86 | refresh: function() {
87 | this.rows.length = 0;
88 |
89 | protect(function() {
90 | var pathList = ['/'];
91 |
92 | var walk = function(marker) {
93 | var params = [];
94 |
95 | if (marker) {
96 | params.push(['Marker', marker])
97 | }
98 |
99 | var xhr = inProgress(function() {
100 | return this.iamcli.query_or_die('ListGroups', params);
101 | }.bind(this));
102 |
103 | var xml = xhr.xml();
104 |
105 | for each (var member in xml..Groups.member) {
106 | this.rows.push(member);
107 | pathList.push(member.Path.toString());
108 | }
109 |
110 | var isTruncated = ((xml..IsTruncated || '').toString().trim().toLowerCase() == 'true');
111 |
112 | return isTruncated ? (xml..Marker || '').toString().trim() : null;
113 | }.bind(this);
114 |
115 | var marker = null;
116 |
117 | do {
118 | marker = walk(marker);
119 | } while (marker);
120 |
121 | var pathFilter = $('group-tree-path-filter');
122 | pathFilter.removeAllItems();
123 | pathList = pathList.uniq().sort();
124 |
125 | for (var i = 0; i < pathList.length; i++) {
126 | var path = pathList[i];
127 | pathFilter.appendItem(path, path);
128 | }
129 |
130 | pathFilter.selectedIndex = 0;
131 |
132 | for (var i = 0; i < this.tree.columns.count; i++) {
133 | this.tree.columns.getColumnAt(i).element.setAttribute('sortDirection', 'natural');
134 | }
135 |
136 | this.invalidate();
137 | }.bind(this));
138 | },
139 |
140 | onDblclick: function(event) {
141 | var group = this.selectedRow();
142 |
143 | if (!group || (event && event.target.tagName != 'treechildren')) {
144 | return;
145 | }
146 |
147 | var groupName = group.GroupName;
148 |
149 | openModalWindow('group-detail-window.xul', 'group-datail-window', 640, 480,
150 | {iamcli:this.iamcli, groupName:groupName});
151 | },
152 |
153 | selectedRow: function() {
154 | var idx = this.selection.currentIndex;
155 | return (idx != -1) ? this.printRows[idx] : null;
156 | },
157 |
158 | deleteGroup: function() {
159 | var group = this.selectedRow();
160 | if (!group) { return; }
161 | var groupName = group.GroupName;
162 |
163 | if (!confirm("Are you sure you want to delete '" + groupName + " ' ?")) {
164 | return;
165 | }
166 |
167 | protect(function() {
168 | inProgress(function() {
169 | var walk = function(marker) {
170 | var params = [['GroupName', groupName]];
171 |
172 | if (marker) {
173 | params.push(['Marker', marker])
174 | }
175 |
176 | var xhr = this.iamcli.query_or_die('ListGroupPolicies', params);
177 | var xml = xhr.xml();
178 |
179 | for each (var member in xml..PolicyNames.member) {
180 | var params = [['GroupName', groupName], ['PolicyName', member]];
181 | this.iamcli.query_or_die('DeleteGroupPolicy', params);
182 | }
183 |
184 | var isTruncated = ((xml..IsTruncated || '').toString().trim().toLowerCase() == 'true');
185 |
186 | return isTruncated ? (xml..Marker || '').toString().trim() : null;
187 | }.bind(this);
188 |
189 | var marker = null;
190 |
191 | do {
192 | marker = walk(marker);
193 | } while (marker);
194 |
195 | this.iamcli.query_or_die('DeleteGroup', [['GroupName', groupName]]);
196 |
197 | this.refresh();
198 | }.bind(this));
199 | }.bind(this));
200 | },
201 |
202 | openGroupEditDialog: function() {
203 | var group = this.selectedRow();
204 | if (!group) { return; }
205 | openDialog('chrome://iamfox/content/group-edit-dialog.xul', 'group-edit-dialog', 'chrome,modal,centerscreen',
206 | {view:this, inProgress:inProgress, group:group});
207 | },
208 |
209 | selectByName: function(name) {
210 | var rows = this.rows;
211 |
212 | for (var i = 0; i < rows.length; i++) {
213 | var user = rows[i];
214 |
215 | if (user.UserName == name) {
216 | this.selection.select(i);
217 | }
218 | }
219 |
220 | this.rows
221 | },
222 |
223 | copyColumnToClipboard: function(name) {
224 | var row = this.selectedRow();
225 |
226 | if (row) {
227 | copyToClipboard(row[name].toString());
228 | }
229 | }
230 | };
231 |
--------------------------------------------------------------------------------
/Resources/chrome/content/iam-client.js:
--------------------------------------------------------------------------------
1 | function IAMClient(accessKeyId, secretAccessKey) {
2 | this.accessKeyId = accessKeyId;
3 | this.secretAccessKey = secretAccessKey;
4 | }
5 |
6 | IAMClient.prototype = {
7 | USER_AGENT: 'IAMClient/0.1.0',
8 | API_VERSION: '2010-05-08',
9 | HOST: 'iam.amazonaws.com',
10 | TIMEOUT: 30000,
11 |
12 | query: function(action, params, callback, async) {
13 | if (!params) {
14 | params = [];
15 | }
16 |
17 | var queryString = this.makeQuery(action, params);
18 |
19 | var xhr = new XMLHttpRequest();
20 | xhr.open('POST', 'https://' + this.HOST + '/', async);
21 | xhr.setRequestHeader('User-Agent', this.USER_AGENT);
22 | xhr.setRequestHeader('Content-Type', 'application/x-www-form-urlencoded');
23 | xhr.setRequestHeader('Content-Length', queryString.length);
24 | xhr.setRequestHeader('Connection', 'close');
25 |
26 | function extxhr() {
27 | xhr.success = function() {
28 | return (xhr.status && xhr.status >= 200 && xhr.status < 300);
29 | }
30 |
31 | xhr.callback = function(xhr) {
32 | callback && callback(xhr);
33 | }
34 |
35 | xhr.xml = function() {
36 | var xml = new XML(xhr.responseText.replace(/xmlns="[^"]*"/, '')); // "
37 | return xml;
38 | }
39 |
40 | return xhr;
41 | }
42 |
43 | if (async) {
44 | xhr.onreadystatechange = function() {
45 | if (xhr.readyState != 4) { return; }
46 | try {
47 | extxhr().callback();
48 | } catch (e) {
49 | alert(e);
50 | }
51 | };
52 | } else {
53 | xhr.onreadystatechange = function() {};
54 | }
55 |
56 | var timer = setTimeout(xhr.abort, this.TIMEOUT);
57 |
58 | try {
59 | xhr.send(queryString);
60 | clearTimeout(timer);
61 | } catch(e) {
62 | if (!async) { clearTimeout(timer); }
63 | throw e;
64 | }
65 |
66 | return extxhr();
67 | }, // query
68 |
69 | makeQuery: function(action, params) {
70 | var kvs = [];
71 |
72 | kvs.push(['Action', action]);
73 | kvs.push(['Version', this.API_VERSION]);
74 | kvs.push(['SignatureVersion', '2']);
75 | kvs.push(['SignatureMethod', 'HmacSHA1']);
76 | kvs.push(['Timestamp', this.timestamp()]);
77 | kvs.push(['AWSAccessKeyId', this.accessKeyId]);
78 |
79 | for (var i = 0; i < params.length; i++) {
80 | kvs.push(params[i]);
81 | }
82 |
83 | kvs.sort(function(a, b) {
84 | a = a[0]; b = b[0];
85 | return (a < b) ? -1 : (a > b) ? 1 : 0;
86 | });
87 |
88 | var queryParams = [];
89 |
90 | function encode(str) {
91 | str = encodeURIComponent(str);
92 |
93 | var func = function(m) {
94 | switch(m) {
95 | case '!':
96 | return '%21';
97 | case "'":
98 | return '%27';
99 | case '(':
100 | return '%28';
101 | case ')':
102 | return '%29';
103 | case '*':
104 | return '%2A';
105 | default:
106 | return m;
107 | }
108 | };
109 |
110 | return str.replace(/[!'()*~]/g, func); // '
111 | }
112 |
113 | for (var i = 0; i < kvs.length; i++) {
114 | var key = kvs[i][0];
115 | var val = encode(kvs[i][1]);
116 | queryParams.push(key + '=' + val);
117 | }
118 |
119 | var queryString = queryParams.join('&');
120 | var stringToSign = 'POST\n' + this.HOST + '\n/\n' + queryString;
121 |
122 | var signature = b64_hmac_sha1(this.secretAccessKey, stringToSign);
123 | queryString += '&Signature=' + encodeURIComponent(signature);
124 |
125 | return queryString;
126 | }, // makeQuery
127 |
128 | timestamp: function(date) {
129 | if (!date) {
130 | date = new Date();
131 | }
132 |
133 | function pad(num) {
134 | return (num < 10 ? '0' : '') + num;
135 | }
136 |
137 | var year = pad(date.getUTCFullYear());
138 | var mon = pad(date.getUTCMonth() + 1);
139 | var day = pad(date.getUTCDate());
140 | var hour = pad(date.getUTCHours());
141 | var min = pad(date.getUTCMinutes());
142 | var sec = pad(date.getUTCSeconds());
143 |
144 | return [year, mon, day].join('-') + 'T' + [hour, min, sec].join(':') + 'Z';
145 | } // timestamp
146 | }; // IAMClient
147 |
--------------------------------------------------------------------------------
/Resources/chrome/content/iamfox.xul:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
8 |
11 |
12 |
--------------------------------------------------------------------------------
/Resources/chrome/content/io.js:
--------------------------------------------------------------------------------
1 | /////////////////////////////////////////////////
2 | /////////////////////////////////////////////////
3 | //
4 | // Basic JavaScript File and Directory IO module
5 | // By: MonkeeSage, v0.1
6 | //
7 | /////////////////////////////////////////////////
8 | /////////////////////////////////////////////////
9 |
10 |
11 | if (typeof(JSIO) != 'boolean') {
12 |
13 | var JSIO = true;
14 |
15 | /////////////////////////////////////////////////
16 | // Basic file IO object based on Mozilla source
17 | // code post at forums.mozillazine.org
18 | /////////////////////////////////////////////////
19 |
20 | // Example use:
21 | // var fileIn = FileIO.open('/test.txt');
22 | // if (fileIn.exists()) {
23 | // var fileOut = FileIO.open('/copy of test.txt');
24 | // var str = FileIO.read(fileIn);
25 | // var rv = FileIO.write(fileOut, str);
26 | // alert('File write: ' + rv);
27 | // rv = FileIO.write(fileOut, str, 'a');
28 | // alert('File append: ' + rv);
29 | // rv = FileIO.unlink(fileOut);
30 | // alert('File unlink: ' + rv);
31 | // }
32 |
33 | var FileIO = {
34 |
35 | localfileCID : '@mozilla.org/file/local;1',
36 | localfileIID : Components.interfaces.nsILocalFile,
37 |
38 | finstreamCID : '@mozilla.org/network/file-input-stream;1',
39 | finstreamIID : Components.interfaces.nsIFileInputStream,
40 |
41 | foutstreamCID : '@mozilla.org/network/file-output-stream;1',
42 | foutstreamIID : Components.interfaces.nsIFileOutputStream,
43 |
44 | sinstreamCID : '@mozilla.org/scriptableinputstream;1',
45 | sinstreamIID : Components.interfaces.nsIScriptableInputStream,
46 |
47 | suniconvCID : '@mozilla.org/intl/scriptableunicodeconverter',
48 | suniconvIID : Components.interfaces.nsIScriptableUnicodeConverter,
49 |
50 | open : function(path) {
51 | try {
52 | var file = Components.classes[this.localfileCID]
53 | .createInstance(this.localfileIID);
54 | file.initWithPath(path);
55 | return file;
56 | }
57 | catch(e) {
58 | return false;
59 | }
60 | },
61 |
62 | read : function(file, charset) {
63 | try {
64 | var data = new String();
65 | var fiStream = Components.classes[this.finstreamCID]
66 | .createInstance(this.finstreamIID);
67 | var siStream = Components.classes[this.sinstreamCID]
68 | .createInstance(this.sinstreamIID);
69 | fiStream.init(file, 1, 0, false);
70 | siStream.init(fiStream);
71 | data += siStream.read(-1);
72 | siStream.close();
73 | fiStream.close();
74 | if (charset) {
75 | data = this.toUnicode(charset, data);
76 | }
77 | return data;
78 | }
79 | catch(e) {
80 | return false;
81 | }
82 | },
83 |
84 | write : function(file, data, mode, charset) {
85 | try {
86 | var foStream = Components.classes[this.foutstreamCID]
87 | .createInstance(this.foutstreamIID);
88 | if (charset) {
89 | data = this.fromUnicode(charset, data);
90 | }
91 | var flags = 0x02 | 0x08 | 0x20; // wronly | create | truncate
92 | if (mode == 'a') {
93 | flags = 0x02 | 0x10; // wronly | append
94 | }
95 | foStream.init(file, flags, 0664, 0);
96 | foStream.write(data, data.length);
97 | // foStream.flush();
98 | foStream.close();
99 | return true;
100 | }
101 | catch(e) {
102 | return false;
103 | }
104 | },
105 |
106 | create : function(file) {
107 | try {
108 | file.create(0x00, 0664);
109 | return true;
110 | }
111 | catch(e) {
112 | return false;
113 | }
114 | },
115 |
116 | unlink : function(file) {
117 | try {
118 | file.remove(false);
119 | return true;
120 | }
121 | catch(e) {
122 | return false;
123 | }
124 | },
125 |
126 | path : function(file) {
127 | try {
128 | return 'file:///' + file.path.replace(/\\/g, '\/')
129 | .replace(/^\s*\/?/, '').replace(/\ /g, '%20');
130 | }
131 | catch(e) {
132 | return false;
133 | }
134 | },
135 |
136 | toUnicode : function(charset, data) {
137 | try{
138 | var uniConv = Components.classes[this.suniconvCID]
139 | .createInstance(this.suniconvIID);
140 | uniConv.charset = charset;
141 | data = uniConv.ConvertToUnicode(data);
142 | }
143 | catch(e) {
144 | // foobar!
145 | }
146 | return data;
147 | },
148 |
149 | fromUnicode : function(charset, data) {
150 | try {
151 | var uniConv = Components.classes[this.suniconvCID]
152 | .createInstance(this.suniconvIID);
153 | uniConv.charset = charset;
154 | data = uniConv.ConvertFromUnicode(data);
155 | // data += uniConv.Finish();
156 | }
157 | catch(e) {
158 | // foobar!
159 | }
160 | return data;
161 | }
162 |
163 | }
164 |
165 |
166 | /////////////////////////////////////////////////
167 | // Basic Directory IO object based on JSLib
168 | // source code found at jslib.mozdev.org
169 | /////////////////////////////////////////////////
170 |
171 | // Example use:
172 | // var dir = DirIO.open('/test');
173 | // if (dir.exists()) {
174 | // alert(DirIO.path(dir));
175 | // var arr = DirIO.read(dir, true), i;
176 | // if (arr) {
177 | // for (i = 0; i < arr.length; ++i) {
178 | // alert(arr[i].path);
179 | // }
180 | // }
181 | // }
182 | // else {
183 | // var rv = DirIO.create(dir);
184 | // alert('Directory create: ' + rv);
185 | // }
186 |
187 | // ---------------------------------------------
188 | // ----------------- Nota Bene -----------------
189 | // ---------------------------------------------
190 | // Some possible types for get are:
191 | // 'ProfD' = profile
192 | // 'DefProfRt' = user (e.g., /root/.mozilla)
193 | // 'UChrm' = %profile%/chrome
194 | // 'DefRt' = installation
195 | // 'PrfDef' = %installation%/defaults/pref
196 | // 'ProfDefNoLoc' = %installation%/defaults/profile
197 | // 'APlugns' = %installation%/plugins
198 | // 'AChrom' = %installation%/chrome
199 | // 'ComsD' = %installation%/components
200 | // 'CurProcD' = installation (usually)
201 | // 'Home' = OS root (e.g., /root)
202 | // 'TmpD' = OS tmp (e.g., /tmp)
203 |
204 | var DirIO = {
205 |
206 | sep : '/',
207 |
208 | dirservCID : '@mozilla.org/file/directory_service;1',
209 |
210 | propsIID : Components.interfaces.nsIProperties,
211 |
212 | fileIID : Components.interfaces.nsIFile,
213 |
214 | get : function(type) {
215 | try {
216 | var dir = Components.classes[this.dirservCID]
217 | .createInstance(this.propsIID)
218 | .get(type, this.fileIID);
219 | return dir;
220 | }
221 | catch(e) {
222 | return false;
223 | }
224 | },
225 |
226 | open : function(path) {
227 | return FileIO.open(path);
228 | },
229 |
230 | create : function(dir) {
231 | try {
232 | dir.create(0x01, 0664);
233 | return true;
234 | }
235 | catch(e) {
236 | return false;
237 | }
238 | },
239 |
240 | read : function(dir, recursive) {
241 | var list = new Array();
242 | try {
243 | if (dir.isDirectory()) {
244 | if (recursive == null) {
245 | recursive = false;
246 | }
247 | var files = dir.directoryEntries;
248 | list = this._read(files, recursive);
249 | }
250 | }
251 | catch(e) {
252 | // foobar!
253 | }
254 | return list;
255 | },
256 |
257 | _read : function(dirEntry, recursive) {
258 | var list = new Array();
259 | try {
260 | while (dirEntry.hasMoreElements()) {
261 | list.push(dirEntry.getNext()
262 | .QueryInterface(FileIO.localfileIID));
263 | }
264 | if (recursive) {
265 | var list2 = new Array();
266 | for (var i = 0; i < list.length; ++i) {
267 | if (list[i].isDirectory()) {
268 | files = list[i].directoryEntries;
269 | list2 = this._read(files, recursive);
270 | }
271 | }
272 | for (i = 0; i < list2.length; ++i) {
273 | list.push(list2[i]);
274 | }
275 | }
276 | }
277 | catch(e) {
278 | // foobar!
279 | }
280 | return list;
281 | },
282 |
283 | unlink : function(dir, recursive) {
284 | try {
285 | if (recursive == null) {
286 | recursive = false;
287 | }
288 | dir.remove(recursive);
289 | return true;
290 | }
291 | catch(e) {
292 | return false;
293 | }
294 | },
295 |
296 | path : function (dir) {
297 | return FileIO.path(dir);
298 | },
299 |
300 | split : function(str, join) {
301 | var arr = str.split(/\/|\\/), i;
302 | str = new String();
303 | for (i = 0; i < arr.length; ++i) {
304 | str += arr[i] + ((i != arr.length - 1) ?
305 | join : '');
306 | }
307 | return str;
308 | },
309 |
310 | join : function(str, split) {
311 | var arr = str.split(split), i;
312 | str = new String();
313 | for (i = 0; i < arr.length; ++i) {
314 | str += arr[i] + ((i != arr.length - 1) ?
315 | this.sep : '');
316 | }
317 | return str;
318 | }
319 |
320 | }
321 |
322 | if (navigator.platform.toLowerCase().indexOf('win') > -1) {
323 | DirIO.sep = '\\';
324 | }
325 |
326 | }
327 |
328 | function newFilePicker() {
329 | var nsIFilePicker = Components.interfaces.nsIFilePicker;
330 | return Components.classes['@mozilla.org/filepicker;1'].createInstance(nsIFilePicker);
331 | }
332 |
333 | function readTextByFilePicker(callback, filter, defstr) {
334 | var fp = newFilePicker();
335 | fp.init(window, 'Import and Merge keys', Components.interfaces.nsIFilePicker.modeOpen);
336 |
337 | if (defstr) {
338 | fp.defaultString = defstr;
339 | }
340 |
341 | if (filter) {
342 | fp.appendFilter(filter[0], filter[1]);
343 | }
344 |
345 | var result = fp.show();
346 | var fin = null;
347 |
348 | switch (result) {
349 | case Components.interfaces.nsIFilePicker.returnOK:
350 | case Components.interfaces.nsIFilePicker.returnReplace:
351 | fin = fp.file;
352 | break;
353 | default:
354 | return null;
355 | }
356 |
357 | var data = FileIO.read(fin);
358 |
359 | if (!data) {
360 | alert("Cannnot read file.");
361 | return null;
362 | }
363 |
364 | return callback(data);
365 | }
366 |
367 | function readAndSet(element) {
368 | element = document.getElementById(element);
369 |
370 | readTextByFilePicker(function(data) {
371 | element.value = data;
372 | });
373 | }
374 |
--------------------------------------------------------------------------------
/Resources/chrome/content/loader.gif:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/cookpad/iam-fox/675f751976bab0db79766bd03a76218c20122c8c/Resources/chrome/content/loader.gif
--------------------------------------------------------------------------------
/Resources/chrome/content/main.js:
--------------------------------------------------------------------------------
1 | function attachViewsToElements(callback) {
2 | var iamcli = newIAMClient();
3 |
4 | function bind(clazz, name) {
5 | var obj = new clazz(iamcli);
6 | var tab = $(name + '-tab');
7 | tab.view = obj;
8 | var tree = $(name + '-tree');
9 | tree.view = obj;
10 | tree._view = obj;
11 | }
12 |
13 | if (iamcli) {
14 | bind(GroupTreeView, 'group');
15 | bind(UserTreeView, 'user');
16 | bind(ServerCertTreeView, 'server-cert');
17 |
18 | if (callback) {
19 | callback();
20 | }
21 | }
22 | }
23 |
24 | function windowOnLoad() {
25 | attachViewsToElements(function() {
26 | selectedView().refresh();
27 | });
28 | }
29 |
30 | function tabOnSelect(event) {
31 | var view = selectedView();
32 | if (view) { view.refresh(); }
33 | }
34 |
35 | function selectedView() {
36 | var tab = $('main-tabs').selectedItem;
37 | return tab ? tab.view : null;
38 | }
39 |
40 | function treeViews() {
41 | var views = [];
42 | var tabs = $('main-tabs').getElementsByTagName('tab');
43 |
44 | for (var i = 0; i < tabs.length; i++) {
45 | if (tabs[i].view) {
46 | views.push(tabs[i].view);
47 | }
48 | }
49 |
50 | return views;
51 | }
52 |
53 | function openAccountDialog() {
54 | openDialog('chrome://iamfox/content/account-dialog.xul', 'account-dialog', 'chrome,modal,centerscreen',
55 | {selectedView:selectedView, attachViewsToElements:attachViewsToElements});
56 | }
57 |
58 | function newIAMClient() {
59 | if (!Prefs.currentUser) {
60 | //openAccountDialog();
61 | return null;
62 | } else {
63 | var iamcli = new IAMClient(Prefs.accessKeyId, Prefs.secretAccessKey);
64 |
65 | iamcli.query_or_die = function(action, params) {
66 | var xhr = iamcli.query(action, params);
67 |
68 | if (!xhr.success()) {
69 | throw xhr;
70 | }
71 |
72 | return xhr;
73 | };
74 |
75 | return iamcli;
76 | }
77 | }
78 |
79 | function inProgress(callback) {
80 | var loader = $('main-loader');
81 | loader.hidden = false;
82 |
83 | var retval = null;
84 | var exception = null;
85 |
86 | try {
87 | retval = callback();
88 | } catch (e) {
89 | exception = e;
90 | }
91 |
92 | loader.hidden = true;
93 |
94 | if (exception) {
95 | throw exception;
96 | }
97 |
98 | return retval;
99 | }
100 |
101 | function openModalWindow(xul, name, width, height, args) {
102 | var uri = 'chrome://iamfox/content/' + xul;
103 | var left = window.screenX + (window.outerWidth - width) / 2;
104 | var top = window.screenY + (window.outerHeight - height) / 2;
105 | var features = 'chrome,modal,centerscreen,dialog=no,resizable,width=' + width + ',height=' + height + ',left=' + left + ',top=' + top;
106 |
107 | var w = window.openDialog(uri, name, features, args);
108 |
109 | return w;
110 | }
111 |
112 | function openGroupAddDialog() {
113 | if (selectedView()) {
114 | openDialog('chrome://iamfox/content/group-add-dialog.xul', 'group-add-dialog', 'chrome,modal,centerscreen',
115 | {selectedView:selectedView, inProgress:inProgress});
116 | }
117 | }
118 |
119 | function openUserAddDialog() {
120 | if (selectedView()) {
121 | openDialog('chrome://iamfox/content/user-add-dialog.xul', 'user-add-dialog', 'chrome,modal,centerscreen',
122 | {selectedView:selectedView, inProgress:inProgress});
123 | }
124 | }
125 |
126 | function openServerCertAddWindow() {
127 | openModalWindow('server-cert-add-window.xul', 'server-cert-add-window', 640, 480,
128 | {selectedView:selectedView, inProgress:inProgress});
129 | }
130 |
131 | function openAboutDialog() {
132 | openDialog('chrome://iamfox/content/about-dialog.xul', 'about-dialog', 'chrome,modal,centerscreen');
133 | }
134 |
--------------------------------------------------------------------------------
/Resources/chrome/content/main.xul:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
25 |
26 |
27 |
28 |
29 |
30 |
31 |
32 |
33 |
34 |
35 |
36 |
44 |
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 |
--------------------------------------------------------------------------------
/Resources/chrome/content/preferences.js:
--------------------------------------------------------------------------------
1 | Prefs = {
2 | version: '0.1.6',
3 |
4 | convert: function() {
5 | var version = nsPreferences.copyUnicharPref('iamfox.version', '').trim();
6 | var accessKeyId = nsPreferences.copyUnicharPref('iamfox.accessKeyId', '').trim();
7 |
8 | if (!version && accessKeyId) {
9 | var secretAccessKey = nsPreferences.copyUnicharPref('iamfox.secretAccessKey', '').trim();
10 | var userAccessKeyIds = nsPreferences.copyUnicharPref('iamfox.userAccessKeyIds', '({})');
11 | userAccessKeyIds = eval(userAccessKeyIds);
12 | var userSecretAccessKeys = nsPreferences.copyUnicharPref('iamfox.userSecretAccessKeys', '({})');
13 | userSecretAccessKeys = eval(userSecretAccessKeys);
14 |
15 | Prefs.currentUser = 'Your name';
16 |
17 | var accounts = [
18 | [
19 | Prefs.currentUser,
20 | {
21 | accessKeyId:accessKeyId,
22 | secretAccessKey:secretAccessKey,
23 | userAccessKeyIds:userAccessKeyIds,
24 | userSecretAccessKeys:userSecretAccessKeys
25 | }
26 | ]
27 | ];
28 |
29 | nsPreferences.setUnicharPref('iamfox.accounts', accounts.toSource());
30 | nsPreferences.setUnicharPref('iamfox.version', this.version);
31 | }
32 | },
33 |
34 | get currentUser() {
35 | return nsPreferences.copyUnicharPref('iamfox.currentUser', null);
36 | },
37 |
38 | set currentUser(v) {
39 | nsPreferences.setUnicharPref('iamfox.currentUser', v);
40 | },
41 |
42 | getAccountList: function() {
43 | this.convert();
44 | var accounts = nsPreferences.copyUnicharPref('iamfox.accounts', '([])');
45 | return eval(accounts);
46 | },
47 |
48 | storeAccountList: function(updated) {
49 | nsPreferences.setUnicharPref('iamfox.accounts', updated.toSource());
50 | },
51 |
52 | addAccount: function(userName, accessKeyId, secretAccessKey) {
53 | var accounts = this.getAccountList();
54 |
55 | var newAccount = [
56 | userName,
57 | {
58 | accessKeyId:accessKeyId,
59 | secretAccessKey:secretAccessKey
60 | }
61 | ];
62 |
63 | var index = -1;
64 |
65 | for(var i = 0; i < accounts.length; i++) {
66 | if (accounts[i][0] == userName) {
67 | index = i;
68 | break;
69 | }
70 | }
71 |
72 | if (index == -1) {
73 | accounts.push(newAccount);
74 | } else {
75 | accounts.splice(index, 1, newAccount);
76 | }
77 |
78 | this.storeAccountList(accounts);
79 |
80 | if (accounts.length == 1) {
81 | this.currentUser = accounts[0][0];
82 | }
83 | },
84 |
85 | deleteAccount: function(userName) {
86 | var accounts = this.getAccountList();
87 | var index = -1;
88 |
89 | for(var i = 0; i < accounts.length; i++) {
90 | if (accounts[i][0] == userName) {
91 | index = i;
92 | break;
93 | }
94 | }
95 |
96 | if (index != -1) {
97 | accounts.splice(index, 1);
98 | this.storeAccountList(accounts);
99 |
100 | if (accounts.length > 0) {
101 | this.currentUser = accounts[0][0];
102 | } else {
103 | this.currentUser = '';
104 | }
105 | }
106 | },
107 |
108 | getAccount: function() {
109 | var accounts = this.getAccountList();
110 |
111 | var userName = this.currentUser;
112 | if (!userName) { return {}; }
113 |
114 | for (var i = 0; i < accounts.length; i++) {
115 | if (accounts[i][0] == userName) {
116 | return accounts[i][1];
117 | }
118 | }
119 |
120 | return {};
121 | },
122 |
123 | storeAccount: function(updated) {
124 | var accounts = this.getAccountList();
125 |
126 | var userName = this.currentUser;
127 | if (!userName) { return; }
128 |
129 | for (var i = 0; i < accounts.length; i++) {
130 | if (accounts[i][0] == userName) {
131 | accounts[i][1] = updated;
132 | this.storeAccountList(accounts);
133 | break;
134 | }
135 | }
136 | },
137 |
138 | get accessKeyId() {
139 | var account = this.getAccount();
140 | return (account.accessKeyId || '').trim();
141 | },
142 |
143 | set accessKeyId(v) {
144 | var account = this.getAccount();
145 | account.accessKeyId = v;
146 | this.storeAccount(account);
147 | },
148 |
149 | get secretAccessKey() {
150 | var account = this.getAccount();
151 | return (account.secretAccessKey || '').trim();
152 | },
153 |
154 | set secretAccessKey(v) {
155 | var account = this.getAccount();
156 | account.secretAccessKey = v;
157 | this.storeAccount(account);
158 | },
159 |
160 | getUserAccessKeyId: function(name) {
161 | var account = this.getAccount();
162 | var userAccessKeyIds = (account.userAccessKeyIds || {});
163 | var userAccessKeyId = (userAccessKeyIds[name] || []);
164 |
165 | if (typeof(userAccessKeyId) == "string") {
166 | userAccessKeyId = [userAccessKeyId];
167 | }
168 |
169 | return userAccessKeyId;
170 | },
171 |
172 | setUserAccessKeyId: function(name, key) {
173 | name = name.toString();
174 | key = key.toString();
175 |
176 | var account = this.getAccount();
177 | var userAccessKeyIds = (account.userAccessKeyIds || {});
178 | userAccessKeyIds[name] = [key];
179 |
180 | account.userAccessKeyIds = userAccessKeyIds;
181 | this.storeAccount(account);
182 | },
183 |
184 | addUserAccessKeyId: function(name, key) {
185 | name = name.toString();
186 | key = key.toString();
187 |
188 | var account = this.getAccount();
189 | var userAccessKeyIds = (account.userAccessKeyIds || {});
190 | var userAccessKeyId = (userAccessKeyIds[name] || []);
191 |
192 | if (typeof(userAccessKeyId) == "string") {
193 | userAccessKeyId = [userAccessKeyId];
194 | }
195 |
196 | userAccessKeyId.push(key);
197 | userAccessKeyIds[name] = userAccessKeyId;
198 |
199 | account.userAccessKeyIds = userAccessKeyIds;
200 | this.storeAccount(account);
201 | },
202 |
203 | deleteUserAccessKeyId: function(name) {
204 | name = name.toString();
205 |
206 | var account = this.getAccount();
207 | var userAccessKeyIds = (account.userAccessKeyIds || {});
208 | delete userAccessKeyIds[name];
209 |
210 | account.userAccessKeyIds = userAccessKeyIds;
211 | this.storeAccount(account);
212 | },
213 |
214 | getUserSecretAccessKey: function(name) {
215 | var account = this.getAccount();
216 | var userSecretAccessKeys = (account.userSecretAccessKeys || {});
217 | var userSecretAccessKey = (userSecretAccessKeys[name] || []);
218 |
219 | if (typeof(userSecretAccessKey) == "string") {
220 | userSecretAccessKey = [userSecretAccessKey];
221 | }
222 |
223 | return userSecretAccessKey;
224 | },
225 |
226 | setUserSecretAccessKey: function(name, key) {
227 | name = name.toString();
228 | key = key.toString();
229 |
230 | var account = this.getAccount();
231 | var userSecretAccessKeys = (account.userSecretAccessKeys || {});
232 | userSecretAccessKeys[name] = [key];
233 |
234 | account.userSecretAccessKeys = userSecretAccessKeys;
235 | this.storeAccount(account);
236 | },
237 |
238 | addUserSecretAccessKey: function(name, key) {
239 | name = name.toString();
240 | key = key.toString();
241 |
242 | var account = this.getAccount();
243 | var userSecretAccessKeys = (account.userSecretAccessKeys || {});
244 | var userSecretAccessKey = (userSecretAccessKeys[name] || []);
245 |
246 | if (typeof(userSecretAccessKey) == "string") {
247 | userSecretAccessKey = [userSecretAccessKey];
248 | }
249 |
250 | userSecretAccessKey.push(key);
251 | userSecretAccessKeys[name] = userSecretAccessKey;
252 |
253 | account.userSecretAccessKeys = userSecretAccessKeys;
254 | this.storeAccount(account);
255 | },
256 |
257 | deleteUserSecretAccessKey: function(name) {
258 | name = name.toString();
259 |
260 | var account = this.getAccount();
261 | var userSecretAccessKeys = (account.userSecretAccessKeys || {});
262 | delete userSecretAccessKeys[name];
263 |
264 | account.userSecretAccessKeys = userSecretAccessKeys;
265 | this.storeAccount(account);
266 | },
267 |
268 | deleteUserAccessKeyIdAndSecretAccessKey: function(name, key) {
269 | name = name.toString();
270 | key = key.toString();
271 |
272 | var account = this.getAccount();
273 | var userAccessKeyIds = (account.userAccessKeyIds || {});
274 | var userSecretAccessKeys = (account.userSecretAccessKeys || {});
275 |
276 | for (var i = 0; i < userAccessKeyIds.length; i++) {
277 | var akid = userAccessKeyIds[i];
278 |
279 | if (key == akid) {
280 | userAccessKeyIds.splice(i, 1);
281 | userSecretAccessKeys.splice(i, 1);
282 | break;
283 | }
284 | }
285 |
286 | account.userAccessKeyIds = userAccessKeyIds;
287 | account.userSecretAccessKeys = userSecretAccessKeys;
288 | this.storeAccount(account);
289 | },
290 |
291 | renameUserAccessKeyIdAndSecretAccessKey: function(old_name, new_name) {
292 | old_name = old_name.toString();
293 | new_name = new_name.toString();
294 |
295 | var account = this.getAccount();
296 | var userAccessKeyIds = (account.userAccessKeyIds || {});
297 | var userSecretAccessKeys = (account.userSecretAccessKeys || {});
298 |
299 | var accessKeyId = userAccessKeyIds[old_name];
300 | var secretAccessKeys = userSecretAccessKeys[old_name];
301 | userAccessKeyIds[new_name] = accessKeyId;
302 | userSecretAccessKeys[new_name] = secretAccessKeys;
303 | delete userAccessKeyIds[old_name];
304 | delete userSecretAccessKeys[old_name];
305 |
306 | account.userAccessKeyIds = userAccessKeyIds;
307 | account.userSecretAccessKeys = userSecretAccessKeys;
308 | this.storeAccount(account);
309 | },
310 |
311 | get userAccessKeyIds() {
312 | var account = this.getAccount();
313 | return (account.userAccessKeyIds || {});
314 | },
315 |
316 | get userSecretAccessKeys() {
317 | var account = this.getAccount();
318 | return (account.userSecretAccessKeys || {});
319 | },
320 |
321 | mergeUserAccessKeyIds: function(data) {
322 | var account = this.getAccount();
323 | var userAccessKeyIds = (account.userAccessKeyIds || {});
324 |
325 | for (var name in data) {
326 | var key = data[name];
327 |
328 | if (key) {
329 | userAccessKeyIds[name] = key;
330 | }
331 | }
332 |
333 | account.userAccessKeyIds = userAccessKeyIds;
334 | this.storeAccount(account);
335 | },
336 |
337 | mergeUserSecretAccessKeys: function(data) {
338 | var account = this.getAccount();
339 | var userSecretAccessKeys = (account.userSecretAccessKeys || {});
340 |
341 | for (var name in data) {
342 | var key = data[name];
343 |
344 | if (key) {
345 | userSecretAccessKeys[name] = key;
346 | }
347 | }
348 |
349 | account.userSecretAccessKeys = userSecretAccessKeys;
350 | this.storeAccount(account);
351 | }
352 | };
353 |
--------------------------------------------------------------------------------
/Resources/chrome/content/server-cert-add-window.js:
--------------------------------------------------------------------------------
1 | function windowOnLoad() {
2 | }
3 |
4 | function serverCertAddWindowDoOK() {
5 | try {
6 | var args = window.arguments[0];
7 | var view = args.selectedView();
8 | var iamcli = view.iamcli;
9 | var inProgress = args.inProgress;
10 |
11 | var serverCertName = ($('server-cert-add-window-server-cert-name').value || '').trim();
12 | var serverCertPath = ($('server-cert-add-window-path').value || '').trim();
13 | var serverCertBody = ($('server-cert-add-window-main-cert').value || '').trim();
14 | var serverPrivateKey = ($('server-cert-add-window-private-key').value || '').trim();
15 | var serverCertChain = ($('server-cert-add-window-chain-cert').value || '').trim();
16 |
17 | if (!serverCertName || !serverCertPath || !serverCertBody || !serverPrivateKey) {
18 | alert("Please input 'Server Certificate Name' and 'Path' and 'Certificate' and 'Private Key'.");
19 | return false;
20 | }
21 |
22 | if (serverCertPath.charAt(serverCertPath.length - 1) != '/') {
23 | serverCertPath += '/';
24 | }
25 |
26 | var xhr = null;
27 |
28 | protect(function() {
29 | inProgress(function() {
30 | var params = [
31 | ['CertificateBody', serverCertBody],
32 | ['Path', serverCertPath],
33 | ['PrivateKey', serverPrivateKey],
34 | ['ServerCertificateName', serverCertName]
35 | ];
36 |
37 | if (serverCertChain) {
38 | params.push(['CertificateChain', serverCertChain]);
39 | }
40 |
41 | xhr = iamcli.query_or_die('UploadServerCertificate', params);
42 |
43 | view.refresh();
44 | view.selectByName(serverCertName);
45 | });
46 | });
47 | } catch(e) { alert(e); }
48 |
49 | if (xhr.success()) {
50 | window.close();
51 | }
52 | }
53 |
--------------------------------------------------------------------------------
/Resources/chrome/content/server-cert-add-window.xul:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
25 |
26 |
27 |
28 |
29 |
30 |
31 |
32 |
33 | (open...)
34 |
35 |
36 |
37 |
38 |
39 |
40 |
41 |
42 |
43 | (open...)
44 |
45 |
46 |
47 |
48 |
49 |
50 |
51 |
52 |
53 |
54 | (open...)
55 |
56 |
57 |
58 |
59 |
60 |
61 |
62 |
63 |
64 |
65 |
66 |
--------------------------------------------------------------------------------
/Resources/chrome/content/server-cert-edit-dialog.xul:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
73 |
--------------------------------------------------------------------------------
/Resources/chrome/content/server-cert-tabpanel.xul:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
26 |
27 |
28 |
29 |
30 |
31 |
32 |
33 | Path:
34 |
35 |
36 |
37 |
38 |
39 | Search:
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 |
--------------------------------------------------------------------------------
/Resources/chrome/content/server-cert-tree-view.js:
--------------------------------------------------------------------------------
1 | function ServerCertTreeView(iamcli) {
2 | this.iamcli = iamcli;
3 | this.rows = [];
4 | this.printRows = [];
5 | this.rowCount = 0;
6 | this.selection = null;
7 | this.sorted = false;
8 | }
9 |
10 | ServerCertTreeView.prototype = {
11 | getCellText: function(row, column) {
12 | var colkey = column.id.toString().split('.');
13 |
14 | if (colkey.length < 1) {
15 | return null;
16 | }
17 |
18 | colkey = colkey[colkey.length - 1];
19 |
20 | return this.printRows[row][colkey];
21 | },
22 |
23 | setTree: function(tree) {
24 | this.tree = tree;
25 | },
26 |
27 | isSorted: function() {
28 | return this.sorted;
29 | },
30 |
31 | cycleHeader: function(column) {
32 | var cert = this.selectedRow();
33 | if (!cert) { return; }
34 |
35 | if (sortRowsByColumn(column, this.rows)) {
36 | this.invalidate();
37 | this.sorted = true;
38 |
39 | if (cert) {
40 | this.selectByName(cert.ServerCertificateName);
41 | }
42 | }
43 | },
44 |
45 | invalidate: function() {
46 | this.printRows.length = 0;
47 |
48 | var pathFilter = $('server-cert-tree-path-filter').selectedItem;
49 | var pathValue = pathFilter ? pathFilter.value : '/';
50 | var filterValue = ($('server-cert-tree-filter').value || '').trim();
51 |
52 | function filter(elem) {
53 | var rp = new RegExp('^' + pathValue);
54 | var rv = new RegExp(filterValue);
55 |
56 | if (!rp.test(elem.Path.toString())) {
57 | return false;
58 | }
59 |
60 | for each (var child in elem.*) {
61 | if (rv.test(child.toString())) {
62 | return true;
63 | }
64 | }
65 |
66 | return false;
67 | };
68 |
69 | for (var i = 0; i < this.rows.length; i++) {
70 | var row = this.rows[i];
71 |
72 | if (filter(row)) {
73 | this.printRows.push(row);
74 | }
75 | }
76 |
77 | if (this.rowCount != this.printRows.length) {
78 | this.tree.rowCountChanged(0, -this.rowCount);
79 | this.rowCount = this.printRows.length;
80 | this.tree.rowCountChanged(0, this.rowCount);
81 | }
82 |
83 | this.tree.invalidate();
84 | },
85 |
86 | refresh: function() {
87 | this.rows.length = 0;
88 |
89 | protect(function() {
90 | var pathList = ['/'];
91 |
92 | var walk = function(marker) {
93 | var params = [];
94 |
95 | if (marker) {
96 | params.push(['Marker', marker])
97 | }
98 |
99 | var xhr = inProgress(function() {
100 | return this.iamcli.query_or_die('ListServerCertificates', params);
101 | }.bind(this));
102 |
103 | var xml = xhr.xml();
104 |
105 | for each (var member in xml..ServerCertificateMetadataList.member) {
106 | this.rows.push(member);
107 | pathList.push(member.Path.toString());
108 | }
109 |
110 | var isTruncated = ((xml..IsTruncated || '').toString().trim().toLowerCase() == 'true');
111 |
112 | return isTruncated ? (xml..Marker || '').toString().trim() : null;
113 | }.bind(this);
114 |
115 | var marker = null;
116 |
117 | do {
118 | marker = walk(marker);
119 | } while (marker);
120 |
121 | var pathFilter = $('server-cert-tree-path-filter');
122 | pathFilter.removeAllItems();
123 | pathList = pathList.uniq().sort();
124 |
125 | for (var i = 0; i < pathList.length; i++) {
126 | var path = pathList[i];
127 | pathFilter.appendItem(path, path);
128 | }
129 |
130 | pathFilter.selectedIndex = 0;
131 |
132 | for (var i = 0; i < this.tree.columns.count; i++) {
133 | this.tree.columns.getColumnAt(i).element.setAttribute('sortDirection', 'natural');
134 | }
135 |
136 | this.invalidate();
137 | }.bind(this));
138 | },
139 |
140 | selectedRow: function() {
141 | var idx = this.selection.currentIndex;
142 | return (idx != -1) ? this.printRows[idx] : null;
143 | },
144 |
145 | deleteServerCert: function() {
146 | var cert = this.selectedRow();
147 | if (!cert) { return; }
148 | var certName = cert.ServerCertificateName;
149 |
150 | if (!confirm("Are you sure you want to delete '" + certName + " ' ?")) {
151 | return;
152 | }
153 |
154 | protect(function() {
155 | inProgress(function() {
156 | this.iamcli.query_or_die('DeleteServerCertificate', [['ServerCertificateName', certName]]);
157 |
158 | this.refresh();
159 | }.bind(this));
160 | }.bind(this));
161 | },
162 |
163 | openServerCertEditDialog: function(event) {
164 | var cert = this.selectedRow();
165 |
166 | if (!cert || (event && event.target.tagName != 'treechildren')) {
167 | return;
168 | }
169 |
170 | openDialog('chrome://iamfox/content/server-cert-edit-dialog.xul', 'server-cert-edit-dialog', 'chrome,modal,centerscreen',
171 | {view:this, inProgress:inProgress, cert:cert});
172 | },
173 |
174 | selectByName: function(name) {
175 | var rows = this.rows;
176 |
177 | for (var i = 0; i < rows.length; i++) {
178 | var cert = rows[i];
179 |
180 | if (cert.ServerCertificateName == name) {
181 | this.selection.select(i);
182 | }
183 | }
184 |
185 | this.rows
186 | },
187 |
188 | copyColumnToClipboard: function(name) {
189 | var row = this.selectedRow();
190 |
191 | if (row) {
192 | copyToClipboard(row[name].toString());
193 | }
194 | }
195 | };
196 |
--------------------------------------------------------------------------------
/Resources/chrome/content/sha1.js:
--------------------------------------------------------------------------------
1 | /*
2 | * A JavaScript implementation of the Secure Hash Algorithm, SHA-1, as defined
3 | * in FIPS PUB 180-1
4 | * Version 2.1a Copyright Paul Johnston 2000 - 2002.
5 | * Other contributors: Greg Holt, Andrew Kepert, Ydnar, Lostinet
6 | * Distributed under the BSD License
7 | * See http://pajhome.org.uk/crypt/md5 for details.
8 | */
9 |
10 | /*
11 | * Configurable variables. You may need to tweak these to be compatible with
12 | * the server-side, but the defaults work in most cases.
13 | */
14 | var hexcase = 0; /* hex output format. 0 - lowercase; 1 - uppercase */
15 | var b64pad = "="; /* base-64 pad character. "=" for strict RFC compliance */
16 | var chrsz = 8; /* bits per input character. 8 - ASCII; 16 - Unicode */
17 |
18 | /*
19 | * These are the functions you'll usually want to call
20 | * They take string arguments and return either hex or base-64 encoded strings
21 | */
22 | function hex_sha1(s){return binb2hex(core_sha1(str2binb(s),s.length * chrsz));}
23 | function b64_sha1(s){return binb2b64(core_sha1(str2binb(s),s.length * chrsz));}
24 | function str_sha1(s){return binb2str(core_sha1(str2binb(s),s.length * chrsz));}
25 | function hex_hmac_sha1(key, data){ return binb2hex(core_hmac_sha1(key, data));}
26 | function b64_hmac_sha1(key, data){ return binb2b64(core_hmac_sha1(key, data));}
27 | function str_hmac_sha1(key, data){ return binb2str(core_hmac_sha1(key, data));}
28 |
29 | /*
30 | * Perform a simple self-test to see if the VM is working
31 | */
32 | function sha1_vm_test()
33 | {
34 | return hex_sha1("abc") == "a9993e364706816aba3e25717850c26c9cd0d89d";
35 | }
36 |
37 | /*
38 | * Calculate the SHA-1 of an array of big-endian words, and a bit length
39 | */
40 | function core_sha1(x, len)
41 | {
42 | /* append padding */
43 | x[len >> 5] |= 0x80 << (24 - len % 32);
44 | x[((len + 64 >> 9) << 4) + 15] = len;
45 |
46 | var w = Array(80);
47 | var a = 1732584193;
48 | var b = -271733879;
49 | var c = -1732584194;
50 | var d = 271733878;
51 | var e = -1009589776;
52 |
53 | for(var i = 0; i < x.length; i += 16)
54 | {
55 | var olda = a;
56 | var oldb = b;
57 | var oldc = c;
58 | var oldd = d;
59 | var olde = e;
60 |
61 | for(var j = 0; j < 80; j++)
62 | {
63 | if(j < 16) w[j] = x[i + j];
64 | else w[j] = rol(w[j-3] ^ w[j-8] ^ w[j-14] ^ w[j-16], 1);
65 | var t = safe_add(safe_add(rol(a, 5), sha1_ft(j, b, c, d)),
66 | safe_add(safe_add(e, w[j]), sha1_kt(j)));
67 | e = d;
68 | d = c;
69 | c = rol(b, 30);
70 | b = a;
71 | a = t;
72 | }
73 |
74 | a = safe_add(a, olda);
75 | b = safe_add(b, oldb);
76 | c = safe_add(c, oldc);
77 | d = safe_add(d, oldd);
78 | e = safe_add(e, olde);
79 | }
80 | return Array(a, b, c, d, e);
81 |
82 | }
83 |
84 | /*
85 | * Perform the appropriate triplet combination function for the current
86 | * iteration
87 | */
88 | function sha1_ft(t, b, c, d)
89 | {
90 | if(t < 20) return (b & c) | ((~b) & d);
91 | if(t < 40) return b ^ c ^ d;
92 | if(t < 60) return (b & c) | (b & d) | (c & d);
93 | return b ^ c ^ d;
94 | }
95 |
96 | /*
97 | * Determine the appropriate additive constant for the current iteration
98 | */
99 | function sha1_kt(t)
100 | {
101 | return (t < 20) ? 1518500249 : (t < 40) ? 1859775393 :
102 | (t < 60) ? -1894007588 : -899497514;
103 | }
104 |
105 | /*
106 | * Calculate the HMAC-SHA1 of a key and some data
107 | */
108 | function core_hmac_sha1(key, data)
109 | {
110 | var bkey = str2binb(key);
111 | if(bkey.length > 16) bkey = core_sha1(bkey, key.length * chrsz);
112 |
113 | var ipad = Array(16), opad = Array(16);
114 | for(var i = 0; i < 16; i++)
115 | {
116 | ipad[i] = bkey[i] ^ 0x36363636;
117 | opad[i] = bkey[i] ^ 0x5C5C5C5C;
118 | }
119 |
120 | var hash = core_sha1(ipad.concat(str2binb(data)), 512 + data.length * chrsz);
121 | return core_sha1(opad.concat(hash), 512 + 160);
122 | }
123 |
124 | /*
125 | * Add integers, wrapping at 2^32. This uses 16-bit operations internally
126 | * to work around bugs in some JS interpreters.
127 | */
128 | function safe_add(x, y)
129 | {
130 | var lsw = (x & 0xFFFF) + (y & 0xFFFF);
131 | var msw = (x >> 16) + (y >> 16) + (lsw >> 16);
132 | return (msw << 16) | (lsw & 0xFFFF);
133 | }
134 |
135 | /*
136 | * Bitwise rotate a 32-bit number to the left.
137 | */
138 | function rol(num, cnt)
139 | {
140 | return (num << cnt) | (num >>> (32 - cnt));
141 | }
142 |
143 | /*
144 | * Convert an 8-bit or 16-bit string to an array of big-endian words
145 | * In 8-bit function, characters >255 have their hi-byte silently ignored.
146 | */
147 | function str2binb(str)
148 | {
149 | var bin = new Array();
150 | var mask = (1 << chrsz) - 1;
151 | for(var i = 0; i < str.length * chrsz; i += chrsz) {
152 | bin[i>>5] |= (str.charCodeAt(i / chrsz) & mask) << (32 - chrsz - i%32);
153 | }
154 | return bin;
155 | }
156 |
157 | /*
158 | * Convert an array of big-endian words to a string
159 | */
160 | function binb2str(bin)
161 | {
162 | var str = "";
163 | var mask = (1 << chrsz) - 1;
164 | for(var i = 0; i < bin.length * 32; i += chrsz)
165 | str += String.fromCharCode((bin[i>>5] >>> (32 - chrsz - i%32)) & mask);
166 | return str;
167 | }
168 |
169 | /*
170 | * Convert an array of big-endian words to a hex string.
171 | */
172 | function binb2hex(binarray)
173 | {
174 | var hex_tab = hexcase ? "0123456789ABCDEF" : "0123456789abcdef";
175 | var str = "";
176 | for(var i = 0; i < binarray.length * 4; i++)
177 | {
178 | str += hex_tab.charAt((binarray[i>>2] >> ((3 - i%4)*8+4)) & 0xF) +
179 | hex_tab.charAt((binarray[i>>2] >> ((3 - i%4)*8 )) & 0xF);
180 | }
181 | return str;
182 | }
183 |
184 | /*
185 | * Convert an array of big-endian words to a base-64 string
186 | */
187 | function binb2b64(binarray)
188 | {
189 | var tab = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
190 | var str = "";
191 | for(var i = 0; i < binarray.length * 4; i += 3)
192 | {
193 | var triplet = (((binarray[i >> 2] >> 8 * (3 - i %4)) & 0xFF) << 16)
194 | | (((binarray[i+1 >> 2] >> 8 * (3 - (i+1)%4)) & 0xFF) << 8 )
195 | | ((binarray[i+2 >> 2] >> 8 * (3 - (i+2)%4)) & 0xFF);
196 | for(var j = 0; j < 4; j++)
197 | {
198 | if((i * 8 + j * 6) > (binarray.length * 32)) str += b64pad;
199 | else str += tab.charAt((triplet >> 6*(3-j)) & 0x3F);
200 | }
201 | }
202 | return str;
203 | }
204 |
205 |
--------------------------------------------------------------------------------
/Resources/chrome/content/signing-cert-add-dialog.xul:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
62 |
--------------------------------------------------------------------------------
/Resources/chrome/content/signing-cert-edit-dialog.xul:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
69 |
--------------------------------------------------------------------------------
/Resources/chrome/content/user-add-dialog.xul:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
73 |
--------------------------------------------------------------------------------
/Resources/chrome/content/user-cert-window.js:
--------------------------------------------------------------------------------
1 | function windowOnLoad() {
2 | var args = window.arguments[0];
3 | document.title = 'Certificates - ' + args.userName;
4 | var listbox = $('user-cert-listbox');
5 | refreshUserCert();
6 | }
7 |
8 | function listboxOnSelect(event) {
9 | var args = window.arguments[0];
10 | var iamcli = args.iamcli;
11 | var userName = args.userName;
12 |
13 | var item = event.currentTarget;
14 |
15 | if (!item || !item.value) {
16 | return;
17 | }
18 |
19 | var textbox = $('user-cert-textbox');
20 | var status = $('user-cert-status-textbox');
21 | var certId = item.value;
22 | textbox.value = decodeURIComponent(window.certHash[certId].CertificateBody);
23 | status.value = window.certHash[certId].Status;
24 | }
25 |
26 | function inProgress(callback) {
27 | var loader = $('user-cert-loader');
28 | loader.hidden = false;
29 |
30 | var retval = null;
31 | var exception = null;
32 |
33 | try {
34 | retval = callback();
35 | } catch (e) {
36 | exception = e;
37 | }
38 |
39 | loader.hidden = true;
40 |
41 | if (exception) {
42 | throw exception;
43 | }
44 |
45 | return retval;
46 | }
47 |
48 | function openSigningCertAddDialog() {
49 | var args = window.arguments[0];
50 | var iamcli = args.iamcli;
51 | var userName = args.userName;
52 |
53 | openDialog('chrome://iamfox/content/signing-cert-add-dialog.xul', 'signing-cert-add-dialog', 'chrome,modal,centerscreen,width=400,height=400',
54 | {iamcli:iamcli, refreshUserCert:refreshUserCert, inProgress:inProgress, userName:userName});
55 | }
56 |
57 | function editCert() {
58 | var args = window.arguments[0];
59 | var iamcli = args.iamcli;
60 | var userName = args.userName;
61 |
62 | var listbox = $('user-cert-listbox');
63 | var item = listbox.selectedItem;
64 |
65 | if (!item || !item.value) {
66 | return;
67 | }
68 |
69 | var certId = item.value;
70 | var status = window.certHash[certId].Status.toString();
71 |
72 | openDialog('chrome://iamfox/content/signing-cert-edit-dialog.xul', 'signing-cert-edit-dialog', 'chrome,modal,centerscreen',
73 | {iamcli:iamcli, refreshUserCert:refreshUserCert, inProgress:inProgress, userName:userName, certificateId:certId, status:status});
74 | }
75 |
76 | function deleteUserCert() {
77 | var args = window.arguments[0];
78 | var iamcli = args.iamcli;
79 | var userName = args.userName;
80 |
81 | var listbox = $('user-cert-listbox');
82 | var item = listbox.selectedItem;
83 |
84 | if (!item || !item.value) {
85 | return;
86 | }
87 |
88 | var certId = item.value;
89 |
90 | if (!confirm("Are you sure you want to delete '" + certId + " ' ?")) {
91 | return;
92 | }
93 |
94 | protect(function() {
95 | inProgress(function() {
96 | var params = [['UserName', userName], ['CertificateId', certId]];
97 | iamcli.query_or_die('DeleteSigningCertificate', params);
98 | });
99 |
100 | var textbox = $('user-cert-textbox');
101 | var status = $('user-cert-status-textbox');
102 | delete window.certHash[certId];
103 | listbox.removeItemAt(listbox.currentIndex);
104 | listbox.clearSelection();
105 | textbox.value = null;
106 | status.value = null;
107 | });
108 | }
109 |
110 | function refreshUserCert() {
111 | var args = window.arguments[0];
112 | var iamcli = args.iamcli;
113 | var userName = args.userName;
114 |
115 | protect(function() {
116 | var certificates = [];
117 | window.certHash = {};
118 |
119 | var walk = function(marker) {
120 | var params = [['UserName', userName]];
121 |
122 | if (marker) {
123 | params.push(['Marker', marker])
124 | }
125 |
126 | var xhr = inProgress(function() {
127 | return iamcli.query_or_die('ListSigningCertificates', params);
128 | });
129 |
130 | var xml = xhr.xml();
131 |
132 | for each (var member in xml..Certificates.member) {
133 | certificates.push(member);
134 | window.certHash[member.CertificateId.toString()] = member;
135 | }
136 |
137 | var isTruncated = ((xml..IsTruncated || '').toString().trim().toLowerCase() == 'true');
138 |
139 | return isTruncated ? (xml..Marker || '').toString().trim() : null;
140 | }.bind(this);
141 |
142 | var marker = null;
143 |
144 | do {
145 | marker = walk(marker);
146 | } while (marker);
147 |
148 | var listbox = $('user-cert-listbox');
149 | var textbox = $('user-cert-textbox');
150 | var status = $('user-cert-status-textbox');
151 |
152 | listbox.clearSelection();
153 | textbox.value = null;
154 | status.value = null;
155 |
156 | for (var i = listbox.itemCount - 1; i >= 0; i--) {
157 | listbox.removeItemAt(i);
158 | }
159 |
160 | for (var i = 0; i < certificates.length; i++) {
161 | var cert = certificates[i];
162 | listbox.appendItem(cert.CertificateId, cert.CertificateId);
163 | }
164 | });
165 | }
166 |
--------------------------------------------------------------------------------
/Resources/chrome/content/user-cert-window.xul:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
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 |
--------------------------------------------------------------------------------
/Resources/chrome/content/user-create-login-profile-dialog.xul:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
55 |
--------------------------------------------------------------------------------
/Resources/chrome/content/user-detail-window.js:
--------------------------------------------------------------------------------
1 | function windowOnLoad() {
2 | var args = window.arguments[0];
3 | document.title = 'Policies - ' + args.userName;
4 | var listbox = $('user-policy-listbox');
5 | refreshUserPolicy();
6 | }
7 |
8 | function listboxOnSelect(event) {
9 | var args = window.arguments[0];
10 | var iamcli = args.iamcli;
11 | var userName = args.userName;
12 |
13 | var item = event.currentTarget;
14 |
15 | if (!item || !item.value) {
16 | return;
17 | }
18 |
19 | var textbox = $('user-policy-textbox');
20 |
21 | var policyName = item.value;
22 |
23 | protect(function() {
24 | inProgress(function() {
25 | var params = [['UserName', userName], ['PolicyName', policyName]];
26 | var xhr = iamcli.query_or_die('GetUserPolicy', params);
27 |
28 | var policy = xhr.xml().GetUserPolicyResult;
29 | textbox.value = decodeURIComponent(policy.PolicyDocument);
30 | disableUpdateButton();
31 | });
32 | });
33 | }
34 |
35 | function inProgress(callback) {
36 | var loader = $('user-policy-loader');
37 | loader.hidden = false;
38 |
39 | var retval = null;
40 | var exception = null;
41 |
42 | try {
43 | retval = callback();
44 | } catch (e) {
45 | exception = e;
46 | }
47 |
48 | loader.hidden = true;
49 |
50 | if (exception) {
51 | throw exception;
52 | }
53 |
54 | return retval;
55 | }
56 |
57 | function addUserPolicy() {
58 | var args = window.arguments[0];
59 | var iamcli = args.iamcli;
60 | var userName = args.userName;
61 |
62 | var policyName = prompt('Policy Name');
63 | policyName = (policyName || '').trim();
64 |
65 | if (policyName.length < 1) {
66 | return;
67 | }
68 |
69 | var listbox = $('user-policy-listbox');
70 |
71 | for (var i = 0; i < listbox.itemCount; i++) {
72 | var item = listbox.getItemAtIndex(i);
73 |
74 | if (item.value == policyName) {
75 | alert('Duplicate policy');
76 | return;
77 | }
78 | }
79 |
80 | protect(function() {
81 | inProgress(function() {
82 | var params = [
83 | ['UserName', userName],
84 | ['PolicyName', policyName],
85 | ['PolicyDocument', POLICY_ALLOW_ALL]
86 | ];
87 |
88 | iamcli.query_or_die('PutUserPolicy', params);
89 | });
90 |
91 | var textbox = $('user-policy-textbox');
92 | var item = listbox.appendItem(policyName, policyName);
93 | listbox.selectItem(item);
94 | textbox.value = POLICY_ALLOW_ALL;
95 | disableUpdateButton();
96 | });
97 | }
98 |
99 | function deleteUserPolicy() {
100 | var args = window.arguments[0];
101 | var iamcli = args.iamcli;
102 | var userName = args.userName;
103 |
104 | var listbox = $('user-policy-listbox');
105 | var item = listbox.selectedItem;
106 |
107 | if (!item || !item.value) {
108 | return;
109 | }
110 |
111 | var policyName = item.value;
112 |
113 | if (!confirm("Are you sure you want to delete '" + policyName + " ' ?")) {
114 | return;
115 | }
116 |
117 | protect(function() {
118 | inProgress(function() {
119 | var params = [['UserName', userName], ['PolicyName', policyName]];
120 | iamcli.query_or_die('DeleteUserPolicy', params);
121 | });
122 |
123 | var textbox = $('user-policy-textbox');
124 | listbox.removeItemAt(listbox.currentIndex);
125 | listbox.clearSelection();
126 | textbox.value = null;
127 | disableUpdateButton();
128 | });
129 | }
130 |
131 | function refreshUserPolicy() {
132 | var args = window.arguments[0];
133 | var iamcli = args.iamcli;
134 | var userName = args.userName;
135 |
136 | protect(function() {
137 | var policyNames = [];
138 |
139 | var walk = function(marker) {
140 | var params = [['UserName', userName]];
141 |
142 | if (marker) {
143 | params.push(['Marker', marker])
144 | }
145 |
146 | var xhr = inProgress(function() {
147 | return iamcli.query_or_die('ListUserPolicies', params);
148 | });
149 |
150 | var xml = xhr.xml();
151 |
152 | for each (var member in xml..PolicyNames.member) {
153 | policyNames.push(member);
154 | }
155 |
156 | var isTruncated = ((xml..IsTruncated || '').toString().trim().toLowerCase() == 'true');
157 |
158 | return isTruncated ? (xml..Marker || '').toString().trim() : null;
159 | }.bind(this);
160 |
161 | var marker = null;
162 |
163 | do {
164 | marker = walk(marker);
165 | } while (marker);
166 |
167 | var listbox = $('user-policy-listbox');
168 | var textbox = $('user-policy-textbox');
169 |
170 | listbox.clearSelection();
171 | textbox.value = null;
172 | disableUpdateButton();
173 |
174 | for (var i = listbox.itemCount - 1; i >= 0; i--) {
175 | listbox.removeItemAt(i);
176 | }
177 |
178 | for (var i = 0; i < policyNames.length; i++) {
179 | var policyName = policyNames[i];
180 | listbox.appendItem(policyName, policyName);
181 | }
182 | });
183 | }
184 |
185 | function updateUserPolicy() {
186 | var args = window.arguments[0];
187 | var iamcli = args.iamcli;
188 | var userName = args.userName;
189 |
190 | var listbox = $('user-policy-listbox');
191 | var textbox = $('user-policy-textbox');
192 |
193 | var item = listbox.selectedItem;
194 |
195 | if (!item || !item.value) {
196 | return;
197 | }
198 |
199 | var policyName = item.value;
200 | var policyDocument = (textbox.value || '').trim();
201 |
202 | protect(function() {
203 | inProgress(function() {
204 | var params = [
205 | ['UserName', userName],
206 | ['PolicyName', policyName],
207 | ['PolicyDocument', policyDocument]
208 | ];
209 |
210 | iamcli.query_or_die('PutUserPolicy', params);
211 | });
212 |
213 | textbox.value = policyDocument;
214 | disableUpdateButton();
215 | });
216 | }
217 |
218 | function enableUpdateButton() {
219 | $('user-policy-update-button').disabled = false;
220 | }
221 |
222 | function disableUpdateButton() {
223 | $('user-policy-update-button').disabled = true;
224 | }
225 |
--------------------------------------------------------------------------------
/Resources/chrome/content/user-detail-window.xul:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
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 |
--------------------------------------------------------------------------------
/Resources/chrome/content/user-edit-dialog.xul:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
69 |
--------------------------------------------------------------------------------
/Resources/chrome/content/user-group-window.js:
--------------------------------------------------------------------------------
1 | function windowOnLoad() {
2 | var args = window.arguments[0];
3 | document.title = 'Group - ' + args.userName;
4 | var listbox = $('user-group-listbox');
5 | refreshUserGroup();
6 | }
7 |
8 | function inProgress(callback) {
9 | var loader = $('user-group-loader');
10 | loader.hidden = false;
11 |
12 | var retval = null;
13 | var exception = null;
14 |
15 | try {
16 | retval = callback();
17 | } catch (e) {
18 | exception = e;
19 | }
20 |
21 | loader.hidden = true;
22 |
23 | if (exception) {
24 | throw exception;
25 | }
26 |
27 | return retval;
28 | }
29 |
30 | function addUserToGroup() {
31 | var args = window.arguments[0];
32 | var iamcli = args.iamcli;
33 | var userName = args.userName;
34 |
35 | var menulist = $('user-group-menulist');
36 | var item = menulist.selectedItem;
37 |
38 | if (!item || !item.value) {
39 | alert("Please select 'Group'.");
40 | return;
41 | }
42 |
43 | var groupName = item.value;
44 |
45 | protect(function() {
46 | inProgress(function() {
47 | var params = [['UserName', userName], ['GroupName', groupName]];
48 | iamcli.query_or_die('AddUserToGroup', params);
49 | });
50 |
51 | refreshUserGroup();
52 | });
53 | }
54 |
55 | function removeUserFromGroup() {
56 | var args = window.arguments[0];
57 | var iamcli = args.iamcli;
58 | var userName = args.userName;
59 |
60 | var listbox = $('user-group-listbox');
61 | var item = listbox.selectedItem;
62 |
63 | if (!item || !item.value) {
64 | return;
65 | }
66 |
67 | var groupName = item.value;
68 |
69 | if (!confirm("Are you sure you want to remove '" + userName + "' from '" + groupName + " ' ?")) {
70 | return;
71 | }
72 |
73 | protect(function() {
74 | inProgress(function() {
75 | var params = [['UserName', userName], ['GroupName', groupName]];
76 | iamcli.query_or_die('RemoveUserFromGroup', params);
77 | });
78 |
79 | refreshUserGroup();
80 | });
81 | }
82 |
83 | function refreshUserGroup() {
84 | var args = window.arguments[0];
85 | var iamcli = args.iamcli;
86 | var userName = args.userName;
87 |
88 | var menulist = $('user-group-menulist');
89 | var listbox = $('user-group-listbox');
90 |
91 | protect(function() {
92 | var groups = [];
93 | var belongs_to = [];
94 |
95 | inProgress(function() {
96 | var walk = function(marker) {
97 | var params = [];
98 |
99 | if (marker) {
100 | params.push(['Marker', marker])
101 | }
102 |
103 | var xhr = iamcli.query_or_die('ListGroups', params);
104 | var xml = xhr.xml();
105 |
106 | for each (var member in xml..Groups.member) {
107 | groups.push(member.GroupName.toString());
108 | }
109 |
110 | var isTruncated = ((xml..IsTruncated || '').toString().trim().toLowerCase() == 'true');
111 |
112 | return isTruncated ? (xml..Marker || '').toString().trim() : null;
113 | }.bind(this);
114 |
115 | var marker = null;
116 |
117 | do {
118 | marker = walk(marker);
119 | } while (marker);
120 | });
121 |
122 | var xhr = inProgress(function() {
123 | var walk = function(marker) {
124 | var params = [['UserName', userName]];
125 |
126 | if (marker) {
127 | params.push(['Marker', marker])
128 | }
129 |
130 | var xhr = iamcli.query_or_die('ListGroupsForUser', params);
131 | var xml = xhr.xml();
132 |
133 | for each (var member in xhr.xml()..Groups.member) {
134 | belongs_to.push(member.GroupName.toString());
135 | }
136 |
137 | var isTruncated = ((xml..IsTruncated || '').toString().trim().toLowerCase() == 'true');
138 |
139 | return isTruncated ? (xml..Marker || '').toString().trim() : null;
140 | }.bind(this);
141 |
142 | var marker = null;
143 |
144 | do {
145 | marker = walk(marker);
146 | } while (marker);
147 | });
148 |
149 | var listbox = $('user-group-listbox');
150 |
151 | listbox.clearSelection();
152 |
153 | for (var i = listbox.itemCount - 1; i >= 0; i--) {
154 | listbox.removeItemAt(i);
155 | }
156 |
157 | for (var i = 0; i < belongs_to.length; i++) {
158 | var groupName = belongs_to[i];
159 | listbox.appendItem(groupName, groupName);
160 | }
161 |
162 | var menulist = $('user-group-menulist');
163 |
164 | menulist.removeAllItems();
165 |
166 | for (var i = 0; i < groups.length; i++) {
167 | var groupName = groups[i];
168 |
169 | if (belongs_to.indexOf(groupName) == -1) {
170 | menulist.appendItem(groupName, groupName);
171 | }
172 | }
173 | });
174 | }
175 |
--------------------------------------------------------------------------------
/Resources/chrome/content/user-group-window.xul:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
21 |
22 |
23 |
24 |
25 |
26 |
27 |
30 |
31 |
32 |
33 |
34 |
35 |
36 |
37 |
38 |
39 |
40 |
41 |
42 |
43 |
--------------------------------------------------------------------------------
/Resources/chrome/content/user-open-console-dialog.xul:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
48 |
--------------------------------------------------------------------------------
/Resources/chrome/content/user-tabpanel.xul:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
38 |
39 |
40 |
41 |
42 |
43 |
44 |
45 | Path:
46 |
47 |
48 |
49 |
50 |
51 | Search:
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 |
--------------------------------------------------------------------------------
/Resources/chrome/content/user-tree-view.js:
--------------------------------------------------------------------------------
1 | function UserTreeView(iamcli) {
2 | this.iamcli = iamcli;
3 | this.rows = [];
4 | this.printRows = [];
5 | this.rowCount = 0;
6 | this.selection = null;
7 | this.sorted = false;
8 | }
9 |
10 | UserTreeView.prototype = {
11 | getCellText: function(row, column) {
12 | var colkey = column.id.toString().split('.');
13 |
14 | if (colkey.length < 1) {
15 | return null;
16 | }
17 |
18 | colkey = colkey[colkey.length - 1];
19 |
20 | return this.printRows[row][colkey];
21 | },
22 |
23 | setTree: function(tree) {
24 | this.tree = tree;
25 | },
26 |
27 | isSorted: function() {
28 | return this.sorted;
29 | },
30 |
31 | cycleHeader: function(column) {
32 | var user = this.selectedRow();
33 | if (!user) { return; }
34 |
35 | if (sortRowsByColumn(column, this.rows)) {
36 | this.invalidate();
37 | this.sorted = true;
38 |
39 | if (user) {
40 | this.selectByName(user.UserName);
41 | }
42 | }
43 | },
44 |
45 | invalidate: function() {
46 | this.printRows.length = 0;
47 |
48 | var pathFilter = $('user-tree-path-filter').selectedItem;
49 | var pathValue = pathFilter ? pathFilter.value : '/';
50 | var filterValue = ($('user-tree-filter').value || '').trim();
51 |
52 | function filter(elem) {
53 | var rp = new RegExp('^' + pathValue);
54 | var rv = new RegExp(filterValue);
55 |
56 | if (!rp.test(elem.Path.toString())) {
57 | return false;
58 | }
59 |
60 | for each (var child in elem.*) {
61 | if (rv.test(child.toString())) {
62 | return true;
63 | }
64 | }
65 |
66 | return false;
67 | };
68 |
69 | for (var i = 0; i < this.rows.length; i++) {
70 | var row = this.rows[i];
71 |
72 | if (filter(row)) {
73 | this.printRows.push(row);
74 | }
75 | }
76 |
77 | if (this.rowCount != this.printRows.length) {
78 | this.tree.rowCountChanged(0, -this.rowCount);
79 | this.rowCount = this.printRows.length;
80 | this.tree.rowCountChanged(0, this.rowCount);
81 | }
82 |
83 | this.tree.invalidate();
84 | },
85 |
86 | refresh: function(noupdate) {
87 | this.rows.length = 0;
88 |
89 | protect(function() {
90 | var pathList = ['/'];
91 |
92 | var walk = function(marker) {
93 | var params = [];
94 |
95 | if (marker) {
96 | params.push(['Marker', marker])
97 | }
98 |
99 | var xhr = inProgress(function() {
100 | return this.iamcli.query_or_die('ListUsers', params);
101 | }.bind(this));
102 |
103 | var xml = xhr.xml();
104 |
105 | for each (var member in xml..Users.member) {
106 | this.rows.push(member);
107 | pathList.push(member.Path.toString());
108 | }
109 |
110 | var isTruncated = ((xml..IsTruncated || '').toString().trim().toLowerCase() == 'true');
111 |
112 | return isTruncated ? (xml..Marker || '').toString().trim() : null;
113 | }.bind(this);
114 |
115 | var marker = null;
116 |
117 | do {
118 | marker = walk(marker);
119 | } while (marker);
120 |
121 | var pathFilter = $('user-tree-path-filter');
122 | pathFilter.removeAllItems();
123 | pathList = pathList.uniq().sort();
124 |
125 | for (var i = 0; i < pathList.length; i++) {
126 | var path = pathList[i];
127 | pathFilter.appendItem(path, path);
128 | }
129 |
130 | pathFilter.selectedIndex = 0;
131 |
132 | for (var i = 0; i < this.tree.columns.count; i++) {
133 | this.tree.columns.getColumnAt(i).element.setAttribute('sortDirection', 'natural');
134 | }
135 |
136 | this.invalidate();
137 | }.bind(this));
138 | },
139 |
140 | onDblclick: function(event) {
141 | var user = this.selectedRow();
142 |
143 | if (!user || (event && event.target.tagName != 'treechildren')) {
144 | return;
145 | }
146 |
147 | var userName = user.UserName;
148 | var xhr = null;
149 |
150 | openModalWindow('user-detail-window.xul', 'user-datail-window', 640, 480,
151 | {iamcli:this.iamcli, userName:userName});
152 | },
153 |
154 | selectedRow: function() {
155 | var idx = this.selection.currentIndex;
156 | return (idx != -1) ? this.printRows[idx] : null;
157 | },
158 |
159 | openUserCertWindow: function(event) {
160 | var user = this.selectedRow();
161 | if (!user) { return; }
162 | var userName = user.UserName;
163 |
164 | openModalWindow('user-cert-window.xul', 'user-cert-window', 640, 480,
165 | {iamcli:this.iamcli, userName:userName});
166 | },
167 |
168 | deleteUser: function() {
169 | var user = this.selectedRow();
170 | if (!user) { return; }
171 | var userName = user.UserName;
172 |
173 | if (!confirm("Are you sure you want to delete '" + userName + "' ?")) {
174 | return;
175 | }
176 |
177 | protect(function() {
178 | inProgress(function() {
179 | var walk = function(marker) {
180 | var params = [['UserName', userName]];
181 |
182 | if (marker) {
183 | params.push(['Marker', marker])
184 | }
185 |
186 | var xhr = this.iamcli.query_or_die('ListAccessKeys', params);
187 | var xml = xhr.xml();
188 |
189 | for each (var member in xml..AccessKeyMetadata.member) {
190 | var params = [['UserName', userName], ['AccessKeyId', member.AccessKeyId]];
191 | this.iamcli.query_or_die('DeleteAccessKey', params);
192 | }
193 |
194 | var isTruncated = ((xml..IsTruncated || '').toString().trim().toLowerCase() == 'true');
195 |
196 | return isTruncated ? (xml..Marker || '').toString().trim() : null;
197 | }.bind(this);
198 |
199 | var marker = null;
200 |
201 | do {
202 | marker = walk(marker);
203 | } while (marker);
204 |
205 | walk = function(marker) {
206 | var params = [['UserName', userName]];
207 |
208 | if (marker) {
209 | params.push(['Marker', marker])
210 | }
211 |
212 | var xhr = this.iamcli.query_or_die('ListGroupsForUser', params);
213 | var xml = xhr.xml();
214 |
215 | for each (var member in xml..Groups.member) {
216 | var params = [['UserName', userName], ['GroupName', member.GroupName]];
217 | this.iamcli.query_or_die('RemoveUserFromGroup', params);
218 | }
219 |
220 | var isTruncated = ((xml..IsTruncated || '').toString().trim().toLowerCase() == 'true');
221 |
222 | return isTruncated ? (xml..Marker || '').toString().trim() : null;
223 | }.bind(this);
224 |
225 | marker = null;
226 |
227 | do {
228 | marker = walk(marker);
229 | } while (marker);
230 |
231 | walk = function(marker) {
232 | var params = [['UserName', userName]];
233 |
234 | if (marker) {
235 | params.push(['Marker', marker])
236 | }
237 |
238 | var xhr = this.iamcli.query_or_die('ListSigningCertificates', params);
239 | var xml = xhr.xml();
240 |
241 | for each (var member in xml..Certificates.member) {
242 | var params = [['UserName', userName], ['CertificateId', member.CertificateId]];
243 | this.iamcli.query_or_die('DeleteSigningCertificate', params);
244 | }
245 |
246 | var isTruncated = ((xml..IsTruncated || '').toString().trim().toLowerCase() == 'true');
247 |
248 | return isTruncated ? (xml..Marker || '').toString().trim() : null;
249 | }.bind(this);
250 |
251 | marker = null;
252 |
253 | do {
254 | marker = walk(marker);
255 | } while (marker);
256 |
257 | walk = function(marker) {
258 | var params = [['UserName', userName]];
259 |
260 | if (marker) {
261 | params.push(['Marker', marker])
262 | }
263 |
264 | var xhr = this.iamcli.query_or_die('ListUserPolicies', params);
265 | var xml = xhr.xml();
266 |
267 | for each (var member in xml..PolicyNames.member) {
268 | var params = [['UserName', userName], ['PolicyName', member]];
269 | this.iamcli.query_or_die('DeleteUserPolicy', params);
270 | }
271 |
272 | var isTruncated = ((xml..IsTruncated || '').toString().trim().toLowerCase() == 'true');
273 |
274 | return isTruncated ? (xml..Marker || '').toString().trim() : null;
275 | }.bind(this);
276 |
277 | marker = null;
278 |
279 | do {
280 | marker = walk(marker);
281 | } while (marker);
282 |
283 | this.iamcli.query_or_die('DeleteUser', [['UserName', userName]]);
284 |
285 | Prefs.deleteUserAccessKeyId(userName);
286 | Prefs.deleteUserSecretAccessKey(userName);
287 |
288 | this.refresh();
289 | }.bind(this));
290 | }.bind(this));
291 | },
292 |
293 | openUserEditDialog: function() {
294 | var user = this.selectedRow();
295 | if (!user) { return; }
296 | openDialog('chrome://iamfox/content/user-edit-dialog.xul', 'user-edit-dialog', 'chrome,modal,centerscreen',
297 | {view:this, inProgress:inProgress, user:user});
298 | },
299 |
300 | openViewKeyDialog: function() {
301 | var user = this.selectedRow();
302 | if (!user) { return; }
303 | openDialog('chrome://iamfox/content/user-view-key-dialog.xul', 'user-edit-dialog', 'chrome,modal,centerscreen',
304 | {view:this, inProgress:inProgress, user:user});
305 | },
306 |
307 | openUserCreateLoginProfileDialog: function() {
308 | var user = this.selectedRow();
309 | if (!user) { return; }
310 | openDialog('chrome://iamfox/content/user-create-login-profile-dialog.xul', 'user-create-login-profile-dialog', 'chrome,modal,centerscreen',
311 | {view:this, inProgress:inProgress, user:user});
312 | },
313 |
314 | openUserOpenConsoleDialog: function() {
315 | var user = this.selectedRow();
316 | if (!user) { return; }
317 | openDialog('chrome://iamfox/content/user-open-console-dialog.xul', 'user-open-console-dialog', 'chrome,modal,centerscreen', {user:user});
318 | },
319 |
320 | selectByName: function(name) {
321 | var rows = this.rows;
322 |
323 | for (var i = 0; i < rows.length; i++) {
324 | var user = rows[i];
325 |
326 | if (user.UserName == name) {
327 | this.selection.select(i);
328 | }
329 | }
330 |
331 | this.rows
332 | },
333 |
334 | openUserGroupWindow: function() {
335 | var user = this.selectedRow();
336 | if (!user) { return; }
337 | openModalWindow('user-group-window.xul', 'user-cert-window', 400, 400,
338 | {iamcli:this.iamcli, userName:user.UserName});
339 | },
340 |
341 | deleteLoginProfile: function() {
342 | var user = this.selectedRow();
343 | if (!user) { return; }
344 | var userName = user.UserName;
345 |
346 | if (!confirm("Are you sure you want to delete '" + userName + "'s login profile' ?")) {
347 | return;
348 | }
349 |
350 | protect(function() {
351 | inProgress(function() {
352 | this.iamcli.query_or_die('DeleteLoginProfile', [['UserName', userName]]);
353 | }.bind(this));
354 | }.bind(this));
355 | },
356 |
357 | copyColumnToClipboard: function(name) {
358 | var row = this.selectedRow();
359 |
360 | if (row) {
361 | copyToClipboard(row[name].toString());
362 | }
363 | }
364 | };
365 |
--------------------------------------------------------------------------------
/Resources/chrome/content/user-view-key-dialog.xul:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
55 |
--------------------------------------------------------------------------------
/Resources/chrome/content/user-view-key-tree-view.js:
--------------------------------------------------------------------------------
1 | function UserViewKeyTreeView(user, iamcli, inProgress) {
2 | this.user = user;
3 | this.iamcli = iamcli;
4 | this.inProgress = inProgress;
5 | this.rowCount = 0;
6 | this.selection = null;
7 | this.sorted = false;
8 | this.data = [];
9 | }
10 |
11 | UserViewKeyTreeView.prototype = {
12 | updateData: function() {
13 | var accessKeyId = Prefs.getUserAccessKeyId(this.user.UserName);
14 | var secretAccessKey = Prefs.getUserSecretAccessKey(this.user.UserName);
15 | var hash = {};
16 | var data = [];
17 |
18 | for (var i = 0; i < accessKeyId.length; i++) {
19 | hash[accessKeyId[i]] = secretAccessKey[i];
20 | }
21 |
22 | protect(function() {
23 | this.inProgress(function() {
24 | var walk = function(marker) {
25 | var params = [['UserName', this.user.UserName]];
26 |
27 | if (marker) {
28 | params.push(['Marker', marker])
29 | }
30 |
31 | var xhr = this.iamcli.query_or_die('ListAccessKeys', params);
32 | var xml = xhr.xml();
33 |
34 | for each (var member in xml..AccessKeyMetadata.member) {
35 | var akid = member.AccessKeyId.toString();
36 | data.push([akid, hash[akid]]);
37 | }
38 |
39 | var isTruncated = ((xml..IsTruncated || '').toString().trim().toLowerCase() == 'true');
40 |
41 | return isTruncated ? (xml..Marker || '').toString().trim() : null;
42 | }.bind(this);
43 |
44 | var marker = null;
45 |
46 | do {
47 | marker = walk(marker);
48 | } while (marker);
49 | }.bind(this));
50 | }.bind(this));
51 |
52 | this.data = data;
53 | },
54 |
55 | getCellText: function(row, column) {
56 | var idx = column.id.toString().split('.');
57 | idx = idx[idx.length - 1];
58 |
59 | return this.data[row][idx];
60 | },
61 |
62 | setTree: function(tree) {
63 | this.tree = tree;
64 | },
65 |
66 | refresh: function() {
67 | this.updateData();
68 |
69 | if (this.rowCount != this.data.length) {
70 | this.tree.rowCountChanged(0, -this.rowCount);
71 | this.rowCount = this.data.length;
72 | this.tree.rowCountChanged(0, this.rowCount);
73 | }
74 |
75 | this.tree.invalidate();
76 | },
77 |
78 | selectedRow: function() {
79 | var idx = this.selection.currentIndex;
80 | return (idx != -1) ? this.data[idx] : null;
81 | },
82 |
83 | copyColumnToClipboard: function(name) {
84 | var row = this.selectedRow();
85 |
86 | if (row) {
87 | var value = (row[name] || '').toString().trim();
88 | if (!value) { value = '(empty)'; }
89 | copyToClipboard(value);
90 | }
91 | },
92 |
93 | addKey: function() {
94 | protect(function() {
95 | this.inProgress(function() {
96 | var userName = this.user.UserName;
97 | var xhr = this.iamcli.query_or_die('CreateAccessKey', [['UserName', userName]]);
98 |
99 | var accessKey = xhr.xml()..CreateAccessKeyResult.AccessKey;
100 | var accessKeyId = accessKey.AccessKeyId.toString().trim();
101 | var secretAccessKey = accessKey.SecretAccessKey.toString().trim()
102 |
103 | Prefs.addUserAccessKeyId(userName, accessKeyId);
104 | Prefs.addUserSecretAccessKey(userName, secretAccessKey);
105 |
106 | this.refresh();
107 | }.bind(this));
108 | }.bind(this));
109 | },
110 |
111 | deleteKey: function() {
112 | var row = this.selectedRow();
113 | if (!row) { return; }
114 |
115 | var akid = row[0];
116 |
117 | if (!confirm("Are you sure you want to delete '" + akid + "' ?")) {
118 | return;
119 | }
120 |
121 | protect(function() {
122 | this.inProgress(function() {
123 | var userName = this.user.UserName;
124 | var params = [['UserName', userName], ['AccessKeyId', akid]];
125 | this.iamcli.query_or_die('DeleteAccessKey', params);
126 |
127 | Prefs.deleteUserAccessKeyIdAndSecretAccessKey(userName, akid);
128 |
129 | this.refresh();
130 | }.bind(this));
131 | }.bind(this));
132 | }
133 | };
134 |
--------------------------------------------------------------------------------
/Resources/chrome/content/utils.js:
--------------------------------------------------------------------------------
1 | function $(element) {
2 | if (arguments.length > 1) {
3 | for (var i = 0, elements = [], length = arguments.length; i < length; i++) {
4 | elements.push(document.getElementById(arguments[i]));
5 | }
6 |
7 | return elements;
8 | }
9 |
10 | return document.getElementById(element + '');
11 | }
12 |
13 | POLICY_ALLOW_ALL = '{\n "Statement": [\n {\n "Effect":"Allow",\n "Action":"*",\n "Resource":"*"\n }\n ]\n}\n';
14 |
15 | function protect(callback) {
16 | var retval = null;
17 |
18 | try {
19 | retval = callback();
20 | } catch (e) {
21 | if (e.xml) {
22 | openErrorDialog(e);
23 | } else {
24 | alert(e);
25 | }
26 | }
27 |
28 | return retval;
29 | }
30 |
31 | Function.prototype.bind = function(context) {
32 | var slice = Array.prototype.slice;
33 |
34 | function update(array, args) {
35 | var arrayLength = array.length;
36 | var length = args.length;
37 |
38 | while (length--) {
39 | array[arrayLength + length] = args[length];
40 | }
41 |
42 | return array;
43 | }
44 |
45 | function merge(array, args) {
46 | array = slice.call(array, 0);
47 | return update(array, args);
48 | }
49 |
50 | if (arguments.length < 2 && typeof(arguments[0]) === "undefined") {
51 | return this;
52 | }
53 |
54 | var __method = this;
55 | var args = slice.call(arguments, 1);
56 |
57 | return function() {
58 | var a = merge(args, arguments);
59 | return __method.apply(context, a);
60 | };
61 | }
62 |
63 | function openErrorDialog(xhr) {
64 | openDialog('chrome://iamfox/content/error-dialog.xul', 'error-dialog', 'chrome,modal,width=400,height=300,centerscreen',
65 | {error:xhr.xml()..Error});
66 | }
67 |
68 | function openURL(url) {
69 | try {
70 | var io = Components.classes['@mozilla.org/network/io-service;1'].getService(Components.interfaces.nsIIOService);
71 | var uri = io.newURI(url, null, null);
72 | var eps = Components.classes['@mozilla.org/uriloader/external-protocol-service;1'].getService(Components.interfaces.nsIExternalProtocolService);
73 | var launcher = eps.getProtocolHandlerInfo('http');
74 | launcher.preferredAction = Components.interfaces.nsIHandlerInfo.useSystemDefault;
75 | launcher.launchWithURI(uri, null);
76 | } catch (e) {
77 | alert(e);
78 | }
79 | }
80 |
81 | function sortRowsByColumn(column, rows) {
82 | var colkey = column.id.toString().split('.');
83 |
84 | if (colkey.length < 1) {
85 | return false;
86 | }
87 |
88 | colkey = colkey[colkey.length - 1];
89 |
90 | var sortDirection = column.element.getAttribute('sortDirection');
91 |
92 | for (var i = 0; i < column.columns.count; i++) {
93 | column.columns.getColumnAt(i).element.setAttribute('sortDirection', 'natural');
94 | }
95 |
96 | rows.sort(function(a, b) {
97 | a = a[colkey];
98 | b = b[colkey];
99 | return (a < b) ? -1 : (a > b) ? 1 : 0;
100 | });
101 |
102 | if (sortDirection == 'ascending' || sortDirection == 'natural') {
103 | sortDirection = 'descending';
104 | rows.reverse();
105 | } else {
106 | sortDirection = 'ascending';
107 | }
108 |
109 | column.element.setAttribute('sortDirection', sortDirection);
110 |
111 | return true;
112 | }
113 |
114 | Array.prototype.uniq = function() {
115 | var hash = {}
116 |
117 | for (var i = 0; i < this.length; i++) {
118 | var value = this[i];
119 | hash[value] = value;
120 | }
121 |
122 | var array = [];
123 |
124 | for (var i in hash) {
125 | array.push(i);
126 | }
127 |
128 | return array;
129 | };
130 |
131 | function copyToClipboard(text) {
132 | var str = Components.classes['@mozilla.org/supports-string;1'].createInstance(Components.interfaces.nsISupportsString);
133 | var trans = Components.classes['@mozilla.org/widget/transferable;1'].createInstance(Components.interfaces.nsITransferable);
134 | var clip = Components.classes['@mozilla.org/widget/clipboard;1'].getService(Components.interfaces.nsIClipboard);
135 |
136 | if (str && trans && clip) {
137 | str.data = text;
138 | trans.addDataFlavor('text/unicode');
139 | trans.setTransferData('text/unicode', str, text.length * 2);
140 | clip.setData(trans, null, Components.interfaces.nsIClipboard.kGlobalClipboard);
141 | }
142 | }
143 |
--------------------------------------------------------------------------------
/Resources/chrome/icons/default/main-window.ico:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/cookpad/iam-fox/675f751976bab0db79766bd03a76218c20122c8c/Resources/chrome/icons/default/main-window.ico
--------------------------------------------------------------------------------
/Resources/chrome/install.rdf:
--------------------------------------------------------------------------------
1 |
2 |
4 |
5 | {2c1ab000-5cd9-11e0-80e3-0800200c9a66}
6 | 2
7 | IAM Fox
8 | 0.1.6
9 | IAM Fox is a GUI client of AWS Identity and Access Management (IAM)
10 | SUGAWARA Genki
11 |
12 |
13 | {ec8030f7-c20a-464f-9b0e-13a3a9e97384}
14 | 3.6
15 | 4.0.*
16 |
17 |
18 |
19 |
20 |
--------------------------------------------------------------------------------
/Resources/chrome/locale/en-US/iamfox.dtd:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/cookpad/iam-fox/675f751976bab0db79766bd03a76218c20122c8c/Resources/chrome/locale/en-US/iamfox.dtd
--------------------------------------------------------------------------------
/Resources/chrome/skin/classic/iamfox.css:
--------------------------------------------------------------------------------
1 | button.mini-button {
2 | min-width: 60px;
3 | }
4 |
5 | #menu_iamfox {
6 | list-style-image: url('menuicon.png');
7 | }
8 |
9 | treechildren::-moz-tree-checkbox(checked) {
10 | list-style-image: url(chrome://global/skin/checkbox/cbox-check.gif);
11 | }
12 |
13 | treechildren::-moz-tree-checkbox(checked, DISABLED){
14 | list-style-image: url(chrome://global/skin/checkbox/cbox-check-dis.gif);
15 | }
--------------------------------------------------------------------------------
/Resources/chrome/skin/classic/menuicon.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/cookpad/iam-fox/675f751976bab0db79766bd03a76218c20122c8c/Resources/chrome/skin/classic/menuicon.png
--------------------------------------------------------------------------------
/Resources/defaults/preferences/prefs.js:
--------------------------------------------------------------------------------
1 | pref("toolkit.defaultChromeURI", "chrome://iamfox/content/main.xul");
2 | pref("toolkit.defaultChromeFeatures", "chrome,centerscreen,width=800,height=600,resizable");
3 | /*
4 | pref("browser.dom.window.dump.enabled", true);
5 | pref("javascript.options.showInConsole", true);
6 | pref("javascript.options.strict", true);
7 | pref("nglayout.debug.disable_xul_cache", true);
8 | pref("nglayout.debug.disable_xul_fastload", true);
9 | */
10 |
--------------------------------------------------------------------------------
/iam-fox.ci:
--------------------------------------------------------------------------------
1 | <*project
2 | version = 4 civer = "Free v4.14.5" winver = "2.8/6.1.7600" >
3 |