Fixed a potential security vulnerability

pull/2686/head
Jamie 6 years ago
parent 60aa1c9fb0
commit 8e36a97f4e

@ -24,16 +24,5 @@ namespace Ombi.Api.Github
request.AddHeader("User-Agent", "Ombi"); request.AddHeader("User-Agent", "Ombi");
return await _api.Request<List<CakeThemes>>(request); return await _api.Request<List<CakeThemes>>(request);
} }
public async Task<string> GetThemesRawContent(string url)
{
var sections = url.Split('/');
var lastPart = sections.Last();
url = url.Replace(lastPart, string.Empty);
var request = new Request(lastPart, url, HttpMethod.Get);
request.AddHeader("Accept", "application/vnd.github.v3+json");
request.AddHeader("User-Agent", "Ombi");
return await _api.RequestContent(request);
}
} }
} }

@ -7,6 +7,5 @@ namespace Ombi.Api.Github
public interface IGithubApi public interface IGithubApi
{ {
Task<List<CakeThemes>> GetCakeThemes(); Task<List<CakeThemes>> GetCakeThemes();
Task<string> GetThemesRawContent(string url);
} }
} }

@ -1,55 +1,16 @@
using System; namespace Ombi.Settings.Settings.Models
using System.ComponentModel.DataAnnotations.Schema;
using Newtonsoft.Json;
using Ombi.Helpers;
namespace Ombi.Settings.Settings.Models
{ {
public class CustomizationSettings : Settings public class CustomizationSettings : Settings
{ {
public string ApplicationName { get; set; } public string ApplicationName { get; set; }
public string ApplicationUrl { get; set; } public string ApplicationUrl { get; set; }
public string CustomCssLink { get; set; } public string CustomCss { get; set; }
public bool EnableCustomDonations { get; set; } public bool EnableCustomDonations { get; set; }
public string CustomDonationUrl { get; set; } public string CustomDonationUrl { get; set; }
public string CustomDonationMessage { get; set; } public string CustomDonationMessage { get; set; }
public string Logo { get; set; } public string Logo { get; set; }
public string PresetThemeName { get; set; }
public string PresetThemeContent { get; set; }
public bool RecentlyAddedPage { get; set; } public bool RecentlyAddedPage { get; set; }
[NotMapped]
public string PresetThemeVersion
{
get
{
if (HasPresetTheme)
{
var parts = PresetThemeName.Split('-');
return parts[3].Replace(".css", string.Empty);
}
return string.Empty;
}
}
[NotMapped]
public string PresetThemeDisplayName
{
get
{
if (HasPresetTheme)
{
var parts = PresetThemeName.Split('-');
return parts[1];
}
return string.Empty;
}
}
[NotMapped]
public bool HasPresetTheme => PresetThemeName.HasValue() || PresetThemeContent.HasValue();
public void AddToUrl(string part) public void AddToUrl(string part)
{ {
if (string.IsNullOrEmpty(ApplicationUrl)) if (string.IsNullOrEmpty(ApplicationUrl))

@ -114,25 +114,13 @@ export interface ICustomizationSettings extends ISettings {
applicationName: string; applicationName: string;
applicationUrl: string; applicationUrl: string;
logo: string; logo: string;
customCssLink: string; customCss: string;
enableCustomDonations: boolean; enableCustomDonations: boolean;
customDonationUrl: string; customDonationUrl: string;
customDonationMessage: string; customDonationMessage: string;
hasPresetTheme: boolean;
presetThemeName: string;
presetThemeContent: string;
presetThemeDisplayName: string;
presetThemeVersion: string;
recentlyAddedPage: boolean; recentlyAddedPage: boolean;
} }
export interface IThemes {
fullName: string;
displayName: string;
version: string;
url: string;
}
export interface IJobSettings { export interface IJobSettings {
embyContentSync: string; embyContentSync: string;
sonarrSync: string; sonarrSync: string;

@ -31,7 +31,6 @@ import {
ISlackNotificationSettings, ISlackNotificationSettings,
ISonarrSettings, ISonarrSettings,
ITelegramNotifcationSettings, ITelegramNotifcationSettings,
IThemes,
IUpdateSettings, IUpdateSettings,
IUserManagementSettings, IUserManagementSettings,
IVoteSettings, IVoteSettings,
@ -135,14 +134,6 @@ export class SettingsService extends ServiceHelpers {
return this.http.post<boolean>(`${this.url}/customization`, JSON.stringify(settings), {headers: this.headers}); return this.http.post<boolean>(`${this.url}/customization`, JSON.stringify(settings), {headers: this.headers});
} }
public getThemes(): Observable<IThemes[]> {
return this.http.get<IThemes[]>(`${this.url}/themes`, {headers: this.headers});
}
public getThemeContent(themeUrl: string): Observable<string> {
return this.http.get(`${this.url}/themecontent?url=${themeUrl}`, {responseType: "text", headers: this.headers});
}
public getEmailNotificationSettings(): Observable<IEmailNotificationSettings> { public getEmailNotificationSettings(): Observable<IEmailNotificationSettings> {
return this.http.get<IEmailNotificationSettings>(`${this.url}/notifications/email`, {headers: this.headers}); return this.http.get<IEmailNotificationSettings>(`${this.url}/notifications/email`, {headers: this.headers});
} }

@ -47,15 +47,6 @@
</div> </div>
</div> </div>
<div class="form-group">
<label for="customLink" class="control-label">Custom CSS Link</label>
<div>
<input type="text" [(ngModel)]="settings.customCssLink" class="form-control form-control-custom " name="customLink" value="{{settings.customCssLink}}"
tooltipPosition="top" pTooltip="A link to a CSS file, you can use this to use your own styles for Ombi">
</div>
</div>
<div class="form-group"> <div class="form-group">
<div class="checkbox"> <div class="checkbox">
<input type="checkbox" id="enableCustomDonations" name="enableCustomDonations" [(ngModel)]="settings.enableCustomDonations"> <input type="checkbox" id="enableCustomDonations" name="enableCustomDonations" [(ngModel)]="settings.enableCustomDonations">
@ -63,7 +54,7 @@
</div> </div>
</div> </div>
<div class="form-group"> <div class="form-group" *ngIf="settings.enableCustomDonations">
<label for="customDonation" class="control-label">Custom Donation URL</label> <label for="customDonation" class="control-label">Custom Donation URL</label>
<div> <div>
<input [disabled]="!settings.enableCustomDonations" type="text" [(ngModel)]="settings.customDonationUrl" class="form-control form-control-custom " name="customDonation" value="{{settings.customDonationUrl}}" <input [disabled]="!settings.enableCustomDonations" type="text" [(ngModel)]="settings.customDonationUrl" class="form-control form-control-custom " name="customDonation" value="{{settings.customDonationUrl}}"
@ -71,7 +62,7 @@
</div> </div>
</div> </div>
<div class="form-group"> <div class="form-group" *ngIf="settings.enableCustomDonations">
<label for="customDonationMessage" class="control-label">Donation Button Message</label> <label for="customDonationMessage" class="control-label">Donation Button Message</label>
<div> <div>
<input [disabled]="!settings.enableCustomDonations" type="text" [(ngModel)]="settings.customDonationMessage" class="form-control form-control-custom " name="customDonationMessage" value="{{settings.customDonationMessage}}" <input [disabled]="!settings.enableCustomDonations" type="text" [(ngModel)]="settings.customDonationMessage" class="form-control form-control-custom " name="customDonationMessage" value="{{settings.customDonationMessage}}"
@ -89,21 +80,15 @@
</div> </div>
<div class="col-md-7"> <div class="col-md-7">
<div *ngIf="themes"> <div>
<div class="form-group"> <div class="form-group">
<label for="presetTheme" class="control-label">Preset Themes</label> <label for="customCss" class="control-label">Custom CSS</label>
<div id="presetTheme">
<select class="form-control form-control-custom" (change)="dropDownChange($event)">
<option *ngFor="let theme of themes" value="{{theme.fullName}}" [selected]="settings.presetThemeName === theme.fullName">{{theme.displayName}} {{theme.version}}</option>
</select>
</div>
</div> </div>
<div class="form-group" *ngIf="settings.presetThemeContent"> <div class="form-group language-css" pCode>
<textarea rows="25" type="text" class="form-control-custom form-control " id="themeContent" name="themeContent" [(ngModel)]="settings.presetThemeContent"> {{settings.presetThemeContent}} </textarea> <textarea rows="25" type="text"
pTooltip="Enter your custom styles here" tooltipPosition="top"
class="form-control-custom form-control " id="themeContent" name="themeContent" [(ngModel)]="settings.customCss"> {{settings.customCss}} </textarea>
</div> </div>
<small>Preset themes are powered by
<a href="https://github.com/leram84/layer.Cake" target="_blank">layer#Cake</a>.
</small>
</div> </div>
</div> </div>

@ -1,6 +1,6 @@
import { Component, OnInit } from "@angular/core"; import { Component, OnInit } from "@angular/core";
import { ICustomizationSettings, IThemes } from "../../interfaces"; import { ICustomizationSettings } from "../../interfaces";
import { NotificationService } from "../../services"; import { NotificationService } from "../../services";
import { SettingsService } from "../../services"; import { SettingsService } from "../../services";
@ -10,7 +10,6 @@ import { SettingsService } from "../../services";
export class CustomizationComponent implements OnInit { export class CustomizationComponent implements OnInit {
public settings: ICustomizationSettings; public settings: ICustomizationSettings;
public themes: IThemes[];
public advanced: boolean; public advanced: boolean;
constructor(private settingsService: SettingsService, private notificationService: NotificationService) { } constructor(private settingsService: SettingsService, private notificationService: NotificationService) { }
@ -18,26 +17,6 @@ export class CustomizationComponent implements OnInit {
public ngOnInit() { public ngOnInit() {
this.settingsService.getCustomization().subscribe(x => { this.settingsService.getCustomization().subscribe(x => {
this.settings = x; this.settings = x;
this.settingsService.getThemes().subscribe(t => {
this.themes = t;
const existingTheme = this.themes.filter((item) => {
return item.fullName === this.settings.presetThemeName;
})[0];
if (existingTheme) {
const index = this.themes.indexOf(existingTheme, 0);
if (index > -1) {
this.themes.splice(index, 1);
}
}
if (x.hasPresetTheme) {
this.themes.unshift({displayName: x.presetThemeDisplayName, fullName: x.presetThemeName, url: existingTheme.url, version: x.presetThemeVersion});
this.themes.unshift({displayName: "None", fullName: "None", url: "", version: ""});
} else {
this.themes.unshift({displayName: "Please Select", fullName: "-1", url: "-1", version: ""});
}
});
}); });
} }
@ -62,26 +41,4 @@ export class CustomizationComponent implements OnInit {
}); });
} }
public dropDownChange(event: any): void {
const selectedThemeFullName = <string> event.target.value;
const selectedTheme = this.themes.filter((val) => {
return val.fullName === selectedThemeFullName;
})[0];
if (selectedTheme.fullName === this.settings.presetThemeName) {
return;
}
if (selectedTheme.fullName === "None" || selectedTheme.fullName === "-1") {
this.settings.presetThemeName = "";
this.settings.presetThemeContent = "";
return;
}
this.settings.presetThemeName = selectedThemeFullName;
this.settingsService.getThemeContent(selectedTheme.url).subscribe(x => {
this.settings.presetThemeContent = x;
});
}
} }

@ -274,19 +274,6 @@ namespace Ombi.Controllers
return model; return model;
} }
/// <summary>
/// Gets the content of the theme available
/// </summary>
/// <param name="url"></param>
/// <returns></returns>
[HttpGet("themecontent")]
[AllowAnonymous]
public async Task<IActionResult> GetThemeContent([FromQuery]string url)
{
var css = await _githubApi.GetThemesRawContent(url);
return Content(css, "text/css");
}
/// <summary> /// <summary>
/// Gets the Sonarr Settings. /// Gets the Sonarr Settings.
/// </summary> /// </summary>

@ -1,4 +1,5 @@
@using Ombi.Core.Settings @using Ombi.Core.Settings
@using Ombi.Helpers
@using Ombi.Settings.Settings.Models @using Ombi.Settings.Settings.Models
@inject ISettingsService<OmbiSettings> Settings @inject ISettingsService<OmbiSettings> Settings
@inject ISettingsService<CustomizationSettings> CustomizationSettings @inject ISettingsService<CustomizationSettings> CustomizationSettings
@ -105,29 +106,12 @@
</head> </head>
<body> <body>
@{ @{
if (customization.HasPresetTheme) if (customization.CustomCss.HasValue())
{ {
if (!string.IsNullOrEmpty(baseUrl)) <style>
{ @Html.Raw(customization.CustomCss)
if (!customization.PresetThemeContent.Contains("/" + baseUrl))
{
var index = customization.PresetThemeContent.IndexOf("/api/");
if (index > 0)
{
customization.PresetThemeContent = customization.PresetThemeContent.Insert(index, "/" + baseUrl);
}
}
}
<style>
@Html.Raw(customization.PresetThemeContent)
</style> </style>
} }
if (!string.IsNullOrEmpty(customization.CustomCssLink))
{
<link rel="stylesheet" href="@customization.CustomCssLink" asp-append-version="true" />
}
} }
@RenderBody() @RenderBody()

Loading…
Cancel
Save