Skip to content

Commit

Permalink
WebGoat#277 Re-institute admin functionality for WebGoat 8
Browse files Browse the repository at this point in the history
   - Report card functionality is back
  • Loading branch information
nbaars committed Dec 31, 2016
1 parent 490f542 commit e2cb9ce
Show file tree
Hide file tree
Showing 14 changed files with 443 additions and 121 deletions.
Original file line number Diff line number Diff line change
@@ -0,0 +1,111 @@
/**
* *************************************************************************************************
* <p>
* <p>
* This file is part of WebGoat, an Open Web Application Security Project
* utility. For details, please see http://www.owasp.org/
* <p>
* Copyright (c) 2002 - 20014 Bruce Mayhew
* <p>
* 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.
* <p>
* 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.
* <p>
* 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.
* <p>
* Getting Source ==============
* <p>
* Source for this application is maintained at
* https://github.com/WebGoat/WebGoat, a repository for free software projects.
*/
package org.owasp.webgoat.service;

import com.google.common.collect.Lists;
import com.google.common.collect.Maps;
import lombok.Getter;
import lombok.Setter;
import lombok.Singular;
import org.apache.catalina.User;
import org.owasp.webgoat.lessons.AbstractLesson;
import org.owasp.webgoat.session.Course;
import org.owasp.webgoat.session.LessonTracker;
import org.owasp.webgoat.session.UserTracker;
import org.owasp.webgoat.session.WebSession;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.ResponseBody;
import org.springframework.web.bind.annotation.RestController;

import java.util.HashMap;
import java.util.List;
import java.util.Map;

/**
* <p>ReportCardService</p>
*
* @author nbaars
* @version $Id: $Id
*/
@Controller
public class ReportCardService {

private final UserTracker userTracker;
private final Course course;

public ReportCardService(UserTracker userTracker, Course course) {
this.userTracker = userTracker;
this.course = course;
}

/**
* Endpoint which generates the report card for the current use to show the stats on the solved lessons
*/
@GetMapping(path = "/service/reportcard.mvc", produces = "application/json")
@ResponseBody
public ReportCard reportCard() {
List<AbstractLesson> lessons = course.getLessons();
ReportCard reportCard = new ReportCard();
reportCard.setTotalNumberOfLessons(course.getTotalOfLessons());
reportCard.setTotalNumberOfAssignments(course.getTotalOfAssignments());
reportCard.setNumberOfAssignmentsSolved(userTracker.numberOfAssignmentsSolved());
reportCard.setNumberOfLessonsSolved(userTracker.numberOfLessonsSolved());
for (AbstractLesson lesson : lessons) {
LessonTracker lessonTracker = userTracker.getLessonTracker(lesson);
LessonStatistics lessonStatistics = new LessonStatistics();
lessonStatistics.setName(lesson.getTitle());
lessonStatistics.setNumberOfAttempts(lessonTracker.getNumberOfAttempts());
lessonStatistics.setSolved(lessonTracker.isLessonSolved());
reportCard.lessonStatistics.add(lessonStatistics);
}
return reportCard;
}

@Getter
@Setter
private class ReportCard {

private int totalNumberOfLessons;
private int totalNumberOfAssignments;
private int solvedLessons;
private int numberOfAssignmentsSolved;
private int numberOfLessonsSolved;
private List<LessonStatistics> lessonStatistics = Lists.newArrayList();
}

@Setter
@Getter
private class LessonStatistics {
private String name;
private boolean solved;
private int numberOfAttempts;
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -89,5 +89,14 @@ public void setLessons(List<AbstractLesson> lessons) {
this.lessons = lessons;
}

public int getTotalOfLessons() {
return this.lessons.size();
}

public int getTotalOfAssignments() {
final int[] total = {0};
this.lessons.stream().forEach(l -> total[0] = total[0] + l.getAssignments().size());
return total[0];
}

}
Original file line number Diff line number Diff line change
Expand Up @@ -4,12 +4,14 @@
import com.google.common.collect.Maps;
import lombok.SneakyThrows;
import org.owasp.webgoat.lessons.AbstractLesson;
import org.owasp.webgoat.lessons.Assignment;
import org.springframework.util.FileCopyUtils;
import org.springframework.util.SerializationUtils;

import java.io.File;
import java.util.HashMap;
import java.util.Map;
import java.util.stream.Collectors;


/**
Expand Down Expand Up @@ -104,4 +106,23 @@ public void reset(AbstractLesson al) {
getLessonTracker(al).reset();
save();
}

public int numberOfLessonsSolved() {
int numberOfLessonsSolved = 0;
for(LessonTracker lessonTracker : storage.values()) {
if (lessonTracker.isLessonSolved()) {
numberOfLessonsSolved = numberOfLessonsSolved + 1;
}
}
return numberOfLessonsSolved;
}

public int numberOfAssignmentsSolved() {
int numberOfAssignmentsSolved = 0;
for (LessonTracker lessonTracker : storage.values()) {
Map<Assignment, Boolean> lessonOverview = lessonTracker.getLessonOverview();
numberOfAssignmentsSolved = lessonOverview.values().stream().filter(b -> b).collect(Collectors.counting()).intValue();
}
return numberOfAssignmentsSolved;
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@ spring.devtools.restart.enabled=false
spring.resources.cache-period=0


webgoat.tracker.overwrite=true
webgoat.tracker.overwrite=false
webgoat.user.directory=${user.home}/.webgoat/
webgoat.build.version=@project.version@
webgoat.build.number=@build.number@
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -55,9 +55,9 @@ define(['jquery',
this.lessonOverviewModel = new LessonOverviewModel();
this.lessonOverview = new LessonOverviewView(this.lessonOverviewModel);
this.lessonContentView = options.lessonContentView;
this.titleView = options.titleView;
this.developerControlsView = new DeveloperControlsView();


_.extend(Controller.prototype,Backbone.Events);

this.start = function() {
Expand All @@ -67,12 +67,13 @@ define(['jquery',
};

this.loadLesson = function(name,pageNum) {

if (this.name === name) {
this.lessonContentView.navToPage(pageNum)
this.lessonContentView.navToPage(pageNum);
this.titleView.render(this.lessonInfoModel.get('lessonTitle'));
return;
}

this.titleView = new TitleView();
this.helpsLoaded = {};
if (typeof(name) === 'undefined' || name === null) {
//TODO: implement lesson not found or return to welcome page?
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ define(['jquery',
'underscore',
'backbone',
'goatApp/view/MenuView'
],
],
function($,
_,
Backbone,
Expand All @@ -11,22 +11,9 @@ define(['jquery',
_.extend(Controller.prototype,Backbone.Events);
options = options || {};
this.menuView = options.menuView;
this.titleView = options.titleView;

// this.initMenu = function() {
// this.listenTo(this.menuView,'lesson:click',this.renderTitle);
// }

this.updateMenu = function(){
this.menuView.updateMenu();
},

//TODO: move title rendering into lessonContent/View pipeline once data can support it
this.renderTitle = function(title) {
this.titleView.render(title);
}


};

return Controller;
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
define([
'backbone'],
function(
Backbone) {
return Backbone.Model.extend({
url: 'service/reportcard.mvc'
});
});
Original file line number Diff line number Diff line change
@@ -0,0 +1,47 @@
<div class="panel panel-default" style="margin-top:25px">
<div class="panel-heading alt"><b>Overview</b></div>

<table class="table">
<tbody>
<tr>
<td width="30%">Total number of lessons</td>
<td width="70%"><%= totalNumberOfLessons %></td>
</tr>
<tr>
<td width="30%">Total number of lessons solved</td>
<td width="70%"><%= numberOfLessonsSolved %></td>
</tr>
<tr>
<td width="30%">Total number of assignments</td>
<td width="70%"><%= totalNumberOfAssignments %></td>
</tr>
<tr>
<td width="30%">Total number of assignments solved</td>
<td width="70%"><%= numberOfAssignmentsSolved %></td>
</tr>
</tbody>
</table>
</div>


<div class="panel panel-default" style="margin-top:25px">
<div class="panel-heading"><b>Lesson overview</b></div>
<table class="table">
<thead>
<tr>
<th>Lesson name</th>
<th>Solved</th>
<th>Number of attempts</th>
</tr>
</thead>
<tbody>
<% _(lessonStatistics).each(function(lesson) { %>
<%= lesson.solved ? '<tr class="success">' : '<tr>' %>
<td><%= lesson.name %></td>
<td><%= lesson.solved %></td>
<td><%= lesson.numberOfAttempts %></td>
</tr>
<% }) %>
</tbody>
</table>
</div>
Loading

0 comments on commit e2cb9ce

Please sign in to comment.