diff options
Diffstat (limited to 'src')
-rw-r--r-- | src/array.js | 61 | ||||
-rw-r--r-- | src/auth.js | 125 | ||||
-rw-r--r-- | src/logoot.js | 153 |
3 files changed, 0 insertions, 339 deletions
diff --git a/src/array.js b/src/array.js deleted file mode 100644 index ae30012..0000000 --- a/src/array.js +++ /dev/null @@ -1,61 +0,0 @@ -// Extend the array class to expose update -// functionality, plus provide some -// useful helper methods -export default function(graffiti) { - - return class GraffitiArray extends Array { - - get mine() { - return this.filter(o=> o._by==graffiti.myID) - } - - get notMine() { - return this.filter(o=> o._by!=graffiti.myID) - } - - get authors() { - return [...new Set(this.map(o=> o._by))] - } - - removeMine() { - this.mine.map(o=> delete o._key) - } - - #getProperty(obj, propertyPath) { - // Split it up by periods - propertyPath = propertyPath.match(/([^\.]+)/g) - // Traverse down the path tree - for (const property of propertyPath) { - obj = obj[property] - } - return obj - } - - sortBy(propertyPath) { - - const sortOrder = propertyPath[0] == '-'? -1 : 1 - if (sortOrder < 0) propertyPath = propertyPath.substring(1) - - return this.sort((a, b)=> { - const propertyA = this.#getProperty(a, propertyPath) - const propertyB = this.#getProperty(b, propertyPath) - return sortOrder * ( - propertyA < propertyB? -1 : - propertyA > propertyB? 1 : 0 ) - }) - } - - groupBy(propertyPath) { - return this.reduce((chain, obj)=> { - const property = this.#getProperty(obj, propertyPath) - if (property in chain) { - chain[property].push(obj) - } else { - chain[property] = new GraffitiArray(obj) - } - return chain - }, {}) - } - - } -} diff --git a/src/auth.js b/src/auth.js deleted file mode 100644 index 8ee803d..0000000 --- a/src/auth.js +++ /dev/null @@ -1,125 +0,0 @@ -export default { - - async logIn(graffitiURL) { - // Generate a random client secret and state - const clientSecret = crypto.randomUUID() - const state = crypto.randomUUID() - - // The client ID is the secret's hex hash - const clientID = await this.sha256(clientSecret) - - // Store the client secret as a local variable - window.localStorage.setItem('graffitiClientSecret', clientSecret) - window.localStorage.setItem('graffitiClientID', clientID) - window.localStorage.setItem('graffitiAuthState', state) - - // Redirect to the login window - const loginURL = this.authURL(graffitiURL) - loginURL.searchParams.set('client_id', clientID) - loginURL.searchParams.set('redirect_uri', window.location.href) - loginURL.searchParams.set('state', state) - window.location.href = loginURL - }, - - async connect(graffitiURL) { - - // Check to see if we are already logged in - let token = window.localStorage.getItem('graffitiToken') - let myID = window.localStorage.getItem('graffitiID') - - if (!token || !myID) { - // Remove them both in case one exists - // and the other does not - token = myID = null - - // Check to see if we are redirecting back - const url = new URL(window.location) - if (url.searchParams.has('code')) { - - // Extract the code and state from the URL and strip it from the history - const code = url.searchParams.get('code') - const state = url.searchParams.get('state') - url.searchParams.delete('code') - url.searchParams.delete('state') - window.history.replaceState({}, '', url) - - // Get stored variables and remove them - const clientSecret = window.localStorage.getItem('graffitiClientSecret') - const clientID = window.localStorage.getItem('graffitiClientID') - const storedState = window.localStorage.getItem('graffitiAuthState') - window.localStorage.removeItem('graffitiClientSecret') - window.localStorage.removeItem('graffitiClientID') - window.localStorage.removeItem('graffitiAuthState') - - // Make sure state has been preserved - if (state != storedState) { - throw new Error("The state in local storage does not match the state sent by the server") - } - - // Construct the body of the POST - let form = new FormData() - form.append('client_id', clientID) - form.append('client_secret', clientSecret) - form.append('code', code) - - // Ask to exchange the code for a token - const tokenURL = this.authURL(graffitiURL) - tokenURL.pathname = '/token' - const response = await fetch(tokenURL, { - method: 'post', - body: form - }) - - // Make sure the response is OK - if (!response.ok) { - let reason = response.status + ": " - try { - reason += (await response.json()).detail - } catch (e) { - reason += response.statusText - } - - throw new Error(`The authorization code could not be exchanged for a token.\n\n${reason}`) - } - - // Parse out the token - const data = await response.json() - token = data.access_token - myID = data.owner_id - - // And make sure that the token is valid - if (!token || !myID) { - throw new Error(`The authorization token could not be parsed from the response.\n\n${data}`) - } - - // Store the token and ID - window.localStorage.setItem('graffitiToken', token) - window.localStorage.setItem('graffitiID', myID) - } - } - - return { myID, token } - - }, - - logOut() { - window.localStorage.removeItem('graffitiToken') - window.localStorage.removeItem('graffitiID') - window.location.reload() - }, - - authURL(graffitiURL) { - const url = new URL(graffitiURL) - url.host = "auth." + url.host - return url - }, - - async sha256(input) { - const encoder = new TextEncoder() - const inputBytes = encoder.encode(input) - const outputBuffer = await crypto.subtle.digest('SHA-256', inputBytes) - const outputArray = Array.from(new Uint8Array(outputBuffer)) - return outputArray.map(b => b.toString(16).padStart(2, '0')).join('') - } - -} diff --git a/src/logoot.js b/src/logoot.js deleted file mode 100644 index c8c7c02..0000000 --- a/src/logoot.js +++ /dev/null @@ -1,153 +0,0 @@ -export default { - - query(property) { - return { - [property]: { - $type: 'array', - $type: ['int', 'long'], - }, - $nor: [ - { [property]: { $gt: this.maxInt } }, - { [property]: { $lt: 0 } }, - ] - } - }, - - get before() { - return [] - }, - - get after() { - return [this.maxInt+1] - }, - - between(a, b, scale=100) { - // Strip zeros and find common length - const aLength = this.lengthWithoutZeros(a) - const bLength = this.lengthWithoutZeros(b) - const minLength = Math.min(aLength, bLength) - - // Initialize output - const out = [] - - // Find the break point where a[i] != b[i] - let i = 0 - while (i < minLength && a[i] == b[i]) { - out.push(a[i]) - i++ - } - - // Initialize upper and lower bounds for - // sampling the last digit - let lowerBound = 1 - let upperBound = this.maxInt - - if (i < minLength) { - // If the break happened before we hit - // the end of one of the arrays - - if (Math.abs(a[i] - b[i]) > 1) { - // If a[i] and b[i] are more than one - // away from each other, just sample - // between them - lowerBound = Math.min(a[i], b[i]) + 1 - upperBound = Math.max(a[i], b[i]) - 1 - } else { - // If they are one away no integers - // will fit in between, so add new layer - const lesser = (a[i] < b[i])? a : b - out.push(lesser[i]) - i++ - - while (i < lesser.length && lesser[i] >= this.maxInt) { - // If the lesser is at it's limit, - // we will need to add even more layers - out.push(lesser[i]) - i++ - } - - if (i < lesser.length) { - // Sample something greater than - // the lesser digit - lowerBound = lesser[i] + 1 - } - } - } else { - // The break happened because we hit - // the end of one of the arrays. - - if (aLength == bLength) { - // If they are entirely equal, - // there is nothing in between - // just return what we have - return out - } - - const longerLength = Math.max(aLength, bLength) - const longer = (a.length == longerLength)? a : b - while (i < longerLength && longer[i] == 0) { - // Skip past the zeros because we can't sample - // for digits less than zero - out.push(0) - i++ - } - - if (i < longerLength) { - if (longer[i] == 1) { - // If longer is at it's limit, - // we still need to add another layer - out.push(0) - } else { - upperBound = longer[i] - 1 - } - } - } - - // Create a random number in [0,1] but bias it to be small, - // so that numbers tend to increase by a small amount. - let random = Math.random() - random = -Math.log(1-random)/scale - random = Math.min(random, 1) - - // Finally, sample between the upper and lower bounds - out.push(Math.floor(random * (upperBound + 1 - lowerBound)) + lowerBound) - return out - }, - - compare(a, b) { - // Strip zeros and find common length - const aLength = this.lengthWithoutZeros(a) - const bLength = this.lengthWithoutZeros(b) - const minLength = Math.min(aLength, bLength) - - // See if there are any differences - for (let i = 0; i < minLength; i++) { - if (a[i] > b[i]) { - return 1 - } else if (a[i] < b[i]) { - return -1 - } - } - - // If they are all the same up til now, - // the longer one is bigger - if (aLength > bLength) { - return 1 - } else if (aLength < bLength) { - return -1 - } else { - return 0 - } - }, - - - lengthWithoutZeros(a) { - let length = a.length - while (length > 0 && a[length - 1] == 0) { - length-- - } - return length - }, - - maxInt: 9007199254740991, -} |