Merge pull request #1 from mwindower/dynamic-frontend

Load BadVulns count with AJAX calls
This commit is contained in:
Stefan Majer 2017-04-24 16:05:34 +02:00 committed by GitHub
commit 4a8066c14d
4 changed files with 141 additions and 22 deletions

View file

@ -194,7 +194,7 @@ td {
td:last-child,
th:last-child {
text-align: right;
padding-right: 0px;
padding-right: 5px;
}
td a {
display: block;
@ -205,6 +205,38 @@ tr.parent a {
.parent a:hover {
color: #2a2a2a;
}
/*------------------------------------*\
Loading Indicator
\*------------------------------------*/
.signal {
border: 2px solid #333;
border-radius: 15px;
height: 15px;
left: 50%;
margin: -8px 0 0 -8px;
opacity: 0;
top: 50%;
width: 15px;
float: right;
animation: pulsate 1s ease-out;
animation-iteration-count: infinite;
}
@keyframes pulsate {
0% {
transform: scale(.1);
opacity: 0.0;
}
50% {
opacity: 1;
}
100% {
transform: scale(1.2);
opacity: 0;
}
}
/*------------------------------------*\
Footer
\*------------------------------------*/

View file

@ -35,6 +35,24 @@ function search(search_val){
}
}
function loadVulnerabilityCount(url){
var xhr = new XMLHttpRequest();
xhr.open('GET', url);
xhr.onload = function() {
if (xhr.status === 200) {
var report = JSON.parse(xhr.responseText);
var id = report.Repo + ':' + report.Tag;
var element = document.getElementById(id);
if (element) {
element.innerHTML = report.BadVulns;
} else {
console.log("element not found for given id ", id);
}
}
};
xhr.send();
}
var el = document.querySelectorAll('tr:nth-child(2)')[0].querySelectorAll('td:nth-child(2)')[0];
if (el.textContent == 'Parent Directory'){
@ -72,22 +90,26 @@ our_table.setAttribute('id', 'directory');
var search_input = document.querySelectorAll('input[name="filter"]')[0];
var clear_button = document.querySelectorAll('a.clear')[0];
if (search_input.value !== ''){
search(search_input.value);
if (search_input) {
if (search_input.value !== ''){
search(search_input.value);
}
search_input.addEventListener('keyup', function(e){
e.preventDefault();
search(search_input.value);
});
search_input.addEventListener('keypress', function(e){
if ( e.which == 13 ) {
e.preventDefault();
}
});
}
search_input.addEventListener('keyup', function(e){
e.preventDefault();
search(search_input.value);
});
search_input.addEventListener('keypress', function(e){
if ( e.which == 13 ) {
e.preventDefault();
}
});
clear_button.addEventListener('click', function(e){
search_input.value = '';
search('');
});
if (clear_button) {
clear_button.addEventListener('click', function(e){
search_input.value = '';
search('');
});
}

View file

@ -37,9 +37,9 @@
<td align="right" nowrap>
{{ $value.Created.Format "02 Jan, 2006 15:04:05 UTC" }}
</td>
<td >
<a href="/repo/{{ $value.Name | urlquery }}/{{ $value.Tag }}/vulns">
{{ $value.VulnerabilityReport.BadVulns }}
<td align="right" nowrap>
<a href="/repo/{{ $value.Name | urlquery }}/{{ $value.Tag }}/vulns" id="{{ $value.Name }}:{{ $value.Tag }}">
<div class="signal"></div>
</a>
</td>
</tr>
@ -51,6 +51,18 @@
<a href="https://twitter.com/jessfraz">@jessfraz</a>
</div><!--/.footer-->
<script src="/js/scripts.js"></script>
<script type="text/javascript">
var ajaxCalls = [
{{ range $key, $value := .Repositories }}
'/repo/{{ $value.Name | urlquery }}/{{ $value.Tag }}/report',
{{ end }}
];
window.onload = function() {
Array.prototype.forEach.call(ajaxCalls, function(url, index){
loadVulnerabilityCount(url);
});
};
</script>
<script>
(function(i,s,o,g,r,a,m){i['GoogleAnalyticsObject']=r;i[r]=i[r]||function(){
(i[r].q=i[r].q||[]).push(arguments)},i[r].l=1*new Date();a=s.createElement(o),
@ -61,4 +73,4 @@ ga('send', 'pageview');
</script>
</body>
</html>
{{end}}
{{end}}

View file

@ -103,6 +103,7 @@ func listenAndServe(port, keyfile, certfile string, r *registry.Registry, c *cla
e.GET("/repo/:repo", rc.tags)
e.GET("/repo/:repo/:tag", rc.tag)
e.GET("/repo/:repo/:tag/vulns", rc.vulnerabilities)
e.GET("/repo/:repo/:tag/report", rc.report)
srv := &http.Server{
Addr: ":" + port,
@ -260,6 +261,58 @@ func (rc *registryController) tags(c echo.Context) error {
return err
}
func (rc *registryController) report(c echo.Context) error {
repo, err := url.QueryUnescape(c.Param("repo"))
if err != nil {
return c.String(http.StatusNotFound, "Given repo can not be unescaped.")
}
if repo == "" {
return c.String(http.StatusNotFound, "No repo given")
}
tag := c.Param("tag")
if tag == "" {
return c.String(http.StatusNotFound, "No tag given")
}
m1, err := r.ManifestV1(repo, tag)
if err != nil {
log.WithFields(log.Fields{
"error": err,
"repo": repo,
"tag": tag,
}).Warn("getting v1 manifest failed")
}
for _, h := range m1.History {
var comp v1Compatibility
if err := json.Unmarshal([]byte(h.V1Compatibility), &comp); err != nil {
msg := "unmarshal v1compatibility failed"
log.WithFields(log.Fields{
"error": err,
"repo": repo,
"tag": tag,
}).Warn(msg)
return c.String(http.StatusInternalServerError, msg)
}
break
}
result := clair.VulnerabilityReport{}
if rc.cl != nil {
result, err = rc.cl.Vulnerabilities(rc.reg, repo, tag, m1)
if err != nil {
log.WithFields(log.Fields{
"error": err,
"repo": repo,
"tag": tag,
}).Error("error during vulnerability scanning.")
}
}
return c.JSON(http.StatusOK, result)
}
func (rc *registryController) vulnerabilities(c echo.Context) error {
repo, err := url.QueryUnescape(c.Param("repo"))
if err != nil {