Fixed enough thing sto be able to authenticate and get data from Strava.
git-svn-id: https://www.unprompted.com/svn/projects/tildefriends/trunk@4347 ed5197a5-7fde-0310-b194-c3ffbd925b24
This commit is contained in:
		
							
								
								
									
										30
									
								
								core/core.js
									
									
									
									
									
								
							
							
						
						
									
										30
									
								
								core/core.js
									
									
									
									
									
								
							| @@ -1,6 +1,7 @@ | ||||
| import * as app from './app.js'; | ||||
| import * as auth from './auth.js'; | ||||
| import * as form from './form.js'; | ||||
| import * as http from './http.js'; | ||||
| import * as httpd from './httpd.js'; | ||||
|  | ||||
| let gProcessIndex = 0; | ||||
| @@ -66,6 +67,11 @@ const k_global_settings = { | ||||
| 		default_value: undefined, | ||||
| 		description: 'If connecting by HTTP and HTTPS is configured, Location header prefix (ie, "https://example.com")', | ||||
| 	}, | ||||
| 	fetch_hosts: { | ||||
| 		type: 'string', | ||||
| 		default_value: undefined, | ||||
| 		description: 'Comma-separated list of host names to which HTTP fetch requests are allowed.  None if empty.', | ||||
| 	}, | ||||
| }; | ||||
|  | ||||
| let gGlobalSettings = { | ||||
| @@ -404,6 +410,9 @@ async function getProcessBlob(blobId, key, options) { | ||||
| 					return ssb.privateMessageDecrypt(process.credentials.session.name, id, message); | ||||
| 				} | ||||
| 			}; | ||||
| 			imports.fetch = function(url, options) { | ||||
| 				return http.fetch(url, options, gGlobalSettings.fetch_hosts); | ||||
| 			} | ||||
|  | ||||
| 			if (process.credentials && | ||||
| 				process.credentials.session && | ||||
| @@ -583,12 +592,12 @@ function guessTypeFromMagicBytes(data) { | ||||
| 	} | ||||
| } | ||||
|  | ||||
| function sendData(response, data, type, headers) { | ||||
| function sendData(response, data, type, headers, status_code) { | ||||
| 	if (data) { | ||||
| 		response.writeHead(200, Object.assign({"Content-Type": type || guessTypeFromMagicBytes(data) || "application/binary", "Content-Length": data.byteLength}, headers || {})); | ||||
| 		response.writeHead(status_code ?? 200, Object.assign({"Content-Type": type || guessTypeFromMagicBytes(data) || "application/binary", "Content-Length": data.byteLength}, headers || {})); | ||||
| 		response.end(data); | ||||
| 	} else { | ||||
| 		response.writeHead(404, Object.assign({"Content-Type": "text/plain; charset=utf-8", "Content-Length": "File not found".length}, headers || {})); | ||||
| 		response.writeHead(status_code ?? 404, Object.assign({"Content-Type": "text/plain; charset=utf-8", "Content-Length": "File not found".length}, headers || {})); | ||||
| 		response.end("File not found"); | ||||
| 	} | ||||
| } | ||||
| @@ -604,7 +613,8 @@ async function getBlobOrContent(id) { | ||||
| } | ||||
|  | ||||
| let g_handler_index = 0; | ||||
| async function useAppHandler(response, handler_blob_id, path, query, headers) { | ||||
| async function useAppHandler(response, handler_blob_id, path, query, headers, packageOwner, packageName) { | ||||
| 	print('useAppHandler', packageOwner, packageName); | ||||
| 	let do_resolve; | ||||
| 	let promise = new Promise(async function(resolve, reject) { | ||||
| 		do_resolve = resolve; | ||||
| @@ -622,6 +632,8 @@ async function useAppHandler(response, handler_blob_id, path, query, headers) { | ||||
| 				respond: do_resolve, | ||||
| 			}, | ||||
| 			credentials: auth.query(headers), | ||||
| 			packageOwner: packageOwner, | ||||
| 			packageName: packageName, | ||||
| 		}); | ||||
| 		await process.ready; | ||||
|  | ||||
| @@ -784,7 +796,11 @@ async function blobHandler(request, response, blobId, uri) { | ||||
| 		let match; | ||||
| 		let id; | ||||
| 		let app_id = blobId; | ||||
| 		let packageOwner; | ||||
| 		let packageName; | ||||
| 		if (match = /^\/\~(\w+)\/(\w+)$/.exec(blobId)) { | ||||
| 			packageOwner = match[1]; | ||||
| 			packageName = match[2]; | ||||
| 			let db = new Database(match[1]); | ||||
| 			app_id = await db.get('path:' + match[2]); | ||||
| 		} | ||||
| @@ -794,7 +810,7 @@ async function blobHandler(request, response, blobId, uri) { | ||||
| 		if (!id && app_object.files['handler.js']) { | ||||
| 			let answer; | ||||
| 			try { | ||||
| 				answer = await useAppHandler(response, app_id, uri.substring(1), request.query ? form.decodeForm(request.query) : undefined, request.headers); | ||||
| 				answer = await useAppHandler(response, app_id, uri.substring(1), request.query ? form.decodeForm(request.query) : undefined, request.headers, packageOwner, packageName); | ||||
| 			} catch (error) { | ||||
| 				data = utf8Encode(`Internal Server Error\n\n${error?.message}\n${error?.stack}`); | ||||
| 				response.writeHead(500, {'Content-Type': 'text/plain; charset=utf-8', 'Content-Length': data.length}); | ||||
| @@ -804,10 +820,10 @@ async function blobHandler(request, response, blobId, uri) { | ||||
| 			if (answer && typeof answer.data == 'string') { | ||||
| 				answer.data = utf8Encode(answer.data); | ||||
| 			} | ||||
| 			sendData(response, answer?.data, answer?.content_type, { | ||||
| 			sendData(response, answer?.data, answer?.content_type, Object.assign(answer?.headers ?? {}, { | ||||
| 				'Access-Control-Allow-Origin': '*', | ||||
| 				'Content-Security-Policy': 'sandbox', | ||||
| 			}); | ||||
| 			}), answer.status_code); | ||||
| 		} else if (id) { | ||||
| 			if (request.headers['if-none-match'] && request.headers['if-none-match'] == '"' + id + '"') { | ||||
| 				let headers = { | ||||
|   | ||||
							
								
								
									
										31
									
								
								core/http.js
									
									
									
									
									
								
							
							
						
						
									
										31
									
								
								core/http.js
									
									
									
									
									
								
							| @@ -1,43 +1,45 @@ | ||||
| function parseUrl(url) { | ||||
| 	// XXX: Hack. | ||||
| 	let match = url.match(new RegExp("(\\w+)://([^/]+)?(.*)")); | ||||
| 	let match = url.match(new RegExp("(\\w+)://([^/:]+)(?::(\\d+))?(.*)")); | ||||
| 	return { | ||||
| 		protocol: match[1], | ||||
| 		host: match[2], | ||||
| 		path: match[3], | ||||
| 		port: match[1] == "http" ? 80 : 443, | ||||
| 		path: match[4], | ||||
| 		port: match[3] ? parseInt(match[3]) : match[1] == "http" ? 80 : 443, | ||||
| 	}; | ||||
| } | ||||
|  | ||||
| function parseResponse(data) { | ||||
| 	let firstLine; | ||||
| 	let headers = {}; | ||||
|  | ||||
| 	while (true) { | ||||
| 		let endLine = data.indexOf('\r\n'); | ||||
| 		let line = data.substring(0, endLine); | ||||
| 		if (!firstLine) { | ||||
| 			firstLine = line; | ||||
| 		} else if (!line.length) { | ||||
| 		data = data.substring(endLine + 2); | ||||
| 		if (!line.length) { | ||||
| 			break; | ||||
| 		} else if (!firstLine) { | ||||
| 			firstLine = line; | ||||
| 		} else { | ||||
| 			let colon = line.indexOf(":"); | ||||
| 			headers[line.substring(colon)] = line.substring(colon + 1); | ||||
| 		} | ||||
| 		data = data.substring(endLine + 2); | ||||
| 	} | ||||
| 	return {body: data}; | ||||
| } | ||||
|  | ||||
| export function fetch(url, options) { | ||||
| export function fetch(url, options, allowed_hosts) { | ||||
| 	let parsed = parseUrl(url); | ||||
| 	return new Promise(function(resolve, reject) { | ||||
| 		if (allowed_hosts.indexOf(parsed.host) == -1) { | ||||
| 			throw new Error(`fetch() request to host ${parsed.host} is not allowed.`); | ||||
| 		} | ||||
| 		let socket = new Socket(); | ||||
| 		let buffer = new Uint8Array(0) | ||||
| 		let buffer = new Uint8Array(0); | ||||
|  | ||||
| 		return socket.connect(parsed.host, parsed.port).then(function() { | ||||
| 			socket.read(function(data) { | ||||
| 				if (data) { | ||||
| 				if (data && data.length) { | ||||
| 					let newBuffer = new Uint8Array(buffer.length + data.length); | ||||
| 					newBuffer.set(buffer, 0); | ||||
| 					newBuffer.set(data, buffer.length); | ||||
| @@ -51,7 +53,12 @@ export function fetch(url, options) { | ||||
| 				return socket.startTls(); | ||||
| 			} | ||||
| 		}).then(function() { | ||||
| 			socket.write(`${options?.method ?? 'GET'} ${parsed.path} HTTP/1.0\r\nHost: ${parsed.host}\r\nConnection: close\r\n\r\n`); | ||||
| 			let body = typeof options?.body == 'string' ? utf8Encode(options.body) : (options.body || new Uint8Array(0)); | ||||
| 			let headers = utf8Encode(`${options?.method ?? 'GET'} ${parsed.path} HTTP/1.0\r\nHost: ${parsed.host}\r\nConnection: close\r\nContent-Length: ${body.length}\r\n\r\n`); | ||||
| 			let fullRequest = new Uint8Array(headers.length + body.length); | ||||
| 			fullRequest.set(headers, 0); | ||||
| 			fullRequest.set(body, headers.length); | ||||
| 			socket.write(fullRequest); | ||||
| 			socket.shutdown(); | ||||
| 		}).catch(function(error) { | ||||
| 			reject(error); | ||||
|   | ||||
		Reference in New Issue
	
	Block a user