LCOV - code coverage report
Current view: top level - src - http_config.c (source / functions) Hit Total Coverage
Test: deployctl-0.3.15.2.96a2d Code Coverage Lines: 123 124 99.2 %
Date: 2018-06-22 Functions: 5 5 100.0 %
Legend: Lines: hit not hit

          Line data    Source code
       1             : /*
       2             :  http_config.c
       3             :  Created by Danny Goossen, Gioxa Ltd on 8/3/17.
       4             : 
       5             :  MIT License
       6             : 
       7             :  Copyright (c) 2017 deployctl, Gioxa Ltd.
       8             : 
       9             :  Permission is hereby granted, free of charge, to any person obtaining a copy
      10             :  of this software and associated documentation files (the "Software"), to deal
      11             :  in the Software without restriction, including without limitation the rights
      12             :  to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
      13             :  copies of the Software, and to permit persons to whom the Software is
      14             :  furnished to do so, subject to the following conditions:
      15             : 
      16             :  The above copyright notice and this permission notice shall be included in all
      17             :  copies or substantial portions of the Software.
      18             : 
      19             :  THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
      20             :  IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
      21             :  FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
      22             :  AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
      23             :  LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
      24             :  OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
      25             :  SOFTWARE.
      26             : 
      27             :  */
      28             : 
      29             : 
      30             : 
      31             : #include "deployd.h"
      32             : 
      33             : // TODO, read from /opt/config/nginx/....config.in
      34             : // and regex the hostname
      35             : // For now staic compiled here
      36             : 
      37             : const char* def_http_conf=
      38             : 
      39             : "server {\n" \
      40             : "   listen 80;\n  listen [::]:80;\n" \
      41             : "   server_name %s;\n" \
      42             : "   server_tokens off;\n" \
      43             : "   client_max_body_size 0;\n" \
      44             : "   index index.html; \n" \
      45             : "   root %s/public;\n"\
      46             : "   error_page 404 /html_error/404.html; \n" \
      47             : "   location / {try_files $uri $uri/ =404;}\n" \
      48             : "   %s" \
      49             : "   location /html_error/ { root /opt/deploy/config; }\n" \
      50             : "   location ^~ /.well-known { root /opt/deploy/var; }\n" \
      51             : "   }\n";
      52             : 
      53             : const char* def_https_conf=
      54             : "server {\n" \
      55             : "   listen 80;\n  listen [::]:80;\n" \
      56             : "   server_name %s;\n" \
      57             : "   server_tokens off;\n" \
      58             : "   client_max_body_size 0;\n" \
      59             : "   index index.html; \n" \
      60             : "   root %s/public;\n" \
      61             : "   error_page 404 /html_error/404.html; \n" \
      62             : "   location / { return 301 https://%s$request_uri; }\n" \
      63             : "   location /html_error/ { root /opt/deploy/config; }\n" \
      64             : "   location ^~ /.well-known { root /opt/deploy/var; }\n" \
      65             : "   }\n" \
      66             : "server {\n" \
      67             : "   listen 443 ssl http2;\n  listen [::]:443 ssl http2;\n" \
      68             : "   server_name %s;\n" \
      69             : "   server_tokens off;\n" \
      70             : "   client_max_body_size 0;\n" \
      71             : "   ssl on;\n" \
      72             : "   ssl_certificate /opt/deploy/.acme.sh/%s/fullchain.cer;\n" \
      73             : "   ssl_certificate_key /opt/deploy/.acme.sh/%s/%s.key;\n" \
      74             : "   ssl_ciphers 'ECDHE-RSA-AES256-GCM-SHA384:ECDHE-RSA-AES128-GCM-SHA256:ECDHE-RSA-AES256-SHA384:ECDHE-RSA-AES128-SHA256:ECDHE-RSA-AES256-SHA:ECDHE-RSA-AES128-SHA:ECDHE-RSA-DES-CBC3-SHA:AES256-GCM-SHA384:AES128-GCM-SHA256:AES256-SHA256:AES128-SHA256:AES256-SHA:AES128-SHA:DES-CBC3-SHA:!aNULL:!eNULL:!EXPORT:!DES:!MD5:!PSK:!RC4';\n" \
      75             : "   ssl_prefer_server_ciphers on;\n" \
      76             : "   ssl_protocols  TLSv1 TLSv1.1 TLSv1.2;\n" \
      77             : "   ssl_session_cache  builtin:1000  shared:SSL:10m;\n" \
      78             : "   ssl_session_timeout  5m;\n" \
      79             : "   index index.html;\n" \
      80             : "   root %s/public;\n"\
      81             : "   error_page 404 /html_error/404.html;\n"\
      82             : "   location / {try_files $uri $uri/ =404;}\n" \
      83             : "   %s" \
      84             : "   location /html_error/ {root /opt/deploy/config;}\n" \
      85             : "   }\n";
      86             : 
      87             : const char * repo_conf_options=
      88             :  "   location ~ ^/(rpm|deb)/([0-9a-zA-Z\\x20\\.]+)/([0-9a-z\\_]+) {autoindex on;}" \
      89             :  "   location ~* ^/(deb|rpm)/ {return 301 $scheme://$server_name/;}";
      90             : 
      91             : /*------------------------------------------------------------------------
      92             :  * url_check,
      93             :  * writes the commit tag in basePATH/public alias baseHREF
      94             :  * and performs a CURL to baseHref
      95             :  * to verify if baseHREF points to basePATH/public
      96             :  * Returns 0 on success
      97             :  *------------------------------------------------------------------------*/
      98           3 : int url_check(void * opaque, char * basePATH,char * baseHREF)
      99             : { // write http config for production environment
     100             :    char * newarg[11];
     101             :    // feedback buffer
     102           3 :    int exitcode=0;
     103           3 :    struct trace_Struct *trace=((data_exchange_t *)opaque)->trace;
     104             :    // env json
     105           3 :    cJSON * env_json=((data_exchange_t *)opaque)->env_json;
     106             : 
     107             :    // no need to set environment for individual commands
     108           3 :    ((data_exchange_t *)opaque)->needenvp=0;
     109             : 
     110           3 :    void * saved_args=((data_exchange_t *)opaque)->paramlist;
     111           3 :    ((data_exchange_t *)opaque)->paramlist=(char **)newarg;
     112             : 
     113             :    char filepath[1024];
     114           3 :    char * commit_sha=cJSON_GetObjectItem(env_json, "CI_COMMIT_SHA")->valuestring;
     115             :    // ***** write index.html of the tag
     116           3 :    newarg[0]="write_file";
     117           3 :    newarg[1]=filepath;
     118           3 :    sprintf(filepath, "%s/public/.commit_sha.txt",basePATH);
     119           3 :    newarg[2]=commit_sha;
     120           3 :    newarg[3]=NULL;
     121             : 
     122           3 :   Write_dyn_trace(trace, yellow,"  Check url:");
     123           3 :   Write_dyn_trace(trace, cyan," %s\n",baseHREF);
     124             : 
     125           3 :    Write_dyn_trace_pad(trace, none,75,"+ validate domain ...");
     126             : 
     127             : 
     128           3 :    debug("writing %s %d bytes\n",newarg[1],strlen(newarg[2]));
     129           3 :    exitcode=cmd_write(opaque);
     130           3 :    if (exitcode)
     131             :    {
     132           1 :       debug("failed writing hash to %s\n",newarg[1]);
     133           1 :       Write_dyn_trace(trace, red,"[FAILED]\n  ERROR: Failed to write validation hash\n");
     134             :    }
     135           3 :    if (!exitcode)
     136             :    {
     137           2 :       usleep(500000);// wait till file change propagated
     138           2 :       exitcode=url_verify( commit_sha,baseHREF,trace);
     139             :    }
     140             :    //Restore arguments
     141           3 :    ((data_exchange_t *)opaque)->paramlist=saved_args;
     142           3 :    return exitcode;
     143             : }
     144             : 
     145             : /*------------------------------------------------------------------------
     146             :  * delete http config file in basePATH
     147             :  *------------------------------------------------------------------------*/
     148           1 : int delete_http_config(void * opaque,char * basePATH)
     149             : {
     150             :    char * newarg[4];
     151             :     char config_file_name[1024];
     152             :     // feedback buffer
     153           1 :    int exitcode=0;
     154           1 :    struct trace_Struct *trace=((data_exchange_t *)opaque)->trace;
     155             :     // env json
     156             : 
     157             :    // no need to set environment for individual commands
     158           1 :    ((data_exchange_t *)opaque)->needenvp=0;
     159             : 
     160           1 :    void * saved_args=((data_exchange_t *)opaque)->paramlist;
     161           1 :    ((data_exchange_t *)opaque)->paramlist=(char **)newarg;
     162           1 :     sprintf((char *)config_file_name,"%s/server.conf",basePATH);
     163           1 :    newarg[0]="/bin/rm";
     164           1 :    newarg[1]="-f";
     165           1 :    newarg[2]=(char *)config_file_name;
     166           1 :    newarg[3]=NULL;
     167             : 
     168           1 :    Write_dyn_trace(trace, none,"+ Remove new offending config-file\n");
     169             : 
     170           1 :    update_details(trace);
     171           1 :    debug("cmd: %s %s %s \n",newarg[0],newarg[1],newarg[2]);
     172             : 
     173           1 :    int temp=cmd_exec(opaque);
     174             : 
     175           1 :    if (temp) {debug("Failed to delete config %s\n",newarg[2]);}
     176           1 :    ((data_exchange_t *)opaque)->paramlist=saved_args;
     177           1 :    return exitcode;
     178             : }
     179             : 
     180             : /*------------------------------------------------------------------------
     181             :  * write_http_config for http or https with http to https redirect
     182             :  * write as root:nginx
     183             :  * returns 0 on succes
     184             :  *------------------------------------------------------------------------*/
     185           3 : int write_http_config(void * opaque, int is_https,char * basePATH, char * server_name)
     186             : { // write http config for production environment
     187             :     char * newarg[4];
     188             :     char config_file_name[1024];
     189             :     char config_file[4096];
     190             :     // feedback buffer
     191           3 :    int exitcode=0;
     192           3 :    struct trace_Struct *trace=((data_exchange_t *)opaque)->trace;
     193             : 
     194             : 
     195             :    // no need to set environment for individual commands
     196           3 :    ((data_exchange_t *)opaque)->needenvp=0;
     197             : 
     198           3 :    void * saved_args=((data_exchange_t *)opaque)->paramlist;
     199           3 :    ((data_exchange_t *)opaque)->paramlist=(char **)newarg;
     200             : 
     201           3 :     sprintf((char *)config_file_name,"%s/server.conf",basePATH);
     202           3 :    const char * conf_options=NULL;
     203           3 :    const char def_conf_options[]="#\n";
     204           3 :    conf_options=def_conf_options;
     205             : 
     206           3 :    if (is_https>1) conf_options=repo_conf_options;
     207             : 
     208           3 :    if (is_https==1||is_https==3)
     209             :    {
     210           1 :       sprintf((char *)config_file,def_https_conf,server_name,basePATH,server_name,server_name,server_name,server_name,server_name,basePATH,conf_options);
     211           1 :       newarg[0]="+ write_config_https...";
     212             : 
     213             :    }
     214             :    else //if (is_https==0|| is_https==2 )
     215             :    {
     216           2 :        sprintf((char *)config_file,def_http_conf,server_name,basePATH,conf_options);
     217           2 :       newarg[0]="+ write_config_http...";
     218             : 
     219             :    }
     220             :    
     221             : 
     222             :        // ***** write config
     223           3 :     newarg[1]=(char *)config_file_name;
     224           3 :     newarg[2]=(char *)config_file;
     225           3 :     newarg[3]=NULL;
     226           3 :     Write_dyn_trace_pad(trace, none,75,"%s",newarg[0]);
     227           3 :    debug("writing %s %d bytes\n",newarg[1],strlen(newarg[2]));
     228           3 :     exitcode=cmd_write(opaque);
     229             : 
     230           3 :     if (!exitcode)
     231             :     {
     232           2 :         debug("wrote %s, %d bytes\n",newarg[1],strlen(newarg[2]));
     233           2 :        Write_dyn_trace(trace, green,"[OK]\n");
     234             :     }
     235             :    else
     236             :    {
     237           1 :       debug("ERROR: Writing  %s, %d bytes\n",newarg[1],strlen(newarg[2]));
     238           1 :        Write_dyn_trace(trace, red,"[FAILED]\n  ERROR: writing new config-file\n");
     239             :    }
     240           3 :    update_details(trace);
     241           3 :         ((data_exchange_t *)opaque)->paramlist=saved_args;
     242           3 :     return exitcode;
     243             : }
     244             : 
     245             : /*------------------------------------------------------------------------
     246             :  * check_namespace
     247             :  * read the basePATH/.namespace file
     248             :  * should contain the project_url from previous deployment
     249             :  * If that matches the current project url, it returns 0
     250             :  * if no content or no file it returns also 0
     251             :  *------------------------------------------------------------------------*/
     252           5 : int check_namespace(void * opaque,char * filepath)
     253             : {
     254           5 :    int result=0;
     255             :    char namespace_file_name[1024];
     256           5 :    int exitcode=0;
     257           5 :    struct trace_Struct *trace=((data_exchange_t *)opaque)->trace;
     258             : 
     259           5 :    cJSON * env_json=((data_exchange_t *)opaque)->env_json;
     260           5 :    char * project_url=cJSON_get_key(env_json, "CI_PROJECT_URL");
     261           5 :    sprintf((char *)namespace_file_name,"%s/.namespace",filepath);
     262             : 
     263           5 :    Write_dyn_trace_pad(trace, none,75,"+ Check name space ...");
     264             : 
     265           5 :    FILE *f = fopen(namespace_file_name, "r");
     266           5 :    if (f == NULL)
     267             :    {// doesn't exist, so ok
     268           3 :        Write_dyn_trace(trace, green,"[OK]\n");
     269             : 
     270           3 :       return 0;
     271             :    }
     272             :    struct MemoryStruct mem;
     273           2 :    init_dynamicbuf(&mem);
     274             :    char buf[1024];
     275           2 :    bzero(buf, 1024);
     276           6 :    while( fgets( buf, 1024, f ) != NULL )
     277             :    {
     278           2 :       Writedynamicbuf(buf, &mem );
     279           2 :       bzero(buf, 1024);
     280             :    }
     281           2 :    fclose(f);
     282           2 :    result=strcmp(mem.memory,project_url);
     283             : 
     284           2 :    if (result)
     285             :    {
     286           1 :       debug("ERR: namespace : \n => %s\n != \n =>%s\n",project_url,mem.memory);
     287           1 :       Write_dyn_trace(trace, red,"[FAILED]\n  ERROR: project_url : \n =>%s\n != \n =>%s\n",project_url,mem.memory);
     288             : 
     289           1 :       exitcode=1;
     290             :    }
     291             :    else
     292             :    {
     293           1 :       Write_dyn_trace(trace, green,"[OK]\n");
     294           1 :         exitcode=0;
     295             :    }
     296           2 :     update_details(trace);
     297             :    // TODO
     298             :    // to avoid deliberate spoofing of namespaces and does to sabotage somebody else release:
     299             :    // check if CI_REPOSITORY_URL points to the same repo as CI_PROJECT_URL
     300             :    // then  git ls-remote CI_REPOSITORY_URL if ok, at least we got access, better to access with API, but doesn't work if not public repo.
     301             : 
     302             :    // for now, unintentional overwrite protection is provided, room for discussion and brainstorm
     303           2 :    return exitcode;
     304             : }
     305             : 
     306             : /*------------------------------------------------------------------------
     307             :  * write_namespace, or locks current directory on this project
     308             :  * writes the project_url in basePATH/.namespace
     309             :  * return 0 on success
     310             :  *------------------------------------------------------------------------*/
     311           1 : int write_namespace(void * opaque, char * filepath )
     312             : {
     313             :    char * newarg[4];
     314             :    char namespace_file_name[1024];
     315             :    // feedback buffer
     316           1 :    int exitcode=0;
     317           1 :    struct trace_Struct *trace=((data_exchange_t *)opaque)->trace;
     318             : 
     319             :    // env json
     320           1 :    cJSON * env_json=((data_exchange_t *)opaque)->env_json;
     321             : 
     322             :    // no need to set environment for individual commands
     323           1 :    ((data_exchange_t *)opaque)->needenvp=0;
     324             : 
     325           1 :    void * saved_args=((data_exchange_t *)opaque)->paramlist;
     326           1 :    ((data_exchange_t *)opaque)->paramlist=(char **)newarg;
     327             : 
     328           1 :    char * project_url=cJSON_get_key(env_json, "CI_PROJECT_URL");
     329             : 
     330           1 :    newarg[0]="write_name_space";
     331           1 :    newarg[1]=(char *)namespace_file_name;
     332           1 :    newarg[2]=(char *)project_url;
     333           1 :    newarg[3]=NULL;
     334           1 :     Write_dyn_trace_pad(trace, none,75,"+ Lock name space ...");
     335             : 
     336           1 :    sprintf((char *)namespace_file_name,"%s/.namespace",filepath);
     337           1 :    exitcode=cmd_write(opaque);
     338           1 :    if (!exitcode)
     339             :    {
     340           1 :       debug("wrote namespace %s: %s\n",newarg[1],newarg[2]);
     341             :    }
     342           1 :    if (!exitcode)
     343           1 :      Write_dyn_trace(trace, green,"[OK]\n");
     344             :    else
     345           0 :      Write_dyn_trace(trace, red,"[FAILED]\n");
     346             : 
     347           1 :    ((data_exchange_t *)opaque)->paramlist=saved_args;
     348             : 
     349           1 :    update_details(trace);
     350           1 :    return exitcode;
     351             : }

Generated by: LCOV version 1.10