Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Self update #1097

Merged
merged 31 commits into from
Oct 16, 2016
Merged
Show file tree
Hide file tree
Changes from 23 commits
Commits
Show all changes
31 commits
Select commit Hold shift + click to select a range
bfebff8
Self upgrade proof of concept
crossan007 Oct 5, 2016
0aee63c
pre-test commit, since you know...this will overwrite my work.
crossan007 Oct 5, 2016
07257c1
Add integrity check
crossan007 Oct 7, 2016
a0399fa
api cleanup
crossan007 Oct 7, 2016
a65324f
update build script to generate signature file
crossan007 Oct 7, 2016
720ce83
fix line ending
crossan007 Oct 7, 2016
f542a89
tweaks
crossan007 Oct 7, 2016
07fb247
require admin rights to upgrade
crossan007 Oct 7, 2016
1c1f5e6
Merge branch 'develop' into self-update
crossan007 Oct 7, 2016
a2062a7
fix derp
crossan007 Oct 7, 2016
a00572c
Merge branch 'self-update' of https://github.com/ChurchCRM/CRM into s…
crossan007 Oct 8, 2016
28f2449
Merge branch 'develop' into self-update
crossan007 Oct 8, 2016
0f3a4cf
tweaks
crossan007 Oct 8, 2016
919c6fa
Merge origin/self-update into self-update
crossan007 Oct 8, 2016
4e514ea
Merge branch 'develop' into self-update
crossan007 Oct 8, 2016
21a9369
improve integrity check
crossan007 Oct 8, 2016
b299280
Merge origin/self-update into self-update
crossan007 Oct 8, 2016
0251942
underp link for integrity check
crossan007 Oct 12, 2016
b913c26
Merge branch 'develop' into self-update
DawoudIO Oct 12, 2016
686d3a7
show more detail in integritycheck.php
crossan007 Oct 12, 2016
529b1e1
Merge origin/self-update into self-update
crossan007 Oct 12, 2016
0f24dd8
cleanup build xml
crossan007 Oct 12, 2016
31165a3
Merge branch 'develop' into self-update
crossan007 Oct 12, 2016
ce312db
cleanup integrity check notification
crossan007 Oct 15, 2016
7ea7df0
delete zip
crossan007 Oct 15, 2016
24da903
Improve update efficiency. Runs much faster
crossan007 Oct 16, 2016
c56879f
fix issue with deep dirs
crossan007 Oct 16, 2016
4f0a63d
weekly integrity check instead of hourly
crossan007 Oct 16, 2016
fd582fd
UI Improvements
crossan007 Oct 16, 2016
4830907
UI Improvements
crossan007 Oct 16, 2016
41d99c8
Handle missing files and fix sRootPath
crossan007 Oct 16, 2016
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
68 changes: 35 additions & 33 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -1,33 +1,35 @@
#Vagrant
.vagrant/

# Covers JetBrains IDEs: IntelliJ, RubyMine, PhpStorm, AppCode, PyCharm
*.iml
## Directory-based project format:
.idea/

## File-based project format:
*.ipr
*.iws

#Exclude composer vendor folders
vendor
composer.lock

# Uploaded Images
thumbnails

# SASS
.sass-cache

#skins
adminlte
font-awesome
ionicons

# Configuration files with passwords
src/Include/Config.php

target
/src/orm/model/ChurchCRM/Base/
/src/orm/model/ChurchCRM/Map/
#Vagrant
.vagrant/

# Covers JetBrains IDEs: IntelliJ, RubyMine, PhpStorm, AppCode, PyCharm
*.iml
## Directory-based project format:
.idea/

## File-based project format:
*.ipr
*.iws

#Exclude composer vendor folders
vendor
composer.lock

# Uploaded Images
thumbnails

# SASS
.sass-cache

#skins
adminlte
font-awesome
ionicons

# Configuration files with passwords
src/Include/Config.php

target
/src/orm/model/ChurchCRM/Base/
/src/orm/model/ChurchCRM/Map/
/src/signatures.json
/src/integrityCheck.json
6 changes: 6 additions & 0 deletions build.xml
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,7 @@
<include name="**"/>
<exclude name="Images/Person/thumbnails/*.jpg"/>
<exclude name="composer.lock"/>
<exclude name="signatures.json"/>
<exclude name="Include/Config.php"/>
<exclude name="vendor/almasaeed2010/**"/>
<exclude name="vendor/components/**"/>
Expand All @@ -41,6 +42,11 @@
<exclude name="skin/adminlte/plugins/datatables/extensions/TableTools/images/psd/**"/>
</fileset>
</copy>

<echo message="Generating code signature file..."/>
<exec command = "php generateSignatures.php ${sourcedir}/churchcrm" passthru="true"/>



</target>

Expand Down
36 changes: 36 additions & 0 deletions generateSignatures.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
<?php

/*
* To change this license header, choose License Headers in Project Properties.
* To change this template file, choose Tools | Templates
* and open the template in the editor.
*/
$CRMRoot = $argv[1];
$CRMRootLen = strlen($CRMRoot);
$signatureFile = $CRMRoot."/signatures.json";
$composerFile = file_get_contents(__DIR__. "/src/composer.json");
$composerJson = json_decode($composerFile, true);

echo "Creating Signature Definition at: ".$signatureFile."\r\n";

$signatureData = new stdClass();
$signatureData->version = $composerJson["version"];
$signatureData->files = array();

$projectFiles = new RecursiveDirectoryIterator($CRMRoot);
$Iterator = new RecursiveIteratorIterator($projectFiles);
$Regex = new RegexIterator($Iterator, '/^.+\.(php|js)$/i', RecursiveRegexIterator::GET_MATCH);
foreach ($Regex as $obj )
{
$file = new stdClass();
$file->filename = substr($obj[0], $CRMRootLen+1);
$file->sha1 = sha1_file($CRMRoot."/".$file->filename);
array_push($signatureData->files, $file);
}

ksort($signatureData->files);

$signatureData->sha1 = sha1(json_encode($signatureData->files));
file_put_contents($signatureFile, json_encode($signatureData));

?>
4 changes: 4 additions & 0 deletions src/Include/HeaderNotLoggedIn.php
Original file line number Diff line number Diff line change
Expand Up @@ -24,4 +24,8 @@
<title>ChurchCRM: <?= gettext($sPageTitle) ?></title>
</head>
<body class="hold-transition login-page">

<script language="javascript" type="text/javascript">
window.CRM = {root: "<?= $sRootPath ?>"};
</script>

94 changes: 94 additions & 0 deletions src/IntegrityCheck.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,94 @@
<?php
/*******************************************************************************
*
* filename : GroupList.php
* website : http://www.churchcrm.io
* copyright : Copyright 2001, 2002 Deane Barker
*
*
* Additional Contributors:
* 2006 Ed Davis
* 2016 Charles Crossan
*
*
* Copyright Contributors
*
* ChurchCRM 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 file best viewed in a text editor with tabs stops set to 4 characters
*
******************************************************************************/
//Include the function library
require 'Include/Config.php';
require 'Include/Functions.php';


//Set the page title
$sPageTitle = gettext('Integrity Check Results');
if (!$_SESSION['bFinance'])
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I don't get this check

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Whooopss.. That's what i get for copying / pasting a page. I should get rid of the header too...

{
Redirect("index.php");
exit;
}
require 'Include/Header.php';
$CRMInstallRoot = __DIR__;
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

no need for the var

$integrityCheckFile = $CRMInstallRoot."/integrityCheck.json";
$IntegrityCheckDetails = json_decode(file_get_contents($integrityCheckFile));

?>

<div class="box box-body">
<p><?= gettext("Previous Integrity Check Result:") ?>
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

use the callout warning css to get read or green

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

image

image

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

fixed in a commit coming soon to a Repo near you

<?php
if ($IntegrityCheckDetails->status == "failure")
{
?>
<span style="color:red"><?= gettext("Failure") ?></span>
<?php
}
else
{
?>
<span style="color:green"><?= gettext("Success") ?></span>
<?php
}
?>
</p>
<?php
if (isset($IntegrityCheckDetails->message))
{
?>
<p><?= gettext("Details:")?> <?= $IntegrityCheckDetails->message ?></p>

<?php
}
if(count($IntegrityCheckDetails->files) > 0 )
{
?>
<p><?= gettext("Files failing integrity check:") ?>
<ul>
<?php
foreach ($IntegrityCheckDetails->files as $file)
{
?>
<li>FileName: <?= $file->filename ?>
<ul>
<li>Expected Hash: <?= $file->expectedhash ?></li>
<li>Actual Hash: <?= $file->actualhash ?></li>
</ul>
</li>
<?php
}
?>
</ul>
<?php
}
?>
</div>

<?php
require 'Include/Footer.php';
?>
101 changes: 98 additions & 3 deletions src/Service/SystemService.php
Original file line number Diff line number Diff line change
Expand Up @@ -363,24 +363,119 @@ function reportIssue($data)

function runTimerJobs()
{
global $sEnableExternalBackupTarget, $sExternalBackupAutoInterval, $sLastBackupTimeStamp;
global $sEnableIntegrityCheck, $sIntegrityCheckInterval, $sLastIntegrityCheckTimeStamp;
//start the external backup timer job
if ($sEnableExternalBackupTarget && $sExternalBackupAutoInterval > 0) //if remote backups are enabled, and the interval is greater than zero
{
try {
$now = new DateTime(); //get the current time
$previous = new DateTime($sLastBackupTimeStamp); // get a DateTime object for the last time a backup was done.
$now = new \DateTime(); //get the current time
$previous = new \DateTime($sLastBackupTimeStamp); // get a DateTime object for the last time a backup was done.
$diff = $previous->diff($now); // calculate the difference.
if (!$sLastBackupTimeStamp || $diff->h >= $sExternalBackupAutoInterval) // if there was no previous backup, or if the interval suggests we do a backup now.
{
$systemService->copyBackupToExternalStorage(); // Tell system service to do an external storage backup.
$now = new DateTime(); // update the LastBackupTimeStamp.
$now = new \DateTime(); // update the LastBackupTimeStamp.
$sSQL = "UPDATE config_cfg SET cfg_value='" . $now->format('Y-m-d H:i:s') . "' WHERE cfg_name='sLastBackupTimeStamp'";
$rsUpdate = RunQuery($sSQL);
}
} catch (Exception $exc) {
// an error in the auto-backup shouldn't prevent the page from loading...
}
}
if ($sEnableIntegrityCheck && $sIntegrityCheckInterval > 0)
{
$now = new \DateTime(); //get the current time
$previous = new \DateTime($sLastIntegrityCheckTimeStamp); // get a DateTime object for the last time a backup was done.
$diff = $previous->diff($now); // calculate the difference.
if (!$sLastIntegrityCheckTimeStamp || $diff->h >= $sIntegrityCheckInterval) // if there was no previous backup, or if the interval suggests we do a backup now.
{
$CRMInstallRoot = dirname(__DIR__);
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

temp var not used else where

$integrityCheckFile = $CRMInstallRoot."/integrityCheck.json";
$appIntegrity = $this->verifyApplicationIntegrity();
file_put_contents($integrityCheckFile, json_encode($appIntegrity));
$now = new \DateTime(); // update the LastBackupTimeStamp.
$sSQL = "UPDATE config_cfg SET cfg_value='" . $now->format('Y-m-d H:i:s') . "' WHERE cfg_name='sLastIntegrityCheckTimeStamp'";
$rsUpdate = RunQuery($sSQL);
}
}
}

function downloadLatestRelease()
{
$release = $this->getLatestRelese();
$CRMInstallRoot = dirname(__DIR__);
$UpgradeDir = $CRMInstallRoot."/Upgrade";
$url = $release['assets'][0]['browser_download_url'];
mkdir($UpgradeDir);
file_put_contents($UpgradeDir."/".basename($url), file_get_contents($url));
$returnFile= array();
$returnFile['fileName'] = basename($url);
$returnFile['fullPath'] = $UpgradeDir."/".basename($url);
$returnFile['sha1'] = sha1_file($UpgradeDir."/".basename($url));
return $returnFile;
}

function doUpgrade($zipFilename,$sha1)
{
ini_set('max_execution_time',60);
$CRMInstallRoot = dirname(__DIR__);
if($sha1 == sha1_file($zipFilename))
{
$zip = new \ZipArchive();
if ($zip->open($zipFilename) == TRUE)
{
for($i = 0; $i < $zip->numFiles; $i++)
{
$archivedFileName = $zip->getNameIndex($i);
$targetFilename = str_replace("churchcrm/","/",$archivedFileName);
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

what are you trying to do here

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

we don't want to maintain the "churchcrm" folder inside of the zip archive when we extract it.

if ($targetFilename != "/Service/SystemService.php") // save the best for last.
{
copy("zip://".$zipFilename."#".$archivedFileName, $CRMInstallRoot.$targetFilename);
}
}
$zip->close();
}
return "It is done";
}
else
{
return "hashes dont match. don't touch it!";
}

}

function verifyApplicationIntegrity()
{
$CRMInstallRoot = dirname(__DIR__);
$signatureFile = $CRMInstallRoot."/signatures.json";
$signatureData = json_decode(file_get_contents($signatureFile));
$signatureFailures = array();

if (sha1(json_encode($signatureData->files)) == $signatureData->sha1)
{
foreach ($signatureData->files as $file)
{
$actualHash = sha1_file($CRMInstallRoot."/".$file->filename);
if ( $actualHash != $file->sha1 )
{
array_push($signatureFailures, array("filename"=>$file->filename,"expectedhash"=>$file->sha1,"actualhash"=>$actualHash));
}
}
}
else
{
return array("status"=>"failure","message"=>"Signature Definition file signature failed validation");
}

if(count($signatureFailures) > 0 )
{
return array("status"=>"failure","files"=>$signatureFailures);
}
else
{
return array("status"=>"success");
}

}
}
8 changes: 7 additions & 1 deletion src/Service/TaskService.php
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,8 @@ public function __construct()

function getAdminTasks() {
requireUserGroupMembership("bAdmin");
$CRMInstallRoot = dirname(__DIR__);
$integrityCheckData = json_decode(file_get_contents($CRMInstallRoot."/integrityCheck.json"));
$sSQL = "SELECT cfg_name, IFNULL(cfg_value, cfg_default) AS value FROM config_cfg";
$rsConfig = mysql_query($sSQL); // Can't use RunQuery -- not defined yet
if ($rsConfig) {
Expand All @@ -42,7 +44,11 @@ function getAdminTasks() {
}

if ($this->latestVersion != null && $this->latestVersion["name"] != $this->installedVersion) {
array_push($tasks, $this->addTask("New Release ". $this->latestVersion["name"], $this->latestVersion["html_url"], true));
array_push($tasks, $this->addTask("New Release ". $this->latestVersion["name"], $this->baseURL."/UpgradeCRM.php", true));
}

if($integrityCheckData->status == "failure") {
array_push($tasks, $this->addTask("Application Integrity Check Failed", $this->baseURL."/IntegrityCheck.php", true));
}

return $tasks;
Expand Down
Loading