├── .gitignore
├── LICENSE
├── README.md
└── src
├── angularjs-nodejs
├── README.md
├── client.js
├── custom.css
├── index.html
└── package.json
└── s3-no-server
├── README.md
├── amazon-auth.js
├── aws-sdk-glue.js
├── custom.css
├── facebook-auth.js
├── fineuploader-glue.js
├── google-auth.js
├── index.html
├── loading.gif
├── not_available-generic.png
├── processing.gif
└── waiting-generic.png
/.gitignore:
--------------------------------------------------------------------------------
1 | .idea/*
2 | *.iml
3 | node_modules/
4 | *custom.fineuploader*
5 | assets/
6 |
--------------------------------------------------------------------------------
/LICENSE:
--------------------------------------------------------------------------------
1 | The MIT License (MIT)
2 |
3 | Copyright (c) 2013-present, Widen Enterprises, Inc.
4 |
5 | Permission is hereby granted, free of charge, to any person obtaining a copy
6 | of this software and associated documentation files (the "Software"), to deal
7 | in the Software without restriction, including without limitation the rights
8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9 | copies of the Software, and to permit persons to whom the Software is
10 | furnished to do so, subject to the following conditions:
11 |
12 | The above copyright notice and this permission notice shall be included in all
13 | copies or substantial portions of the Software.
14 |
15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21 | SOFTWARE.
22 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | Fine Uploader Integration Examples
2 | ======================
3 | [](LICENSE)
4 |
5 | Using [Fine Uploader][1] to solve real problems.
6 |
7 |
8 | Here are the examples covered in this repo:
9 | * [An AngularJS Directive using Fine Uploader UI and node.js][2]
10 | * [Uploading to S3 without a server][3]
11 |
12 | [1]: http://fineuploader.com
13 | [2]: src/angularjs-nodejs
14 | [3]: src/s3-no-server
15 |
--------------------------------------------------------------------------------
/src/angularjs-nodejs/README.md:
--------------------------------------------------------------------------------
1 | # Fine Uploader UI: AngularJS and node.js Integration
2 |
3 |
4 | Please read the [blog post that covers this example][1] in detail.
5 |
6 | [1]: https://blog.fineuploader.com/full-stack-javascript-image-uploader-using-angularjs-node-js-6e2fca020073
7 |
--------------------------------------------------------------------------------
/src/angularjs-nodejs/client.js:
--------------------------------------------------------------------------------
1 | /**
2 | * AngularJS directive for Fine Uploader UI jQuery (traditional endpoints).
3 | * Maintained by Widen Enterprises.
4 | *
5 | * This example:
6 | * - Delegates error messages to the dialog element.
7 | * - Generates client-side pre-upload image previews (where supported).
8 | * - Allows files to be excluded based on extension and MIME type (where supported).
9 | * - Determines the most appropriate upload button and drop zone text based on browser capabilities.
10 | * - Renders larger image preview on-demand in a dialog element.
11 | * - Keeps an aggregate progress bar up-to-date based on upload status for all files.
12 | * - Enables delete file support.
13 | * - Ensure newly submitted files are added to the top of the visible list.
14 | * - Enables chunking & auto-resume support.
15 | *
16 | * Requirements:
17 | * - Fine Uploader 5.4 or 5.5
18 | * - Dialog element polyfill 0.4.2
19 | * - AngularJS 1.5
20 | */
21 |
22 | (function() {
23 | function isTouchDevice() {
24 | return "ontouchstart" in window || navigator.msMaxTouchPoints > 0;
25 | }
26 |
27 | function initButtonText($scope) {
28 | var input = document.createElement("input");
29 |
30 | input.setAttribute("multiple", "true");
31 |
32 | if (input.multiple === true && !qq.android()) {
33 | $scope.uploadButtonText = "Select Files";
34 | }
35 | else {
36 | $scope.uploadButtonText = "Select a File";
37 | }
38 | }
39 |
40 | function initDropZoneText($scope, $interpolate) {
41 | if (qq.supportedFeatures.folderDrop && !isTouchDevice()) {
42 | $scope.dropZoneText = "Drop Files or Folders Here";
43 | }
44 | else if (qq.supportedFeatures.fileDrop && !isTouchDevice()) {
45 | $scope.dropZoneText = "Drop Files Here";
46 | }
47 | else {
48 | $scope.dropZoneText = $scope.$eval($interpolate("Press '{{uploadButtonText}}'"));
49 | }
50 | }
51 |
52 | function bindToRenderedTemplate($compile, $scope, $interpolate, element) {
53 | $compile(element.contents())($scope);
54 |
55 | initButtonText($scope);
56 | initDropZoneText($scope, $interpolate);
57 | }
58 |
59 | function openLargerPreview($scope, uploader, modal, size, fileId) {
60 | uploader.drawThumbnail(fileId, new Image(), size).then(function(image) {
61 | $scope.largePreviewUri = image.src;
62 | $scope.$apply();
63 | modal.showModal();
64 | });
65 | }
66 |
67 | function closePreview(modal) {
68 | modal.close();
69 | }
70 |
71 | angular.module("fineUploaderDirective", [])
72 | .directive("fineUploader", function($compile, $interpolate) {
73 | return {
74 | restrict: "A",
75 | replace: true,
76 |
77 | link: function($scope, element, attrs) {
78 | var endpoint = attrs.uploadServer,
79 | notAvailablePlaceholderPath = attrs.notAvailablePlaceholder,
80 | waitingPlaceholderPath = attrs.waitingPlaceholder,
81 | acceptFiles = attrs.allowedMimes,
82 | sizeLimit = attrs.maxFileSize,
83 | largePreviewSize = parseInt(attrs.largePreviewSize),
84 | allowedExtensions = JSON.parse(attrs.allowedExtensions),
85 | previewDialog = document.querySelector('.large-preview'),
86 |
87 | uploader = new qq.FineUploader({
88 | debug: true,
89 | element: element[0],
90 | request: {endpoint: endpoint},
91 |
92 | validation: {
93 | acceptFiles: acceptFiles,
94 | allowedExtensions: allowedExtensions,
95 | sizeLimit: sizeLimit
96 | },
97 |
98 | deleteFile: {
99 | endpoint: endpoint,
100 | enabled: true
101 | },
102 |
103 | thumbnails: {
104 | placeholders: {
105 | notAvailablePath: notAvailablePlaceholderPath,
106 | waitingPath: waitingPlaceholderPath
107 | }
108 | },
109 |
110 | display: {
111 | prependFiles: true
112 | },
113 |
114 | failedUploadTextDisplay: {
115 | mode: "custom"
116 | },
117 |
118 | retry: {
119 | enableAuto: true
120 | },
121 |
122 | chunking: {
123 | enabled: true
124 | },
125 |
126 | resume: {
127 | enabled: true
128 | },
129 |
130 | callbacks: {
131 | onSubmitted: function(id, name) {
132 | var fileEl = this.getItemByFileId(id),
133 | thumbnailEl = fileEl.querySelector('.thumbnail-button');
134 |
135 | thumbnailEl.addEventListener('click', function() {
136 | openLargerPreview($scope, uploader, previewDialog, largePreviewSize, id);
137 | });
138 | }
139 | }
140 | });
141 |
142 | dialogPolyfill.registerDialog(previewDialog);
143 | $scope.closePreview = closePreview.bind(this, previewDialog);
144 | bindToRenderedTemplate($compile, $scope, $interpolate, element);
145 | }
146 | }
147 | });
148 | })();
149 |
--------------------------------------------------------------------------------
/src/angularjs-nodejs/custom.css:
--------------------------------------------------------------------------------
1 | .thumbnail-button {
2 | border: none;
3 | background-color: transparent;
4 | padding: 0;
5 | }
6 |
7 | .large-preview {
8 | width: inherit;
9 | right: inherit;
10 | height: inherit;
11 | margin: inherit;
12 | position: fixed;
13 | top: 50%;
14 | left: 50%;
15 | transform: translate(-50%, -50%);
16 | }
17 |
18 | .large-preview button {
19 | position: absolute;
20 | top: 0;
21 | right: 0;
22 | }
--------------------------------------------------------------------------------
/src/angularjs-nodejs/index.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
24 |
25 |
26 |
27 | Fine Uploader AngularJS Integration Example
28 |
29 |
30 |
108 |
109 |
110 |
111 |
112 | X
113 |
114 |
115 |
116 |
124 |
125 |
126 |
127 |
128 |
129 |
130 |
131 |
132 |
133 |
134 |
135 |
--------------------------------------------------------------------------------
/src/angularjs-nodejs/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name" : "fineUploaderAngularExample",
3 | "description" : "Fine Uploader Angular & NodeJS example",
4 | "dependencies" : {
5 | "angular": "1.4.x",
6 | "dialog-polyfill": "0.4.2",
7 | "fine-uploader": "~5.x.x",
8 | "fine-uploader-traditional-server": "3.0.2"
9 | },
10 | "engines": {
11 | "node" : ">=5.0.0"
12 | },
13 | "version" : "1.0.0",
14 | "scripts": {
15 | "server": "PUBLIC_DIR=$(pwd) NODE_MODULES_DIR=$(pwd)/node_modules/ UPLOADED_FILES_DIR=$(pwd)/uploads/ node node_modules/fine-uploader-traditional-server/nodejs"
16 | }
17 | }
18 |
--------------------------------------------------------------------------------
/src/s3-no-server/README.md:
--------------------------------------------------------------------------------
1 | # Fine Uploader S3: Uploading file to S3 without writing any server-side code
2 |
3 | ### All you need is a simple HTTP server to host the HTML/javascript files.
4 |
5 | There is a live demo using this code at https://fineuploader-s3-client-demo.s3.amazonaws.com/index.html.
6 |
7 | Please read the [blog post that covers this example][1] in detail.
8 |
9 | You can also read more on Fine Uploader's client-side signing feature (new as of 4.2) on the [associated feature's
10 | documentation page][2].
11 |
12 | [1]: https://blog.fineuploader.com/uploads-without-any-server-code-3d7219167591
13 | [2]: http://docs.fineuploader.com/features/no-server-uploads.html
14 |
--------------------------------------------------------------------------------
/src/s3-no-server/amazon-auth.js:
--------------------------------------------------------------------------------
1 | /**
2 | * Handles the Amazon login workflow.
3 | */
4 | $(function() {
5 | // Called when the SDK is loaded & ready
6 | var onAmazonLoginReady = function() {
7 | amazon.Login.setClientId("amzn1.application-oa2-client.86174d2cae1d4fe9950b7f31f4d1e3aa");
8 | },
9 |
10 | sdkScriptEl = document.createElement('script');
11 |
12 | // Prepare the script tag used to load the SDK
13 | sdkScriptEl.type = "text/javascript";
14 | sdkScriptEl.async = true;
15 | sdkScriptEl.id = "amazon-login-sdk";
16 | sdkScriptEl.src = "https://api-cdn.amazon.com/sdk/login1.js";
17 | document.getElementById("amazon-root").appendChild(sdkScriptEl);
18 |
19 | // Called when the login button is clicked
20 | document.getElementById("amazon-signin").onclick = function() {
21 | // Only allow access to profile, and always require re-auth
22 | var options = {
23 | scope : "profile",
24 | interactive: "always"
25 | };
26 |
27 | // Attempt to authorize the user (results in pop-up)
28 | amazon.Login.authorize(options)
29 | // Called when the auth attempt has completed
30 | .onComplete(function(authResult) {
31 | // If authorized...
32 | if (authResult.status === "complete") {
33 | var expiresInMs = parseInt(authResult.expires_in) * 1000;
34 |
35 | $(document).trigger("tokenReceived.s3Demo");
36 |
37 | // Get the authenticated user's name (for file storage)
38 | amazon.Login.retrieveProfile(function(response) {
39 | s3DemoGlobals.userName = response.profile.Name;
40 | });
41 |
42 | // Grab S3 credentials using the bearer token
43 | s3DemoGlobals.assumeRoleWithWebIdentity({
44 | idToken: authResult.access_token,
45 | roleArn: "arn:aws:iam::776099607611:role/demo-s3-noserver-amazon",
46 | providerId: "www.amazon.com"
47 | });
48 |
49 | // Make the user re-auth just before the token expires.
50 | setTimeout(function() {
51 | alert("Token expired. You must sign in again.");
52 | $(document).trigger("tokenExpired.s3Demo");
53 | }, expiresInMs - 10000)
54 | }
55 | });
56 | return false;
57 | };
58 |
59 | window.onAmazonLoginReady = onAmazonLoginReady;
60 |
61 | // Show the login button if there is no usable token
62 | $(document).on("tokenExpired.s3Demo", function() {
63 | $("#amazon-signin").show();
64 | });
65 |
66 | // Hide the login button if a usable token exists
67 | $(document).on("tokenReceived.s3Demo", function() {
68 | $("#amazon-signin").hide();
69 | });
70 |
71 | });
72 |
--------------------------------------------------------------------------------
/src/s3-no-server/aws-sdk-glue.js:
--------------------------------------------------------------------------------
1 | /**
2 | * Grabs AWS credentials for an authenticated user.
3 | */
4 | $(function() {
5 | var assumeRoleWithWebIdentity = function(params) {
6 | var sts = new AWS.STS(),
7 | assumeRoleParams = {};
8 |
9 | s3DemoGlobals.roleArn = params.roleArn || s3DemoGlobals.roleArn;
10 | s3DemoGlobals.providerId = params.providerId || s3DemoGlobals.providerId;
11 | s3DemoGlobals.idToken = params.idToken || s3DemoGlobals.idToken;
12 |
13 | assumeRoleParams = {
14 | RoleArn: s3DemoGlobals.roleArn,
15 | RoleSessionName: "web-identity-federation",
16 | WebIdentityToken: s3DemoGlobals.idToken
17 | };
18 |
19 | if (s3DemoGlobals.providerId) {
20 | assumeRoleParams.ProviderId = s3DemoGlobals.providerId;
21 | }
22 |
23 | sts.assumeRoleWithWebIdentity(assumeRoleParams, params.callback || s3DemoGlobals.updateCredentials);
24 | },
25 | getFuCredentials = function(data) {
26 | return {
27 | accessKey: data.Credentials.AccessKeyId,
28 | secretKey: data.Credentials.SecretAccessKey,
29 | sessionToken: data.Credentials.SessionToken,
30 | expiration: data.Credentials.Expiration
31 | };
32 | };
33 |
34 | s3DemoGlobals.assumeRoleWithWebIdentity = assumeRoleWithWebIdentity;
35 | s3DemoGlobals.getFuCredentials = getFuCredentials;
36 | }());
37 |
--------------------------------------------------------------------------------
/src/s3-no-server/custom.css:
--------------------------------------------------------------------------------
1 | /*
2 |
3 | CSS for Fine Uploader UI. Depends on a matching HTML file.
4 | Maintained by Widen Enterprises.
5 |
6 | See the HTML file comments for more details.
7 |
8 | */
9 |
10 | .demo-title
11 | {
12 | text-align: center;
13 | font-weight: 200;
14 | margin-top: 0px;
15 | margin-bottom: 40px;
16 | color: #00abc7;
17 | font-size: 36px;
18 | }
19 |
20 | .uploader-drop-zone
21 | {
22 | /* Static height drop zone that also contains the file list, with a border */
23 | height: 300px;
24 | border: solid 1px black;
25 | -webkit-border-radius: 8px;
26 | -moz-border-radius: 8px;
27 | border-radius: 8px;
28 | text-align: center;
29 |
30 | /* Make the drop zone scollable */
31 | overflow-y: scroll;
32 | }
33 |
34 | LI.file-container
35 | {
36 | /* Make sure the drop zone text is always at least a little visible */
37 | opacity: .6;
38 |
39 | /* Rounded file container corners */
40 | -webkit-border-radius: 8px;
41 | -moz-border-radius: 8px;
42 | border-radius: 8px;
43 |
44 | margin: 10px;
45 |
46 | /* Used to un-center the text for each file item,
47 | otherwise the .uploader-drop-zone text-align style will apply */
48 | text-align: left;
49 | }
50 |
51 | .qq-uploader
52 | {
53 | margin: 20px 0;
54 | width: auto;
55 | }
56 |
57 | .qq-upload-button
58 | {
59 | margin-bottom: 10px;
60 |
61 | /* Rounded upload button corners */
62 | -webkit-border-radius: 4px;
63 | -moz-border-radius: 4px;
64 | border-radius: 4px;
65 | }
66 |
67 | .drop-zone-text
68 | {
69 | /* Vertically & horizontally center the dynamically generated drop zone message
70 | inside the drop zone & make it a bit presentable */
71 | position: absolute;
72 | vertical-align: middle;
73 | line-height: 300px;
74 | font-size: 200%;
75 | width: 100%;
76 | left: 0;
77 | color: #cccccc;
78 | }
79 |
80 | .file-info
81 | {
82 | display: inline-block;
83 | width: 400px;
84 | }
85 |
86 | IMG
87 | {
88 | vertical-align: middle;
89 | }
90 |
91 | .signin-button
92 | {
93 | margin-bottom: 20px;
94 | display:block;
95 | }
96 |
97 | body
98 | {
99 | background-color: #FEFEFC;
100 | font-family: 'Maven Pro', sans-serif;
101 | padding: 40px 0;
102 | }
103 |
104 | a
105 | {
106 | color: #0088CC;
107 | text-decoration: none;
108 | font-size: 14px;
109 | }
110 |
111 | a:hover
112 | {
113 | text-decoration: underline;
114 | }
115 |
116 | p
117 | {
118 | font-size: 14px;
119 | }
120 |
121 | h2
122 | {
123 | font-weight: 200;
124 | margin-bottom: 5px;
125 | color: #00abc7;
126 | font-size: 36px;
127 | }
128 |
129 | h3
130 | {
131 | font-weight:300;
132 | font-size: 24px;
133 | line-height: 28px;
134 | color: #00abc7;
135 | }
136 |
137 | h4
138 | {
139 | color: #e65c47;
140 | font-weight: 300;
141 | }
142 |
143 | .wrapper
144 | {
145 | width: 80%;
146 | max-width: 1024px;
147 | margin: 0 auto;
148 | }
149 |
150 | .sign-in-buttons
151 | {
152 | text-align: center;
153 | }
154 |
155 | .hero-unit
156 | {
157 | margin-top:30px;
158 | padding: 20px 40px;
159 | line-height: 18px;
160 | }
161 |
162 |
163 |
164 | .footer
165 | {
166 | padding: 70px 0;
167 | border-top: 1px solid #e5e5e5;
168 | background-color: #525252;
169 | color :#eee;
170 | position: relative;
171 | left: 0;
172 | bottom: 0;
173 | height: 120px;
174 | width: 100%;
175 | margin-top: 60px;
176 | }
177 | .footer p
178 | {
179 | margin-bottom: 0;
180 | color: #eee;
181 | }
182 | .footer-links
183 | {
184 | margin: 10px 0;
185 | }
186 | .footer-links li
187 | {
188 | display: inline;
189 | margin-right: 10px;
190 | }
191 | .footer a
192 | {
193 | color: #66ccdd;
194 | }
195 | .widenIcon
196 | {
197 | margin: -3px 0px 0px 4px;
198 | }
--------------------------------------------------------------------------------
/src/s3-no-server/facebook-auth.js:
--------------------------------------------------------------------------------
1 | /**
2 | * Handles the Facebook login workflow.
3 | */
4 | $(function() {
5 | var scriptId = "facebook-jssdk",
6 | refScript = document.getElementsByTagName("script")[0],
7 | autoLogout = true,
8 | sdkScript;
9 |
10 | // Sets up the script tag used to load the SDK
11 | if (!document.getElementById(scriptId)) {
12 | sdkScript = document.createElement("script");
13 | sdkScript.id = scriptId;
14 | sdkScript.async = true;
15 | sdkScript.src = "//connect.facebook.net/en_US/all.js";
16 |
17 | refScript.parentNode.insertBefore(sdkScript, refScript);
18 | }
19 |
20 | // Called when the SDK is loaded and ready
21 | window.fbAsyncInit = function() {
22 | // Initialize the login workflow
23 | FB.init({
24 | appId : "494966370620626",
25 | status : true,
26 | cookie : false,
27 | xfbml : false
28 | });
29 |
30 | // Called when the login button is clicked
31 | $("#facebook-signin").click(function() {
32 | // Ensure we don't de-auth the user if they click on the login button
33 | autoLogout = false;
34 | FB.login();
35 | });
36 |
37 | // Called when auth attempt has completed
38 | FB.Event.subscribe('auth.authResponseChange', function(response) {
39 | // Successfully authenticated
40 | if (response.status === 'connected') {
41 | // Force FB to delete auth credentials for the user on page load.
42 | // This ensure the user has to re-authenticate on page load. Probably only useful for this demo.
43 | if (autoLogout) {
44 | FB.api("/me/permissions", "DELETE");
45 | }
46 | else {
47 | (function() {
48 | var expiresInMs = parseInt(response.authResponse.expiresIn) * 1000;
49 | $(document).trigger("tokenReceived.s3Demo");
50 |
51 | // Grab the authenticated user's name via the Graph API (for file storage)
52 | FB.api("/me", function(response) {
53 | s3DemoGlobals.userName = response.name;
54 | });
55 |
56 | // Grab S3 credentials for the user
57 | s3DemoGlobals.assumeRoleWithWebIdentity({
58 | idToken: response.authResponse.accessToken,
59 | roleArn: "arn:aws:iam::776099607611:role/demo-s3-noserver-facebook",
60 | providerId: "graph.facebook.com"
61 | });
62 |
63 | // Ensure the user is asked to re-auth just before the token expires
64 | setTimeout(function() {
65 | alert("Token expired. You must sign in again.");
66 | $(document).trigger("tokenExpired.s3Demo");
67 | }, expiresInMs - 10000)
68 | }());
69 | }
70 | }
71 | else {
72 | $(document).trigger("tokenExpired.s3Demo");
73 | }
74 | });
75 | };
76 |
77 | // Show the login button if we don't have a valid token to use
78 | $(document).on("tokenExpired.s3Demo", function() {
79 | $("#facebook-signin").show();
80 | });
81 |
82 | // Hide the login button if we do have a valid token to use
83 | $(document).on("tokenReceived.s3Demo", function() {
84 | $("#facebook-signin").hide();
85 | });
86 | });
87 |
--------------------------------------------------------------------------------
/src/s3-no-server/fineuploader-glue.js:
--------------------------------------------------------------------------------
1 | /**
2 | * Sets up a Fine Uploader S3 jQuery UI instance, ensures files are saved under a "directory" in the bucket
3 | * bearing the logged-in user's name, provides a link to view the uploaded file after it has reached the bucket
4 | * and asks AWS for new credentials before those expire.
5 | */
6 | $(function() {
7 | var bucketUrl = "https://fineuploader-s3-client-demo-uploads.s3.amazonaws.com",
8 | updateCredentials = function(error, data) {
9 | if (!error) {
10 | $('#uploader').fineUploaderS3("setCredentials", s3DemoGlobals.getFuCredentials(data));
11 | }
12 | },
13 | hideUploader = function() {
14 | $("#uploader").hide();
15 | };
16 |
17 | $("#uploader").fineUploaderS3({
18 | request: {
19 | endpoint: bucketUrl
20 | },
21 | objectProperties: {
22 | // Since we want all items to be publicly accessible w/out a server to return a signed URL
23 | acl: "public-read",
24 |
25 | // The key for each file will follow this format: {USER_NAME}/{UUID}.{FILE_EXTENSION}
26 | key: function(id) {
27 | var filename = this.getName(id),
28 | uuid = this.getUuid(id);
29 |
30 | return qq.format("{}/{}.{}", s3DemoGlobals.userName, uuid, qq.getExtension(filename));
31 | }
32 | },
33 | chunking: {
34 | enabled: true
35 | },
36 | resume: {
37 | enabled: true
38 | },
39 | // Restrict files to 15 MB and 5 net files per session
40 | validation: {
41 | itemLimit: 5,
42 | sizeLimit: 15000000
43 | },
44 | thumbnails: {
45 | placeholders: {
46 | notAvailablePath: "not_available-generic.png",
47 | waitingPath: "waiting-generic.png"
48 | }
49 | }
50 | })
51 | .on('complete', function(event, id, name, response, xhr) {
52 | var $fileEl = $(this).fineUploaderS3("getItemByFileId", id),
53 | $viewBtn = $fileEl.find(".view-btn"),
54 | key = $(this).fineUploaderS3("getKey", id);
55 |
56 | // Add a "view" button to access the uploaded file in S3 if the upload is successful
57 | if (response.success) {
58 | $viewBtn.show();
59 | $viewBtn.attr("href", bucketUrl + "/" + key);
60 | }
61 | })
62 | .on("credentialsExpired", function() {
63 | var promise = new qq.Promise();
64 |
65 | // Grab new credentials
66 | s3DemoGlobals.assumeRoleWithWebIdentity({
67 | callback: function(error, data) {
68 | if (error) {
69 | promise.failure("Failed to assume role");
70 | }
71 | else {
72 | promise.success(s3DemoGlobals.getFuCredentials(data));
73 | }
74 | }
75 | });
76 |
77 | return promise;
78 | });
79 |
80 | s3DemoGlobals.updateCredentials = updateCredentials;
81 |
82 | $(document).on("tokenExpired.s3Demo", hideUploader);
83 | $(document).on("tokenReceived.s3Demo", function() {
84 | $("#uploader").show();
85 | });
86 | $(document).trigger("tokenExpired.s3Demo");
87 | });
88 |
--------------------------------------------------------------------------------
/src/s3-no-server/google-auth.js:
--------------------------------------------------------------------------------
1 | /**
2 | * Handles the Google login workflow.
3 | */
4 | $(function() {
5 | var plusOnScriptEl = document.createElement('script'),
6 | referenceScriptEl = document.getElementsByTagName('script')[0],
7 |
8 | // Called when the auth attempt has completed
9 | s3GoogleOauthHandler = function(authResult) {
10 | // If authenticated...
11 | if (authResult.status.signed_in) {
12 | var expiresInMs = parseInt(authResult.expires_in) * 1000;
13 |
14 | $(document).trigger("tokenReceived.s3Demo");
15 |
16 | setUserName(authResult.access_token);
17 |
18 | // Get S3 credentials
19 | s3DemoGlobals.assumeRoleWithWebIdentity({
20 | roleArn: "arn:aws:iam::776099607611:role/demo-s3-noserver-google",
21 | idToken: authResult.id_token
22 | });
23 |
24 | // Ensure the user is asked to re-auth before the token expires
25 | setTimeout(function() {
26 | alert("Token expired. You must sign in again.");
27 | $(document).trigger("tokenExpired.s3Demo");
28 | }, expiresInMs - 10000)
29 | }
30 | else {
31 | $(document).trigger("tokenExpired.s3Demo");
32 | }
33 | },
34 |
35 | showButton = function() {
36 | $("#google-signin").show();
37 | },
38 |
39 | // Grabs the authenticated user's name (for file storage)
40 | setUserName = function(accessToken) {
41 | var xhr = new XMLHttpRequest();
42 |
43 | xhr.onload = function() {
44 | if (xhr.status === 200) {
45 | var userName = JSON.parse(xhr.responseText).displayName;
46 |
47 | s3DemoGlobals.userName = userName;
48 | }
49 | };
50 |
51 | xhr.open("GET", "https://www.googleapis.com/plus/v1/people/me?access_token=" + accessToken);
52 | xhr.send();
53 | };
54 |
55 | window.s3GoogleOauthHandler = s3GoogleOauthHandler;
56 |
57 | // Setup the script tag used to load the SDK
58 | plusOnScriptEl.type = "text/javascript";
59 | plusOnScriptEl.async = true;
60 | plusOnScriptEl.src = "https://plus.google.com/js/client:plusone.js";
61 | referenceScriptEl.parentNode.insertBefore(plusOnScriptEl, referenceScriptEl);
62 |
63 | $(document).on("tokenExpired.s3Demo", showButton);
64 | $(document).on("tokenReceived.s3Demo", function() {
65 | $("#google-signin").hide();
66 | });
67 |
68 | });
69 |
--------------------------------------------------------------------------------
/src/s3-no-server/index.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
29 |
30 | S3 server-less example
31 |
32 |
33 |
34 |
35 |
36 |
37 |
70 |
71 |
74 |
75 |
76 |
77 |
78 |
79 |
80 |
81 |
82 |
83 |
84 |
85 |
86 |
Upload files to Amazon S3 - No server-side code required
87 |
88 |
89 |
90 |
91 |
92 |
93 |
94 |
95 |
96 |
97 |
98 |
99 |
100 |
101 |
102 |
103 |
104 |
105 |
106 |
Don't want to write ANY server-side code at all?
107 |
Leave EVERYTHING up to the browser and S3.
108 |
109 |
Fine Uploader can handle the S3 request signing for you. Just provide temporary credentials for
110 | your locked-down IAM user and pass them off to Fine Uploader S3. You can do this all client-side,
111 | easily and securely, using Google, Facebook, or Amazon as an identity provider, and the AWS JavaScript SDK.
112 | Need more details? Read the blog post that covers step-by-step setup for this workflow.
113 |
114 |
This demo uses only client-side code to authenticate and upload files to S3. We have not written
115 | any server-side code at all. In fact, the entire example is hosted in an S3 bucket. Try it out
116 | by choosing one of the identity providers to the right.
117 |
118 |
119 |
120 |
121 |
151 |
152 |
153 |
154 |
155 |
156 |
157 |
Additional links:
158 |
159 |
160 |
165 |
166 |
167 |
Note: If you simply want to avoid the signature HTTP requests for each file/chunk, and need
168 | to support legacy browsers, you can do that too, but some server-side code will be required
169 | to utilize the AWS temporary credentials calls. See the client-side signing feature page
170 | in the documentation for more details.
171 |
172 |
173 |
174 |
177 |
178 |
179 |
209 |
210 |