package org.sakaiproject.shortenedurl.entityprovider;
import java.io.OutputStream;
import java.io.UnsupportedEncodingException;
import java.net.URLDecoder;
import java.util.Map;
import javax.servlet.http.HttpServletResponse;
import lombok.Setter;
import lombok.extern.apachecommons.CommonsLog;
import org.apache.commons.lang.StringUtils;
import org.sakaiproject.component.api.ServerConfigurationService;
import org.sakaiproject.entitybroker.EntityView;
import org.sakaiproject.entitybroker.entityprovider.EntityProvider;
import org.sakaiproject.entitybroker.entityprovider.annotations.EntityCustomAction;
import org.sakaiproject.entitybroker.entityprovider.capabilities.ActionsExecutable;
import org.sakaiproject.entitybroker.entityprovider.capabilities.AutoRegisterEntityProvider;
import org.sakaiproject.entitybroker.entityprovider.capabilities.Describeable;
import org.sakaiproject.entitybroker.exception.EntityException;
import org.sakaiproject.shortenedurl.api.ShortenedUrlService;
/**
* Implementation of the EntityProvider for the ShortenedUrlService to allow URL shortening via GET requests.
*
* @author Steve Swinsburg (steve.swinsburg@gmail.com)
*
*/
@CommonsLog
public class ShortenedUrlServiceEntityProviderImpl implements ShortenedUrlServiceEntityProvider, EntityProvider, AutoRegisterEntityProvider, Describeable, ActionsExecutable {
public String getEntityPrefix() {
return ENTITY_PREFIX;
}
@EntityCustomAction(action="shorten",viewKey=EntityView.VIEW_LIST)
public Object shorten(OutputStream out, EntityView view, Map<String, Object> params) {
String path = (String)params.get("path");
if(StringUtils.isBlank(path)){
throw new EntityException("Invalid path.", path);
}
//SHORTURL-38 check if eternal urls are allowed to be shortened, defaults to false (only internal urls are allowed)
//if external not allowed then we need to check the host and the url to be shortened, otherwise we don't care
boolean externalAllowed = serverConfigurationService.getBoolean("shortenedurl.external.enabled", false);
if(!externalAllowed) {
String serverUrl = serverConfigurationService.getServerUrl();
//decode path
String pathDecoded;
try {
pathDecoded = URLDecoder.decode(path, "UTF-8");
} catch (UnsupportedEncodingException e) {
throw new EntityException("Unable to decode path.", path);
}
//path could be a relative fragment (ie /portal/site/abc), if so, create full url and check
String fullUrl = pathDecoded;
if(StringUtils.startsWith(pathDecoded, "/")) {
fullUrl = serverUrl + pathDecoded;
log.debug("Path: " + pathDecoded + ", full URL: " + fullUrl);
}
//now have full url so check they start with the same value. otherwise it is external and it should be blocked.
if(!StringUtils.startsWith(fullUrl, serverUrl)) {
log.error("Attempted to shorten:" + pathDecoded + ", but this does not have the same prefix as the current server: " + serverUrl);
throw new EntityException("Couldn't shorten URL as external URLs are not permitted. The path parameter must contain either a relative path or a full URL that is for the same host.", path, HttpServletResponse.SC_FORBIDDEN);
}
}
boolean secure = Boolean.parseBoolean((String)params.get("secure"));
try {
String shortenedUrl = shortenedUrlService.shorten(URLDecoder.decode(path, "UTF-8"), secure);
if(StringUtils.isBlank(shortenedUrl)){
throw new EntityException("Couldn't shorten URL.", path);
}
return shortenedUrl;
} catch (UnsupportedEncodingException e) {
throw new EntityException("Unable to decode path.", path);
}
}
@Setter
private ShortenedUrlService shortenedUrlService;
@Setter
private ServerConfigurationService serverConfigurationService;
}