From 18eea01c29e086bd5eda41eca85b9428b8ff95dd Mon Sep 17 00:00:00 2001 From: Alan Rynne Date: Thu, 26 Aug 2021 16:27:53 +0200 Subject: [PATCH] feat(embed): Wrapped all localStorage access with try/catch statements --- packages/frontend/src/components/Renderer.vue | 10 +++- packages/objectloader/index.js | 55 ++++++++++--------- .../viewer/src/modules/ViewerObjectLoader.js | 9 ++- 3 files changed, 45 insertions(+), 29 deletions(-) diff --git a/packages/frontend/src/components/Renderer.vue b/packages/frontend/src/components/Renderer.vue index e11970875..8eb60be5e 100644 --- a/packages/frontend/src/components/Renderer.vue +++ b/packages/frontend/src/components/Renderer.vue @@ -348,9 +348,15 @@ export default { async getPreviewImage(angle) { angle = angle || 0 let previewUrl = this.objectUrl.replace('streams', 'preview') + '/' + angle + let token = undefined + try { + token = localStorage.getItem('AuthToken') + }catch (e) { + console.warn("Sanboxed mode, only public streams will fetch properly.") + } const res = await fetch(previewUrl, { - headers: localStorage.getItem('AuthToken') - ? { Authorization: `Bearer ${localStorage.getItem('AuthToken')}` } + headers: token + ? { Authorization: `Bearer ${token}` } : {} }) const blob = await res.blob() diff --git a/packages/objectloader/index.js b/packages/objectloader/index.js index 0a7e7eebd..756738a8a 100644 --- a/packages/objectloader/index.js +++ b/packages/objectloader/index.js @@ -1,5 +1,5 @@ /** - * Simple client that streams object info from a Speckle Server. + * Simple client that streams object info from a Speckle Server. * TODO: Object construction progress reporting is weird. */ @@ -9,7 +9,7 @@ export default class ObjectLoader { /** * Creates a new object loader instance. - * @param {*} param0 + * @param {*} param0 */ constructor( { serverUrl, streamId, token, objectId, options = { fullyTraverseArrays: false, excludeProps: [ ] } } ) { this.INTERVAL_MS = 20 @@ -18,13 +18,18 @@ export default class ObjectLoader { this.serverUrl = serverUrl || window.location.origin this.streamId = streamId this.objectId = objectId - this.token = token || localStorage.getItem( 'AuthToken' ) + console.log('Object loader constructor called!!!') + try { + this.token = token || localStorage.getItem( 'AuthToken' ) + } catch (error) { + // Accessing localStorage may throw when executing on sandboxed document, ignore. + } this.headers = { 'Accept': 'text/plain' } - if( token ) { + if( this.token ) { this.headers['Authorization'] = `Bearer ${this.token}` } @@ -45,25 +50,25 @@ export default class ObjectLoader { /** * Use this method to receive and construct the object. It will return the full, de-referenced and de-chunked original object. - * @param {*} onProgress - * @returns + * @param {*} onProgress + * @returns */ async getAndConstructObject( onProgress ) { - + ;( await this.downloadObjectsInBuffer( onProgress ) ) // Fire and forget; PS: semicolon of doom - + let rootObject = await this.getObject( this.objectId ) return this.traverseAndConstruct( rootObject, onProgress ) } /** * Internal function used to download all the objects in a local buffer. - * @param {*} onProgress + * @param {*} onProgress */ async downloadObjectsInBuffer( onProgress ) { let first = true let downloadNum = 0 - + for await ( let obj of this.getObjectIterator() ) { if( first ) { this.totalChildrenCount = obj.totalChildrenCount @@ -78,9 +83,9 @@ export default class ObjectLoader { /** * Internal function used to recursively traverse an object and populate its references and dechunk any arrays. - * @param {*} obj - * @param {*} onProgress - * @returns + * @param {*} obj + * @param {*} onProgress + * @returns */ async traverseAndConstruct( obj, onProgress ) { if( !obj ) return @@ -91,20 +96,20 @@ export default class ObjectLoader { let arr = [] for ( let element of obj ) { if ( typeof element !== 'object' && ! this.options.fullyTraverseArrays ) return obj - + // Dereference element if needed let deRef = element.referencedId ? await this.getObject( element.referencedId ) : element - if( element.referencedId && onProgress ) onProgress( { stage: 'construction', current: ++this.traversedReferencesCount > this.totalChildrenCount ? this.totalChildrenCount : this.traversedReferencesCount, total: this.totalChildrenCount } ) - + if( element.referencedId && onProgress ) onProgress( { stage: 'construction', current: ++this.traversedReferencesCount > this.totalChildrenCount ? this.totalChildrenCount : this.traversedReferencesCount, total: this.totalChildrenCount } ) + // Push the traversed object in the array arr.push( await this.traverseAndConstruct( deRef, onProgress ) ) } - + // De-chunk - if( arr[0]?.speckle_type?.toLowerCase().includes('datachunk') ) { + if( arr[0]?.speckle_type?.toLowerCase().includes('datachunk') ) { return arr.reduce( ( prev, curr ) => prev.concat( curr.data ), [] ) } - + return arr } @@ -113,11 +118,11 @@ export default class ObjectLoader { for( let ignoredProp of this.options.excludeProps ) { delete obj[ ignoredProp ] } - + // 2) Iterate through obj - for( let prop in obj ) { + for( let prop in obj ) { if( typeof obj[prop] !== 'object' ) continue // leave alone primitive props - + if( obj[prop].referencedId ) { obj[prop] = await this.getObject( obj[prop].referencedId ) if( onProgress ) onProgress( { stage: 'construction', current: ++this.traversedReferencesCount > this.totalChildrenCount ? this.totalChildrenCount : this.traversedReferencesCount, total: this.totalChildrenCount } ) @@ -131,8 +136,8 @@ export default class ObjectLoader { /** * Internal function. Returns a promise that is resolved when the object id is loaded into the internal buffer. - * @param {*} id - * @returns + * @param {*} id + * @returns */ async getObject( id ){ if ( this.buffer[id] ) return this.buffer[id] @@ -198,7 +203,7 @@ export default class ObjectLoader { let result = re.exec( chunk ) if ( !result ) { if ( readerDone ) break - let remainder = chunk.substr( startIndex ) + let remainder = chunk.substr( startIndex ) ;( { value: chunk, done: readerDone } = await reader.read() ) // PS: semicolon of doom chunk = remainder + ( chunk ? decoder.decode( chunk ) : '' ) startIndex = re.lastIndex = 0 diff --git a/packages/viewer/src/modules/ViewerObjectLoader.js b/packages/viewer/src/modules/ViewerObjectLoader.js index 53aab5543..b9d69fdf6 100644 --- a/packages/viewer/src/modules/ViewerObjectLoader.js +++ b/packages/viewer/src/modules/ViewerObjectLoader.js @@ -10,7 +10,12 @@ export default class ViewerObjectLoader { constructor( parent, objectUrl, authToken ) { this.viewer = parent - this.token = authToken || localStorage.getItem( 'AuthToken' ) + this.token = null + try { + this.token = authToken || localStorage.getItem( 'AuthToken' ) + } catch ( error ) { + // Accessing localStorage may throw when executing on sandboxed document, ignore. + } if ( !this.token ) { console.warn( 'Viewer: no auth token present. Requests to non-public stream objects will fail.' ) @@ -32,7 +37,7 @@ export default class ViewerObjectLoader { serverUrl: this.serverUrl, token: this.token, streamId: this.streamId, - objectId: this.objectId, + objectId: this.objectId } ) this.converter = new Converter( this.loader )