Subversion Repositories web_pages

Rev

Rev 20 | Show entire file | Ignore whitespace | Details | Blame | Last modification | View Log | RSS feed

Rev 20 Rev 21
Line 44... Line 44...
44
#     Added support for formats hash in router configuration
44
#     Added support for formats hash in router configuration
45
#     Modified makeVPNConfigFile to accept filename template with ROUTER and USER placeholders
45
#     Modified makeVPNConfigFile to accept filename template with ROUTER and USER placeholders
46
#     Added support for multiple OVPN files per user based on formats configuration
46
#     Added support for multiple OVPN files per user based on formats configuration
47
#     Formats structure allows specifying filename and additionalStrings per format
47
#     Formats structure allows specifying filename and additionalStrings per format
48
#     Expands \n in additionalStrings to actual newlines in config files
48
#     Expands \n in additionalStrings to actual newlines in config files
-
 
49
#  v1.1.1 2026-06-15 RWR
-
 
50
#     Decodes base64 OVPN content only once per user, not per format
-
 
51
#     Fixed bug in makeVPNConfigFile where content was being overwritten
-
 
52
#     Cleans out old QR code and OVPN files for the router before recreating them
49
 
53
 
50
use strict;
54
use strict;
51
use warnings;
55
use warnings;
52
 
56
 
53
# use libraries from the directory this script is in
57
# use libraries from the directory this script is in
Line 67... Line 71...
67
use GD::Barcode::QRcode; # for creating the QR code images
71
use GD::Barcode::QRcode; # for creating the QR code images
68
use MIME::Base64 qw( decode_base64 ); # for decoding the ovpn file returned from the API
72
use MIME::Base64 qw( decode_base64 ); # for decoding the ovpn file returned from the API
69
use File::Path qw( make_path ); # for creating directories
73
use File::Path qw( make_path ); # for creating directories
70
use Fcntl qw(:flock); # Import locking constants
74
use Fcntl qw(:flock); # Import locking constants
71
 
75
 
72
our $VERSION = '1.1.0';
76
our $VERSION = '1.1.1';
73
 
77
 
74
# Check if running as root
78
# Check if running as root
75
if ($> != 0) {
79
if ($> != 0) {
76
   die "Error: This script must be run as root.\n";
80
   die "Error: This script must be run as root.\n";
77
}
81
}
Line 200... Line 204...
200
   return '' unless $contents && $contents->{'content'};
204
   return '' unless $contents && $contents->{'content'};
201
   # Replace ROUTER and USER in the filename template
205
   # Replace ROUTER and USER in the filename template
202
   my $fileName = $filenameTemplate;
206
   my $fileName = $filenameTemplate;
203
   $fileName =~ s/ROUTER/$routerName/g;
207
   $fileName =~ s/ROUTER/$routerName/g;
204
   $fileName =~ s/USER/$userName/g;
208
   $fileName =~ s/USER/$userName/g;
-
 
209
   # modified to use a separate variable for the file contents since it was overwritten previously
205
   $contents->{'content'} = decode_base64($contents->{'content'});
210
   my $fileContents = $contents->{'content'};
206
   $contents->{'content'} .= "\n";
211
   $fileContents .= "\n";
207
   $contents->{'content'} =~ s/(\r?\n)+/\n/g; # normalize line endings
212
   $fileContents =~ s/(\r?\n)+/\n/g; # normalize line endings
208
   my $comment = '';
213
   my $comment = '';
209
   if ( $contents->{'content'} !~ /# Added by loadOpnSense.pl/ ) {
214
   if ( $fileContents !~ /# Added by opensense-totp-ovpn-export/ ) {
210
      $comment = "# Added by loadOpnSense.pl\n";
215
      $comment = "# Added by opensense-totp-ovpn-export\n";
211
   }
216
   }
212
   # Expand \n to actual newlines in additionalOvpnStrings
217
   # Expand \n to actual newlines in additionalOvpnStrings
213
   $additionalOvpnStrings =~ s/\\n/\n/g if $additionalOvpnStrings;
218
   $additionalOvpnStrings =~ s/\\n/\n/g if $additionalOvpnStrings;
214
   foreach my $string ( split( /\n/, $additionalOvpnStrings || '' ) ) {
219
   foreach my $string ( split( /\n/, $additionalOvpnStrings || '' ) ) {
215
      next if $string eq '';
220
      next if $string eq '';
216
      unless ( $contents->{'content'} =~ /\Q$string\E/ ) {
221
      unless ( $fileContents =~ /\Q$string\E/ ) {
217
         $contents->{'content'} .= "$comment$string\n";
222
         $fileContents .= "$comment$string\n";
218
         $comment = ''; # only add comment once
223
         $comment = ''; # only add comment once
219
      }
224
      }
220
   }
225
   }
221
   # This allows us to retain the relative file path for storage, but ensuring we write the file to 
226
   # This allows us to retain the relative file path for storage, but ensuring we write the file to 
222
   # the correct path even if we are not running the script from the script directory.
227
   # the correct path even if we are not running the script from the script directory.
223
   open my $out, '>', "$absDir/" . $fileName or die "Cannot write file $fileName to $absDir: $!";
228
   open my $out, '>', "$absDir/" . $fileName or die "Cannot write file $fileName to $absDir: $!";
224
   print $out $contents->{'content'};
229
   print $out $fileContents;
225
   close $out;
230
   close $out;
226
   return $ovpnLocation . '/' . $fileName;
231
   return $ovpnLocation . '/' . $fileName;
227
}
232
}
228
 
233
 
229
# cleanOldDataFiles: Deletes old data files in the specified directory matching the given pattern
234
# cleanOldDataFiles: Deletes old data files in the specified directory matching the given pattern
Line 370... Line 375...
370
   my $formats = $config->{'formats'};
375
   my $formats = $config->{'formats'};
371
   # die Dumper($config) . "\n";
376
   # die Dumper($config) . "\n";
372
   # die Dumper($formats) . "\n";
377
   # die Dumper($formats) . "\n";
373
   if ( $formats && ref($formats) eq 'HASH' && keys %$formats ) {
378
   if ( $formats && ref($formats) eq 'HASH' && keys %$formats ) {
374
      # Iterate through each format
379
      # Iterate through each format
-
 
380
      $cert->{'content'} = decode_base64( $cert->{'content'} ); # decode once for all formats
375
      foreach my $formatName ( keys %$formats ) {
381
      foreach my $formatName ( keys %$formats ) {
376
         my $format = $formats->{$formatName};
382
         my $format = $formats->{$formatName};
377
         next unless ref($format) eq 'HASH';
383
         next unless ref($format) eq 'HASH';
378
         my $filename = $format->{'filename'} || '';
384
         my $filename = $format->{'filename'} || '';
379
         my $additionalStrings = $format->{'additionalStrings'} || '';
385
         my $additionalStrings = $format->{'additionalStrings'} || '';