From 62347b50f456f2480f3c4af059c0d274650fedbe Mon Sep 17 00:00:00 2001 From: orbiter Date: Fri, 3 Aug 2007 23:06:53 +0000 Subject: [PATCH] added security layer for ViewImage: - images may be requested by localhost and authorized users only, if the request is done using a clear-text URL - the image may be requested also using a code that can be a license to retrieve a URL for everyone - some servelets produce URL licenses for ViewImage, like image search results git-svn-id: https://svn.berlios.de/svnroot/repos/yacy/trunk@4027 6c8d7289-2bf4-0310-a012-ef5d649a1542 --- htroot/ViewImage.java | 31 ++++++-- htroot/js/yacysearch.js | 6 +- htroot/xml/snippet.java | 6 ++ htroot/xml/snippet.xml | 3 +- htroot/yacysearch.html | 2 +- htroot/yacysearch.java | 6 +- source/de/anomic/data/URLLicense.java | 75 +++++++++++++++++++ .../de/anomic/plasma/plasmaSwitchboard.java | 6 ++ 8 files changed, 120 insertions(+), 15 deletions(-) create mode 100644 source/de/anomic/data/URLLicense.java diff --git a/htroot/ViewImage.java b/htroot/ViewImage.java index 7b8478632..e6f1ac299 100644 --- a/htroot/ViewImage.java +++ b/htroot/ViewImage.java @@ -61,13 +61,29 @@ public class ViewImage { plasmaSwitchboard sb = (plasmaSwitchboard)env; - String urls = post.get("url", ""); - URL url; - try { - url = new URL(urls); + // the url to the image can be either submitted with an url in clear text, or using a license key + // if the url is given as clear text, the user must be authorized as admin + // the license can be used also from non-authorized users + + String urlString = post.get("url", ""); + String urlLicense = post.get("code", ""); + boolean auth = ((String) header.get("CLIENTIP", "")).equals("localhost") || sb.verifyAuthentication(header, true); // handle access rights + + URL url = null; + if ((urlString.length() > 0) && (auth)) try { + url = new URL(urlString); } catch (MalformedURLException e1) { - return null; + url = null; + } + + if ((url == null) && (urlLicense.length() > 0)) { + url = sb.licensedURLs.releaseLicense(urlLicense); + urlString = url.toNormalform(true, true); } + + if (url == null) return null; + System.out.println("loading image from " + url.toString()); + int width = post.getInt("width", 0); int height = post.getInt("height", 0); int maxwidth = post.getInt("maxwidth", 0); @@ -78,7 +94,7 @@ public class ViewImage { Object[] resource = sb.snippetCache.getResource(url, true, timeout, false); byte[] imgb = null; if (resource == null) { - if (urls.endsWith(".ico")) { + if (urlString.endsWith(".ico")) { // load default favicon dfltfvcn.ico try { imgb = serverFileUtils.read(new File(sb.getRootPath(), "htroot/env/grafics/dfltfvcn.ico")); @@ -103,9 +119,8 @@ public class ViewImage { } // read image - Image image = ymageImageParser.parse(urls.toString(), imgb); + Image image = ymageImageParser.parse(urlString.toString(), imgb); - boolean auth = ((String) header.get("CLIENTIP", "")).equals("localhost") || sb.verifyAuthentication(header, false); // handle access rights if ((auth) && ((width == 0) || (height == 0)) && (maxwidth == 0) && (maxheight == 0)) return image; // find original size diff --git a/htroot/js/yacysearch.js b/htroot/js/yacysearch.js index cb37bdb29..6c88eceb5 100644 --- a/htroot/js/yacysearch.js +++ b/htroot/js/yacysearch.js @@ -231,12 +231,12 @@ function handleImageState(req, progressbar) { for (i = 0; i < links; i++) { var type = response.getElementsByTagName("type")[i].firstChild.data; var href = response.getElementsByTagName("href")[i].firstChild.data; + var code = response.getElementsByTagName("code")[i].firstChild.data; var name = response.getElementsByTagName("name")[i].firstChild.data; var attr = response.getElementsByTagName("attr")[i].firstChild.data; - //
#[name]# - var img = document.createElement("img"); - img.setAttribute("src", "/ViewImage.png?maxwidth=96&maxheight=96&url=" + href); + var img = document.createElement("img"); + img.setAttribute("src", "/ViewImage.png?maxwidth=96&maxheight=96&code=" + code); img.setAttribute("alt", name); var imganchor = document.createElement("a"); diff --git a/htroot/xml/snippet.java b/htroot/xml/snippet.java index 710dcb811..d17f9001b 100644 --- a/htroot/xml/snippet.java +++ b/htroot/xml/snippet.java @@ -77,8 +77,14 @@ public class snippet { plasmaSnippetCache.MediaSnippet ms; for (int i = 0; i < mediaSnippets.size(); i++) { ms = (plasmaSnippetCache.MediaSnippet) mediaSnippets.get(i); + try { + url = new URL(ms.href); + } catch (MalformedURLException e) { + continue; + } prop.put("link_" + i + "_type", ms.type); prop.put("link_" + i + "_href", ms.href); + prop.put("link_" + i + "_code", switchboard.licensedURLs.aquireLicense(url)); prop.put("link_" + i + "_name", ms.name); prop.put("link_" + i + "_attr", ms.attr); } diff --git a/htroot/xml/snippet.xml b/htroot/xml/snippet.xml index 452af6a99..bcf10bc7e 100644 --- a/htroot/xml/snippet.xml +++ b/htroot/xml/snippet.xml @@ -8,7 +8,8 @@ #{link}# #[type]# - #[href]# + #[href]# + #[code]# #[name]# #[attr]# diff --git a/htroot/yacysearch.html b/htroot/yacysearch.html index 1c73b59f0..be776f003 100644 --- a/htroot/yacysearch.html +++ b/htroot/yacysearch.html @@ -150,7 +150,7 @@ document.getElementById("Enter").value = "search again - catch up more links"; #(/recommend)# #(/authorized)# -

#[description]#

+

#[description]#

#(snippet)#loading snippet ...::#[text]##(/snippet)#

#[urlname]#

#[date]# | YBR-#[ybr]# | Info | Pictures

diff --git a/htroot/yacysearch.java b/htroot/yacysearch.java index a46665c14..b1db973ee 100644 --- a/htroot/yacysearch.java +++ b/htroot/yacysearch.java @@ -323,8 +323,10 @@ public class yacysearch { try{ URL url=new URL(result.getUrl()); int port=url.getPort(); - //TODO: parse ... - prop.put("type_results_" + i + "_favicon", url.getProtocol() + "://" + url.getHost() + ((port != -1) ? (":" + String.valueOf(port)) : "") + "/favicon.ico"); + URL faviconURL = new URL(url.getProtocol() + "://" + url.getHost() + ((port != -1) ? (":" + String.valueOf(port)) : "") + "/favicon.ico"); + // TODO: parse ... + // aquire license for favicon url loading + prop.put("type_results_" + i + "_faviconCode", sb.licensedURLs.aquireLicense(faviconURL)); }catch(MalformedURLException e){} prop.put("type_results_" + i + "_urlhash", result.getUrlhash()); prop.put("type_results_" + i + "_urlhexhash", yacySeed.b64Hash2hexHash(result.getUrlhash())); diff --git a/source/de/anomic/data/URLLicense.java b/source/de/anomic/data/URLLicense.java new file mode 100644 index 000000000..a0b8eeb72 --- /dev/null +++ b/source/de/anomic/data/URLLicense.java @@ -0,0 +1,75 @@ +// URLLicense.java +// (C) 2007 by Michael Peter Christen; mc@yacy.net, Frankfurt a. M., Germany +// first published 03.07.2007 on http://yacy.net +// +// This is a part of YaCy, a peer-to-peer based web search engine +// +// $LastChangedDate: 2006-04-02 22:40:07 +0200 (So, 02 Apr 2006) $ +// $LastChangedRevision: 1986 $ +// $LastChangedBy: orbiter $ +// +// LICENSE +// +// This program is free software; you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation; either version 2 of the License, or +// (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with this program; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + +package de.anomic.data; + +import java.util.HashMap; +import java.util.Random; + +import de.anomic.net.URL; + +public class URLLicense { + + // this class defines a license-generation for URLs + // it is used in case of snippet- and preview-Image-fetching to grant also non-authorized users the usage of a image-fetcher servlet + + private Random random; + private HashMap permissions; + private int keylen; + + public URLLicense(int keylen) { + this.permissions = new HashMap(); + this.random = new Random(System.currentTimeMillis()); + this.keylen = keylen; + } + + public String aquireLicense(URL url) { + // generate license key + String license = ""; + while (license.length() < keylen) license += Integer.toHexString(random.nextInt()); + license = license.substring(0, keylen); + // store reference to url with license key + synchronized (permissions) { + permissions.put(license, url); + } + // return the license key + return license; + } + + public URL releaseLicense(String license) { + URL url = null; + synchronized (permissions) { + url = (URL) permissions.remove(license); + } + if (url == null) { + System.out.println("DEBUG-URLLICENSE: no URL license present for code=" + license); + } else { + System.out.println("DEBUG-URLLICENSE: granted download of " + url.toString()); + } + return url; + } + +} diff --git a/source/de/anomic/plasma/plasmaSwitchboard.java b/source/de/anomic/plasma/plasmaSwitchboard.java index cb1a46367..7d817aa08 100644 --- a/source/de/anomic/plasma/plasmaSwitchboard.java +++ b/source/de/anomic/plasma/plasmaSwitchboard.java @@ -124,6 +124,7 @@ import java.util.Set; import java.util.TreeMap; import java.util.TreeSet; +import de.anomic.data.URLLicense; import de.anomic.data.blogBoard; import de.anomic.data.blogBoardComments; import de.anomic.data.bookmarksDB; @@ -258,6 +259,8 @@ public final class plasmaSwitchboard extends serverAbstractSwitch implements ser public double totalQPM = 0d; public TreeMap clusterhashes; // map of peerhash(String)/alternative-local-address as ip:port or only ip (String) or null if address in seed should be used public boolean acceptLocalURLs, acceptGlobalURLs; + public URLLicense licensedURLs; + /* * Remote Proxy configuration */ @@ -948,6 +951,9 @@ public final class plasmaSwitchboard extends serverAbstractSwitch implements ser i++; } + // initiate url license object + licensedURLs = new URLLicense(8); + // set URL domain acceptance this.acceptGlobalURLs = "global.any".indexOf(getConfig("network.unit.domain", "global")) >= 0; this.acceptLocalURLs = "local.any".indexOf(getConfig("network.unit.domain", "global")) >= 0;