diff --git a/docs/index.html b/docs/index.html index 6889f66a..c77a9430 100644 --- a/docs/index.html +++ b/docs/index.html @@ -306,7 +306,7 @@ Error message and password prompt {"created":"20240712071211426","creator":"ibnux","title":"$:/state/tabs/controlpanel/toolbars-1345989671","text":"$:/core/ui/ControlPanel/Toolbars/PageControls","modified":"20240712071211426","modifier":"ibnux"}, {"title":"$:/status/RequireReloadDueToPluginChange","text":"no"}, {"created":"20240712071004482","creator":"i","title":"$:/status/UserName","text":"ibnux","modified":"20240712071005201","modifier":"ibnu"}, -{"title":"$:/StoryList","text":"","list":"GettingStarted"}, +{"title":"$:/StoryList","created":"20241009085621609","creator":"ibnux","text":"","list":"GettingStarted [[Integrated Radius System]]","modified":"20241009085621609","modifier":"ibnux"}, {"created":"20240712071159691","creator":"ibnux","title":"$:/theme","text":"$:/themes/tiddlywiki/snowwhite","modified":"20240713151537740","modifier":"ibnux"}, {"title":"$:/themes/tiddlywiki/readonly","name":"ReadOnly","author":"JeremyRuston","core-version":">=5.0.0","plugin-type":"theme","description":"Hides the ability to edit tiddlers","dependents":"$:/themes/tiddlywiki/snowwhite","version":"5.3.5","type":"application/json","text":"{\"tiddlers\":{\"$:/themes/tiddlywiki/readonly/styles.tid\":{\"title\":\"$:/themes/tiddlywiki/readonly/styles.tid\",\"tags\":\"[[$:/tags/Stylesheet]]\",\"text\":\"\\\\define button-selector(title)\\nbutton.$title$, .tc-drop-down button.$title$, div.$title$\\n\\\\end\\n\\n\\\\rules only filteredtranscludeinline transcludeinline macrodef macrocallinline\\n\\n\u003C\u003Cbutton-selector tc-btn-\\\\%24\\\\%3A\\\\%2Fcore\\\\%2Fui\\\\%2FButtons\\\\%2Fclone>>,\\n\u003C\u003Cbutton-selector tc-btn-\\\\%24\\\\%3A\\\\%2Fcore\\\\%2Fui\\\\%2FButtons\\\\%2Fdelete>>,\\n\u003C\u003Cbutton-selector tc-btn-\\\\%24\\\\%3A\\\\%2Fcore\\\\%2Fui\\\\%2FButtons\\\\%2Fedit>>,\\n\u003C\u003Cbutton-selector tc-btn-\\\\%24\\\\%3A\\\\%2Fcore\\\\%2Fui\\\\%2FButtons\\\\%2Fnew-here>>,\\n\u003C\u003Cbutton-selector tc-btn-\\\\%24\\\\%3A\\\\%2Fcore\\\\%2Fui\\\\%2FButtons\\\\%2Fnew-journal-here>>,\\n\u003C\u003Cbutton-selector tc-btn-\\\\%24\\\\%3A\\\\%2Fcore\\\\%2Fui\\\\%2FButtons\\\\%2Fimport>>,\\n\u003C\u003Cbutton-selector tc-btn-\\\\%24\\\\%3A\\\\%2Fcore\\\\%2Fui\\\\%2FButtons\\\\%2Fmanager>>,\\n\u003C\u003Cbutton-selector tc-btn-\\\\%24\\\\%3A\\\\%2Fcore\\\\%2Fui\\\\%2FButtons\\\\%2Fnew-image>>,\\n\u003C\u003Cbutton-selector tc-btn-\\\\%24\\\\%3A\\\\%2Fcore\\\\%2Fui\\\\%2FButtons\\\\%2Fnew-journal>>,\\n\u003C\u003Cbutton-selector tc-btn-\\\\%24\\\\%3A\\\\%2Fcore\\\\%2Fui\\\\%2FButtons\\\\%2Fnew-tiddler>> {\\n\\tdisplay: none;\\n}\"}}}"}, {"title":"$:/themes/tiddlywiki/snowwhite","name":"Snow White","author":"JeremyRuston","core-version":">=5.0.0","plugin-type":"theme","description":"Emphasises individual tiddlers","dependents":"$:/themes/tiddlywiki/vanilla","plugin-priority":"0","version":"5.3.5","type":"application/json","text":"{\"tiddlers\":{\"$:/themes/tiddlywiki/snowwhite/base\":{\"title\":\"$:/themes/tiddlywiki/snowwhite/base\",\"tags\":\"[[$:/tags/Stylesheet]]\",\"text\":\"\\\\define sidebarbreakpoint-minus-one()\\n\u003C$text text={{{ [{$:/themes/tiddlywiki/vanilla/metrics/sidebarbreakpoint}removesuffix[px]subtract[1]addsuffix[px]] ~[{$:/themes/tiddlywiki/vanilla/metrics/sidebarbreakpoint}] }}}/>\\n\\\\end\\n\\n\\\\rules only filteredtranscludeinline transcludeinline macrodef macrocallinline\\n\\n.tc-sidebar-header {\\n\\ttext-shadow: 0 1px 0 \u003C\u003Ccolour sidebar-foreground-shadow>>;\\n}\\n\\n.tc-tiddler-info {\\n\\t\u003C\u003Cbox-shadow \\\"inset 1px 2px 3px rgba(0,0,0,0.1)\\\">>\\n}\\n\\n@media screen {\\n\\t.tc-tiddler-frame {\\n\\t\\t\u003C\u003Cbox-shadow \\\"1px 1px 5px rgba(0, 0, 0, 0.3)\\\">>\\n\\t}\\n}\\n\\n@media (max-width: \u003C\u003Csidebarbreakpoint-minus-one>>) {\\n\\t.tc-tiddler-frame {\\n\\t\\t\u003C\u003Cbox-shadow none>>\\n\\t}\\n}\\n\\n.tc-page-controls button svg, .tc-tiddler-controls button svg, .tc-topbar button svg {\\n\\t\u003C\u003Ctransition \\\"fill 150ms ease-in-out\\\">>\\n}\\n\\n.tc-tiddler-controls button.tc-selected,\\n.tc-page-controls button.tc-selected {\\n\\t\u003C\u003Cfilter \\\"drop-shadow(0px -1px 2px rgba(0,0,0,0.25))\\\">>\\n}\\n\\n.tc-tiddler-frame input.tc-edit-texteditor,\\n.tc-tiddler-frame select.tc-edit-texteditor {\\n\\t\u003C\u003Cbox-shadow \\\"inset 0 1px 8px rgba(0, 0, 0, 0.15)\\\">>\\n}\\n\\n.tc-edit-tags {\\n\\t\u003C\u003Cbox-shadow \\\"inset 0 1px 8px rgba(0, 0, 0, 0.15)\\\">>\\n}\\n\\n.tc-tiddler-frame .tc-edit-tags input.tc-edit-texteditor {\\n\\t\u003C\u003Cbox-shadow \\\"none\\\">>\\n\\tborder: none;\\n\\toutline: none;\\n}\\n\\ntextarea.tc-edit-texteditor {\\n\\tfont-family: {{$:/themes/tiddlywiki/vanilla/settings/editorfontfamily}};\\n}\\n\\ncanvas.tc-edit-bitmapeditor {\\n\\t\u003C\u003Cbox-shadow \\\"2px 2px 5px rgba(0, 0, 0, 0.5)\\\">>\\n}\\n\\n.tc-drop-down {\\n\\tborder-radius: 4px;\\n\\t\u003C\u003Cbox-shadow \\\"2px 2px 10px rgba(0, 0, 0, 0.5)\\\">>\\n}\\n\\n.tc-block-dropdown {\\n\\tborder-radius: 4px;\\n\\t\u003C\u003Cbox-shadow \\\"2px 2px 10px rgba(0, 0, 0, 0.5)\\\">>\\n}\\n\\n.tc-modal {\\n\\tborder-radius: 6px;\\n\\t\u003C\u003Cbox-shadow \\\"0 3px 7px rgba(0,0,0,0.3)\\\">>\\n}\\n\\n.tc-modal-footer {\\n\\tborder-radius: 0 0 6px 6px;\\n\\t\u003C\u003Cbox-shadow \\\"inset 0 1px 0 #fff\\\">>;\\n}\\n\\n\\n.tc-alert {\\n\\tborder-radius: 6px;\\n\\t\u003C\u003Cbox-shadow \\\"0 3px 7px rgba(0,0,0,0.6)\\\">>\\n}\\n\\n.tc-notification {\\n\\tborder-radius: 6px;\\n\\t\u003C\u003Cbox-shadow \\\"0 3px 7px rgba(0,0,0,0.3)\\\">>\\n\\ttext-shadow: 0 1px 0 rgba(255,255,255, 0.8);\\n}\\n\\n.tc-sidebar-lists .tc-tab-set .tc-tab-divider {\\n\\tborder-top: none;\\n\\theight: 1px;\\n\\t\u003C\u003Cbackground-linear-gradient \\\"left, rgba(0,0,0,0.15) 0%, rgba(0,0,0,0.0) 100%\\\">>\\n}\\n\\n.tc-more-sidebar > .tc-tab-set > .tc-tab-buttons > button {\\n\\t\u003C\u003Cbackground-linear-gradient \\\"left, rgba(0,0,0,0.01) 0%, rgba(0,0,0,0.1) 100%\\\">>\\n}\\n\\n.tc-more-sidebar > .tc-tab-set > .tc-tab-buttons > button.tc-tab-selected {\\n\\t\u003C\u003Cbackground-linear-gradient \\\"left, rgba(0,0,0,0.05) 0%, rgba(255,255,255,0.05) 100%\\\">>\\n}\\n\\n.tc-message-box img {\\n\\t\u003C\u003Cbox-shadow \\\"1px 1px 3px rgba(0,0,0,0.5)\\\">>\\n}\\n\\n.tc-plugin-info {\\n\\t\u003C\u003Cbox-shadow \\\"1px 1px 3px rgba(0,0,0,0.5)\\\">>\\n}\\n\"}}}"}, @@ -322,7 +322,7 @@ Error message and password prompt {"created":"20240715042750725","creator":"ibnux","text":"Hotspot Plan is the Internet Plan you sell to customer.\n\n* ''Status'' is where you can enable or disable Internet Plan, Admin can activate the Internet Plan, but Customer cannot buy it, it will not show in the order page Customer, Customer can recharge it.\n* ''Type'' is to set is Prepaid Plan or Postpaid Plan. if it PostPaid, it will only have Period Validity and fix expired date.\n* ''Plan Type '' is to set wether Internet Plan for Personal Customer or Business Customer\n* ''Radius'' is this Plan for radius system then check it\n* ''Device'' is the logic how PHPNuxBill Talk to Mikrotik or Radius or other Device. Choose wisely, Hotspot plan choose the Hotspot Device, or Radius if it Radius Plan.\n\n** ''Dummy'' will not do anything, some user just need PHPNuxBill just for tracking sales.\n** ''MikrotikHotspot'' for Hotspot Plan\n** ''MikrotikPppoe'' for PPPOE Plan\n** ''Radius'' for [[Radius System with Mysql]]\n** ''RadiusRest'' for [[Integrated Radius System]]\n* ''Bandwidth Name'' is your Bandwidth Plan for Internet Plan\n* ''Shared Users'' 1 account can be used for how many devices can be online\n* ''Plan Validity'' How long Plan will be expired?\n* ''Router Name'' if it not Radius, you must select which Mikrotik will have this Hotspot Plan\n* ''IP Pool'' is [ext[IP Pool|../?_route=pool/list]] you created before. \n\nAfter you save it, you can customize another options\n\n* ''Expired Internet Plan'', if customer plan expired, it will move to this plan, you need to create Expired plan first, and the expired plan set expired plan to expired plan too. //''Default''// just remove the customer from Mikrotik.\n* ''on-login / on-up'' is helper to add custome script to Mikrotik\n* ''on-logout / on-down'' is helper to add custome script to Mikrotik\n\n\u003Cbutton>[[Back|Hotspot System]]\u003C/button>","title":"Create PPPOE Plan","modified":"20240715043523134","modifier":"ibnux"}, {"created":"20240712072200400","creator":"ibnux","text":"! ''Congratulations!!''\n\nNow you already install PHPNuxBill\n\nWhere to go now?\n\nConfigure The PHPNuxBill as you need, go to [ext[Settings|../index.php?_route=settings/app]], after that got to [ext[Localisation|../index.php?_route=settings/localisation]].\n\nAfter that, which one do you want to accomplish?\n\n*\u003Cbutton>[[Hotspot System]]\u003C/button> ^^most user just need this^^\n** Voucher system with or without Registration (''Activation'')\n** Payment Gateway only with Registration\n** Prepaid and or Postpaid system\n** 1 plan for 1 router \n\n* \u003Cbutton>[[PPPOE System]]\u003C/button>\n** Voucher system and or Payment Gateway\n** ''Only with Registration''\n** Prepaid and or Postpaid system\n** 1 plan for 1 router\n\n* \u003Cbutton>[[Radius System with Mysql]]\u003C/button> ^^Advanced^^\n** Hotspot and or PPPOE\n** Voucher system with or without Registration (Activation)\n** Payment Gateway only with Registration\n** Prepaid and or Postpaid system\n** PPPOE only with Registration\n** ''1 Plan for Multiple Router''\n\n* \u003Cbutton>[[Integrated Radius System]]\u003C/button> ^^Easy^^\n** Hotspot and or PPPOE\n** Voucher system with or without Registration\u003Cbr>(Activation or ''Direct voucher login'')\n** Payment Gateway only with Registration\n** Prepaid and or Postpaid system\n** PPPOE only with Registration\n** 1 Plan for Multiple Router\n\nAlthough all the system can run together, you need to setup one by one\n\nVoucher or Payment Gateway, just follow above tutorial, it will Guide you.\n\n\u003C\u003C\u003C\nIf you like PHPNuxBill, don't forget to [ext[donate|index.php?_route=community]] some of your profits to this project.\n\u003C\u003C\u003C\n\n!! Other Features\n\n* [[Additional Billing]]\n* [[Creating Theme|https://github.com/hotspotbilling/phpnuxbill/wiki/Themes]]\n\n!! Mikrotik Template\n\n* [[Simple Template|https://github.com/hotspotbilling/phpnuxbill-mikrotik-login-template/]]\n* [[Redirect Directly to PHPNuxBill|https://github.com/agstrxyz/phpnuxbill-login-hotspot]]\n","title":"GettingStarted","modified":"20240729072718586","modifier":"ibnux","tags":"","type":"text/vnd.tiddlywiki"}, {"created":"20240712084946106","creator":"ibnux","text":"!Step to create Hotspot Plan\n\nHotspot System based on the Mikrotik Feature inside `IP > Hotspot`, You need to configure it first.\n\n\n!! For [[Radius System with Mysql]]\n \n# [[Add NAS]]\n# [[Create Bandwidth Plan]]\n# [[Create Hotspot Plan]]\n\n!! For [[Integrated Radius System]]\n\n# [[Create Bandwidth Plan]]\n# [[Create Hotspot Plan]]\n\n!! Without Radius\n\n# [[Add Mikrotik]]\n# [[Create Bandwidth Plan]]\n# [[Create Hotspot Plan]]\n\nAfter That, how do you want to sell Internet Plan?\n\n* Customer self services buy internet using Payment Gateway\n* Customer Buy Voucher and activate it at PHPNuxBill\n\nWhich one do you want?\n\n\u003Cbutton>[[Payment Gateway]]\u003C/button> \u003Cbutton>[[Internet Voucher]]\u003C/button>\n","title":"Hotspot System","modified":"20240714053827041","modifier":"ibnux"}, -{"created":"20240712080714532","creator":"ibnux","text":"Radius System is complicated, But with [[REST API|https://www.google.com/search?q=REST+API]] is Easy enough.\n\nFreeradius REST API is configuration to make Freeradius talk to PHPNuxBill via HTTP Connection, configuration is more simple.\n\nWith Freeradius REST, it will use current PHPNuxBill Core, and you don't need IP Public for Mikrotik, but still need static IP, as the IP need to be registered to clients.conf, or [[allow all IP|https://serverfault.com/questions/114780/is-there-a-way-to-allow-all-external-ip-connections-in-freeradius]], but be careful.\n\n\u003C\u003C\u003C\nFor now is only support PAP Authentication, i am still working with CHAP\n\u003C\u003C\u003C\n\n\u003C\u003C\u003C\nPassword can be sniffed when login to Mikrotik if using PAP\n\u003C\u003C\u003C\n\n```\n \n ┌──────────────┐\n │ PHPNUXBILL │\n └──────────────┘\n ▲ \n │ \n ▼ \n ┌──────────────┐\n │ Freeradius │\n └──────────────┘\n ▲ \n │ \n ▼ \n ┌──────────┐ \n │ Mikrotik │ \n └──────────┘ \n```\n\n!! Installing freeradius\n\nThis Tutorial tested in Ubuntu 20.04 and 22.04\n\n`apt-get -y install freeradius freeradius-rest`\n\nedit clients.conf\n\n`nano /etc/freeradius/3.0/clients.conf`\n\nAdd your Mikrotik IP or your Public IP, this is example\n\n\u003C\u003C\u003C\neverytime you add/edit Client, restart freeradius\n\u003C\u003C\u003C\n\n```\nclient myRouterA {\n\tipaddr\t\t= 10.0.1.0/24\n\tsecret\t\t= verysecret\n}\n\nclient myRouterB {\n\tipaddr\t\t= 10.0.2.0/24\n\tsecret\t\t= secretvery\n}\n```\n\nor allow all IP\n\n```\n# All IPv4\nclient 0.0.0.0/0 {\n secret = verysecret\n}\n# All IPv6\nclient ::/0 {\n secret = secretvery\n}\n```\n\nCreate rest Configuration\n\n`nano /etc/freeradius/3.0/mods-enabled/rest`\n\nuse this configuration, change phpnuxbill.domain with your domain\n\n```\nrest {\n tls {\n # ca_file = ${certdir}/ca.pem\n\t\t# ca_info_file = ${certdir}/cacert_bundle.pem\n\t\t# ca_path = ${certdir}\n check_cert = no\n check_cert_cn = no\n }\n\tconnect_uri = \"https://phpnuxbill.domain/radius.php\"\n\n\tauthenticate {\n\t\turi = \"${..connect_uri}?action=authenticate\"\n method = 'post'\n body = 'post'\n data = \"username=%{urlquote:%{User-Name}}&password=%{urlquote:%{User-Password}}&CHAPchallenge=%{urlquote:%{CHAP-Challenge}}&CHAPassword=%{urlquote:%{CHAP-Password}}&realm=%{urlquote:%{Mikrotik-Realm}}&macAddr=%{urlquote:%{Calling-Station-Id}}&nasip=%{urlquote:%{NAS-IP-Address}}\"\n\t\ttls = ${..tls}\n\t}\n\n authorize {\n uri = \"${..connect_uri}?action=authorize\"\n method = 'post'\n body = 'post'\n data = \"username=%{urlquote:%{User-Name}}&password=%{urlquote:%{User-Password}}&CHAPchallenge=%{urlquote:%{CHAP-Challenge}}&CHAPassword=%{urlquote:%{CHAP-Password}}&realm=%{urlquote:%{Mikrotik-Realm}}&macAddr=%{urlquote:%{Calling-Station-Id}}&nasip=%{urlquote:%{NAS-IP-Address}}\"\n\t\ttls = ${..tls}\n }\n\n\taccounting {\n\t\turi = \"${..connect_uri}?action=accounting\"\n\t\tmethod = 'post'\n\t\tbody = 'post'\n data = \"username=%{urlquote:%{User-Name}}&nasIpAddress=%{urlquote:%{NAS-IP-Address}}&realm=%{urlquote:%{Mikrotik-Realm}}&nasid=%{urlquote:%{NAS-Identifier}}\\\n&acctSessionId=%{urlquote:%{Acct-Session-Id}}&macAddr=%{urlquote:%{Calling-Station-Id}}&acctSessionTime=%{urlquote:%{Acct-Session-Time}}\\\n&acctInputOctets=%{urlquote:%{Acct-Input-Octets}}&acctOutputOctets=%{urlquote:%{Acct-Output-Octets}}\\\n&acctInputGigawords=%{urlquote:%{Acct-Input-Gigawords}}&acctOutputGigawords=%{urlquote:%{Acct-Output-Gigawords}}\\\n&acctInputPackets=%{urlquote:%{Acct-Input-Packets}}&acctOutputPackets=%{urlquote:%{Acct-Output-Packets}}\\\n&nasPortId=%{urlquote:%{NAS-Port-Id}}&framedIPAddress=%{urlquote:%{Framed-IP-Address}}\\\n&sessionTimeout=%{urlquote:%{Session-Timeout}}&framedIPNetmask=%{urlquote:%{Framed-IP-Netmask}}\\\n&acctStatusType=%{urlquote:%{Acct-Status-Type}}&nasPortType=%{urlquote:%{NAS-Port-Type}}\"\n\t\ttls = ${..tls}\n\t}\n\n post-auth {\n uri = \"${..connect_uri}?action=post-auth\"\n method = 'post'\n body = 'post'\n data = \"username=%{urlquote:%{User-Name}}\"\n\t\ttls = ${..tls}\n }\n\n\tpool {\n\t\tstart = ${thread[pool].start_servers}\n\t\tmin = ${thread[pool].min_spare_servers}\n\t\tmax = ${thread[pool].max_servers}\n\t\tspare = ${thread[pool].max_spare_servers}\n\t\tuses = 0\n\t\tretry_delay = 30\n\t\tlifetime = 0\n\t\tidle_timeout = 60\n\t}\n}\n```\n\nedit sites\n\n`nano /etc/freeradius/3.0/sites-enabled/default `\n\nConfigure just like this, don't delete others\n\n```\nauthorize {\n# filter_username\n#\tfilter_password\n#\tpreprocess\n#\toperator-name\n#\tcui\n#\tauth_log\n\trest\n if (ok) {\n update control {\n Auth-Type := rest\n }\n }\n\n ....\n}\n\nauthenticate {\n Auth-Type rest {\n rest {\n updated = 1\n }\n if (updated) {\n ok\n }\n }\n\tAuth-Type rest {\n\t\trest\n\t}\n\n ....\n}\n\naccounting {\n\tdetail\n\trest\n\n ....\n}\n\nsession {\n\tradutmp\n \n ....\n}\n\npost-auth {\n\tif (reply:Group-Name) {\n update control {\n &Group := \"%{reply:Group-Name}\"\n }\n }\n if (reply:Mikrotik-Rate-Limit) {\n update reply {\n Mikrotik-Rate-Limit := \"%{reply:Mikrotik-Rate-Limit}\"\n }\n }\n if (reply:Expiration) {\n update reply {\n Expiration := \"%{reply:Expiration}\"\n }\n }\n\tupdate {\n\t\t&reply: += &session-state:\n\t}\n}\n```\n\nrestart services\n\n`systemctl restart freeradius.service`\n\n!! DEBUG\n\nTo check if someting wrong, stop freeradius\n\n`systemctl stop freeradius.service`\n\nActivate log in Mikrotik\n\n`/system logging add topics=radius,debug action=memory`\n\nrun radius just like this\n\n`freeradius -X`\n\nthen try to login\n\n!! Next\n\nGo to [ext[Settings|../index.php?_route=settings/app]] and Enable Radius.\n\nYou want to sell Hotspot or PPPOE?\n\n * [[Hotspot System]]\n * [[PPPOE System]]\n","title":"Integrated Radius System","modified":"20240713053828920","modifier":"ibnux","tags":"[[radius rest]]"}, +{"created":"20240712080714532","creator":"ibnux","text":"Radius System is complicated, But with [[REST API|https://www.google.com/search?q=REST+API]] is Easy enough.\n\nFreeradius REST API is configuration to make Freeradius talk to PHPNuxBill via HTTP Connection, configuration is more simple.\n\nWith Freeradius REST, it will use current PHPNuxBill Core, and you don't need IP Public for Mikrotik, but still need static IP, as the IP need to be registered to clients.conf, or [[allow all IP|https://serverfault.com/questions/114780/is-there-a-way-to-allow-all-external-ip-connections-in-freeradius]], but be careful.\n\n\u003C\u003C\u003C\nFor now is only support PAP Authentication, i am still working with CHAP\n\u003C\u003C\u003C\n\n\u003C\u003C\u003C\nPassword can be sniffed when login to Mikrotik if using PAP\n\u003C\u003C\u003C\n\n```\n \n ┌──────────────┐\n │ PHPNUXBILL │\n └──────────────┘\n ▲ \n │ \n ▼ \n ┌──────────────┐\n │ Freeradius │\n └──────────────┘\n ▲ \n │ \n ▼ \n ┌──────────┐ \n │ Mikrotik │ \n └──────────┘ \n```\n\n!! Installing freeradius\n\nThis Tutorial tested in Ubuntu 20.04 and 22.04\n\n`apt-get -y install freeradius freeradius-rest`\n\nedit clients.conf\n\n`nano /etc/freeradius/3.0/clients.conf`\n\nAdd your Mikrotik IP or your Public IP, this is example\n\n\u003C\u003C\u003C\neverytime you add/edit Client, restart freeradius\n\u003C\u003C\u003C\n\n```\nclient myRouterA {\n\tipaddr\t\t= 10.0.1.0/24\n\tsecret\t\t= verysecret\n}\n\nclient myRouterB {\n\tipaddr\t\t= 10.0.2.0/24\n\tsecret\t\t= secretvery\n}\n```\n\nor allow all IP\n\n```\n# All IPv4\nclient 0.0.0.0/0 {\n secret = verysecret\n}\n# All IPv6\nclient ::/0 {\n secret = secretvery\n}\n```\n\nCreate rest Configuration\n\n`nano /etc/freeradius/3.0/mods-enabled/rest`\n\nuse this configuration, change phpnuxbill.domain with your domain, copy all this configuration\n\n```\nrest {\n tls {\n # ca_file = ${certdir}/ca.pem\n\t\t# ca_info_file = ${certdir}/cacert_bundle.pem\n\t\t# ca_path = ${certdir}\n check_cert = no\n check_cert_cn = no\n }\n\tconnect_uri = \"https://phpnuxbill.domain/radius.php\"\n\n\tauthenticate {\n\t\turi = \"${..connect_uri}?action=authenticate\"\n method = 'post'\n body = 'post'\n data = \"username=%{urlquote:%{User-Name}}&password=%{urlquote:%{User-Password}}&CHAPchallenge=%{urlquote:%{CHAP-Challenge}}&CHAPassword=%{urlquote:%{CHAP-Password}}&nasid=%{urlquote:%{NAS-Identifier}}&realm=%{urlquote:%{Mikrotik-Realm}}&macAddr=%{urlquote:%{Calling-Station-Id}}&nasip=%{urlquote:%{NAS-IP-Address}}\"\n\t\ttls = ${..tls}\n\t}\n\n authorize {\n uri = \"${..connect_uri}?action=authorize\"\n method = 'post'\n body = 'post'\n data = \"username=%{urlquote:%{User-Name}}&password=%{urlquote:%{User-Password}}&CHAPchallenge=%{urlquote:%{CHAP-Challenge}}&CHAPassword=%{urlquote:%{CHAP-Password}}&nasid=%{urlquote:%{NAS-Identifier}}&realm=%{urlquote:%{Mikrotik-Realm}}&macAddr=%{urlquote:%{Calling-Station-Id}}&nasip=%{urlquote:%{NAS-IP-Address}}\"\n\t\ttls = ${..tls}\n }\n\n\taccounting {\n\t\turi = \"${..connect_uri}?action=accounting\"\n\t\tmethod = 'post'\n\t\tbody = 'post'\n data = \"username=%{urlquote:%{User-Name}}&nasIpAddress=%{urlquote:%{NAS-IP-Address}}&realm=%{urlquote:%{Mikrotik-Realm}}&nasid=%{urlquote:%{NAS-Identifier}}\\\n&acctSessionId=%{urlquote:%{Acct-Session-Id}}&macAddr=%{urlquote:%{Calling-Station-Id}}&acctSessionTime=%{urlquote:%{Acct-Session-Time}}\\\n&acctInputOctets=%{urlquote:%{Acct-Input-Octets}}&acctOutputOctets=%{urlquote:%{Acct-Output-Octets}}\\\n&acctInputGigawords=%{urlquote:%{Acct-Input-Gigawords}}&acctOutputGigawords=%{urlquote:%{Acct-Output-Gigawords}}\\\n&acctInputPackets=%{urlquote:%{Acct-Input-Packets}}&acctOutputPackets=%{urlquote:%{Acct-Output-Packets}}\\\n&nasPortId=%{urlquote:%{NAS-Port-Id}}&framedIPAddress=%{urlquote:%{Framed-IP-Address}}\\\n&sessionTimeout=%{urlquote:%{Session-Timeout}}&framedIPNetmask=%{urlquote:%{Framed-IP-Netmask}}\\\n&acctStatusType=%{urlquote:%{Acct-Status-Type}}&nasPortType=%{urlquote:%{NAS-Port-Type}}\"\n\t\ttls = ${..tls}\n\t}\n\n post-auth {\n uri = \"${..connect_uri}?action=post-auth\"\n method = 'post'\n body = 'post'\n data = \"username=%{urlquote:%{User-Name}}\"\n\t\ttls = ${..tls}\n }\n\n\tpool {\n\t\tstart = ${thread[pool].start_servers}\n\t\tmin = ${thread[pool].min_spare_servers}\n\t\tmax = ${thread[pool].max_servers}\n\t\tspare = ${thread[pool].max_spare_servers}\n\t\tuses = 0\n\t\tretry_delay = 30\n\t\tlifetime = 0\n\t\tidle_timeout = 60\n\t}\n}\n```\n\nedit sites\n\n`nano /etc/freeradius/3.0/sites-enabled/default `\n\nConfigure just like this, don't delete others, just set what it need\n\n```\nauthorize {\n# filter_username\n#\tfilter_password\n#\tpreprocess\n#\toperator-name\n#\tcui\n#\tauth_log\n\trest\n if (ok) {\n update control {\n Auth-Type := rest\n }\n }\n\n ....\n}\n\nauthenticate {\n Auth-Type rest {\n rest {\n updated = 1\n }\n if (updated) {\n ok\n }\n }\n\tAuth-Type rest {\n\t\trest\n\t}\n\n ....\n}\n\naccounting {\n\tdetail\n\trest\n\n ....\n}\n\nsession {\n\tradutmp\n \n ....\n}\n\npost-auth {\n\tif (reply:Group-Name) {\n update control {\n &Group := \"%{reply:Group-Name}\"\n }\n }\n if (reply:Mikrotik-Rate-Limit) {\n update reply {\n Mikrotik-Rate-Limit := \"%{reply:Mikrotik-Rate-Limit}\"\n }\n }\n if (reply:Expiration) {\n update reply {\n Expiration := \"%{reply:Expiration}\"\n }\n }\n\tupdate {\n\t\t&reply: += &session-state:\n\t}\n}\n```\n\nrestart services\n\n`systemctl restart freeradius.service`\n\n!! DEBUG\n\nTo check if someting wrong, stop freeradius\n\n`systemctl stop freeradius.service`\n\nActivate log in Mikrotik\n\n`/system logging add topics=radius,debug action=memory`\n\nrun radius just like this\n\n`freeradius -X`\n\nthen try to login\n\n!! Next\n\nGo to [ext[Settings|../index.php?_route=settings/app]] and Enable Radius.\n\nYou want to sell Hotspot or PPPOE?\n\n * [[Hotspot System]]\n * [[PPPOE System]]\n","title":"Integrated Radius System","modified":"20241009085747300","modifier":"ibnux","tags":"[[radius rest]]"}, {"created":"20240714052949493","creator":"ibnux","text":"There's 3 Voucher version\n\n!! With customer registration\n\nPHPNuxBill Voucher is to activate internet plan for an account.\n\nCustomer must register, then buy Voucher from some place you sell, then activate the voucher. \n\n[ext[Create Voucher|../?_route=plan/voucher]] based your already created Plan.\n\n!! Without Registration\n\nIs not actually without registration, it will register only username, and the voucher will be password, From Hotspot Login, customer need to redirect to PHPNuxBill, then activate the voucher, then they can login for Internet.\n\n# Go to [ext[Settings|../?_route=settings/app]]\n# Disable Registration at Voucher Settings\n# [ext[Create Voucher|../?_route=plan/voucher]] based your already created Plan.\n\n\n!! Voucher direct login\n\nFor Voucher directly login from Mikrotik Hotspot Login without activation, you need to use [[Integrated Radius System]], customer no need to activate voucher, as long username same as password it will detected as Voucher, automatically activate the voucher\n\nJust [ext[Create Voucher|../?_route=plan/voucher]] based your already created Plan. This will run together with PHPNuxBill Customer system, you can sell voucher directly, with or without Registration system.\n\nOnly Plan with Radius selected as Router will be activated as Voucher.\n","title":"Internet Voucher","modified":"20240715063639438","modifier":"ibnux"}, {"created":"20240713063147852","creator":"ibnux","text":"i don't have any Template\n\nthis is example:\nhttps://github.com/hotspotbilling/phpnuxbill-mikrotik-login-template\n\nCustomer need to register at PHPNuxBill, so you need to add link on Mikrotik Login page, just add anywhere this link on Mikrotik Login page, this link, change domain to your server IP or Domain.\n\n```\n\u003Ca href=\"http://domain/?nux-mac=$(mac-esc)&nux-ip=$(ip)&nux-router=1\" class=\"btn btn-block btn-success\">Register\u003Ca>\n```\n\n`?nux-mac=$(mac-esc)&nux-ip=$(ip)&nux-router=1` this will help user to auto login from User Dashboard\n\n''nux-router ''is Optional, See mikrotik ID in `Networks -> Routers`, it will make Customer show only Package for that Router/Location only, if you have multiple location","title":"Mikrotik Login Template","modified":"20240713063350641","modifier":"ibnux"}, {"created":"20240713062428411","creator":"ibnux","text":"Customer just self services, Customer register to get an account, Order the plan and automatically activate for the account.\n\nThen customer just login to Internet with account they register it.\n\nThis need Payment Gateway, PHPNuxBill can support multiple Payment Gateway.\n\nGo to [ext[Plugin Manager|../?_route=pluginmanager]], and install Payment Gateway you need\n\nThen go to [ext[Payment Gateway Settings|../?_route=paymentgateway]], You can activate Multiple Payment Gateway, configure it based the payment Gateway settings, and add it to walled Garden.\n\nDone, you now can selling Internet services.\n\nbut maybe you need to configure [[Mikrotik Login Template]], ","title":"Payment Gateway","modified":"20240714053605590","modifier":"ibnux"}, diff --git a/radius.php b/radius.php index b14c5551..2b4547fe 100644 --- a/radius.php +++ b/radius.php @@ -42,7 +42,7 @@ try { $CHAPchallenge = _req('CHAPchallenge'); $isCHAP = false; if (!empty($CHAPassword)) { - $c = ORM::for_table('tbl_customers')->select('password')->select('pppoe_password')->whereRaw("BINARY `username` = '$username'")->find_one(); + $c = ORM::for_table('tbl_customers')->select('password')->select('pppoe_password')->whereRaw("BINARY username = '$username'")->find_one(); if ($c) { if (Password::chap_verify($c['password'], $CHAPassword, $CHAPchallenge)) { $password = $c['password']; @@ -111,7 +111,7 @@ try { $username = Text::alphanumeric($username, "-_.,"); $d = ORM::for_table('tbl_voucher')->whereRaw("BINARY `code` = '$username'")->find_one(); } else { - $d = ORM::for_table('tbl_customers')->whereRaw("BINARY `username` = '$username'")->find_one(); + $d = ORM::for_table('tbl_customers')->whereRaw("BINARY username = '$username'")->find_one(); if ($d['password'] != $password) { if ($d['pppoe_password'] != $password) { unset($d); @@ -136,7 +136,7 @@ try { $CHAPchallenge = _req('CHAPchallenge'); $isCHAP = false; if (!empty($CHAPassword)) { - $c = ORM::for_table('tbl_customers')->select('password')->select('pppoe_password')->whereRaw("BINARY `username` = '$username'")->find_one(); + $c = ORM::for_table('tbl_customers')->select('password')->select('pppoe_password')->whereRaw("BINARY username = '$username'")->find_one(); if ($c) { if (Password::chap_verify($c['password'], $CHAPassword, $CHAPchallenge)) { $password = $c['password']; @@ -201,10 +201,10 @@ try { ], 401); } } - $tur = ORM::for_table('tbl_user_recharges')->whereRaw("BINARY `username` = '$username'")->find_one(); + $tur = ORM::for_table('tbl_user_recharges')->whereRaw("BINARY username = '$username'")->find_one(); if ($tur) { if (!$isVoucher && !$isCHAP) { - $d = ORM::for_table('tbl_customers')->select('password')->select('pppoe_password')->whereRaw("BINARY `username` = '$username'")->find_one(); + $d = ORM::for_table('tbl_customers')->select('password')->select('pppoe_password')->whereRaw("BINARY username = '$username'")->find_one(); if ($d) { if ($d['password'] != $password) { if ($d['pppoe_password'] != $password) { @@ -233,7 +233,7 @@ try { $v->status = "1"; $v->used_date = date('Y-m-d H:i:s'); $v->save(); - $tur = ORM::for_table('tbl_user_recharges')->whereRaw("BINARY `username` = '$username'")->find_one(); + $tur = ORM::for_table('tbl_user_recharges')->whereRaw("BINARY username = '$username'")->find_one(); if ($tur) { process_radiust_rest($tur, $code); } else { @@ -264,54 +264,22 @@ try { } header("HTTP/1.1 200 ok"); $d = ORM::for_table('rad_acct') - ->whereRaw("BINARY `username` = '$username'") - ->where('acctstatustype', _post('acctStatusType')) + ->whereRaw("BINARY username = '$username'") + ->where('acctsessionid', _post('acctsessionid')) ->findOne(); if (!$d) { $d = ORM::for_table('rad_acct')->create(); } $acctOutputOctets = _post('acctOutputOctets', 0); $acctInputOctets = _post('acctInputOctets', 0); - if (_post('acctStatusType') == 'Stop') { - // log in the Start only - $start = ORM::for_table('rad_acct') - ->whereRaw("BINARY `username` = '$username'") - ->where('acctstatustype', 'Start') - ->findOne(); - if (!$start) { - $start = ORM::for_table('rad_acct')->create(); - } - if ($acctOutputOctets !== false && $acctInputOctets !== false) { - $start->acctOutputOctets += intval($acctOutputOctets); - $start->acctInputOctets += intval($acctInputOctets); - } else { - $start->acctOutputOctets = 0; - $start->acctInputOctets = 0; - } - $start->acctsessionid = _post('acctSessionId'); - $start->username = $username; - $start->realm = _post('realm'); - $start->nasipaddress = _post('nasip'); - $start->nasid = _post('nasid'); - $start->nasportid = _post('nasPortId'); - $start->nasporttype = _post('nasPortType'); - $start->framedipaddress = _post('framedIPAddress'); - $start->acctstatustype = _post('acctStatusType'); - $start->macaddr = _post('macAddr'); - $start->dateAdded = date('Y-m-d H:i:s'); - $start->save(); + if ($acctOutputOctets !== false && $acctInputOctets !== false) { + $d->acctOutputOctets += intval($acctOutputOctets); + $d->acctInputOctets += intval($acctInputOctets); + } else { $d->acctOutputOctets = 0; $d->acctInputOctets = 0; - } else { - if ($acctOutputOctets !== false && $acctInputOctets !== false) { - $d->acctOutputOctets += intval($acctOutputOctets); - $d->acctInputOctets += intval($acctInputOctets); - } else { - $d->acctOutputOctets = 0; - $d->acctInputOctets = 0; - } } - $d->acctsessionid = _post('acctSessionId'); + $d->acctSessionId = _post('acctSessionId'); $d->username = $username; $d->realm = _post('realm'); $d->nasipaddress = _post('nasip'); @@ -324,7 +292,7 @@ try { $d->dateAdded = date('Y-m-d H:i:s'); $d->save(); if (_post('acctStatusType') == 'Start') { - $tur = ORM::for_table('tbl_user_recharges')->whereRaw("BINARY `username` = '$username'")->where('status', 'on')->where('routers', 'radius')->find_one(); + $tur = ORM::for_table('tbl_user_recharges')->whereRaw("BINARY username = '$username'")->where('status', 'on')->where('routers', 'radius')->find_one(); $plan = ORM::for_table('tbl_plans')->where('id', $tur['plan_id'])->find_one(); if ($plan['limit_type'] == "Data_Limit" || $plan['limit_type'] == "Both_Limit") { $totalUsage = $d['acctOutputOctets'] + $d['acctInputOctets']; @@ -364,7 +332,11 @@ function process_radiust_rest($tur, $code) global $config; $plan = ORM::for_table('tbl_plans')->where('id', $tur['plan_id'])->find_one(); $bw = ORM::for_table("tbl_bandwidth")->find_one($plan['id_bw']); - $USRon = ORM::for_table('radacct')->where('username', $tur['username'])->where_raw("acctstoptime IS NULL")->count(); + // Count User Onlines + $USRon = ORM::for_table('rad_acct') + ->where('username', $tur['username']) + ->where("acctStatusType", 'Start') + ->count(); if ($USRon >= $plan['shared_users'] && $plan['type'] == 'Hotspot') { show_radius_result(["control:Auth-Type" => "Accept", 'Reply-Message' => 'You are already logged in - access denied ('.$USRon.')'], 401); } @@ -407,7 +379,7 @@ function process_radiust_rest($tur, $code) if ($plan['typebp'] == "Limited") { if ($plan['limit_type'] == "Data_Limit" || $plan['limit_type'] == "Both_Limit") { - $raddact = ORM::for_table('rad_acct')->whereRaw("BINARY `username` = '$tur[username]'")->where('acctstatustype', 'Start')->find_one(); + $raddact = ORM::for_table('rad_acct')->whereRaw("BINARY username = '$tur[username]'")->where('acctstatustype', 'Start')->find_one(); $totalUsage = intval($raddact['acctOutputOctets']) + intval($raddact['acctInputOctets']); $attrs['reply:Mikrotik-Total-Limit'] = Text::convertDataUnit($plan['data_limit'], $plan['data_unit']) - $totalUsage; if ($attrs['reply:Mikrotik-Total-Limit'] < 0) { diff --git a/system/lan/english.json b/system/lan/english.json index 81315026..5b2f2dfb 100644 --- a/system/lan/english.json +++ b/system/lan/english.json @@ -725,5 +725,10 @@ "Customer_will_reply_email_to_this_address__empty_if_you_want_to_use_From_Address": "Customer will reply email to this address, empty if you want to use From Address", "You_will_get_Payment_and_Error_notification": "You will get Payment and Error notification", "Languge_set_to_english": "Bahasa diatur ke bahasa Inggris", - "Forgot_Password": "Forgot Password" + "Forgot_Password": "Forgot Password", + "_Are_You_Sure_": "Are You Sure?", + "Send_your_balance___": "Send your balance ?", + "Search_Users": "Search Users", + "Theme_Voucher": "Theme Voucher", + "Payment_Info": "Payment Info" } \ No newline at end of file