├── tests.edn ├── .gitignore ├── CHANGELOG.md ├── project.clj ├── test └── can │ ├── bitmask_test.cljc │ └── can_test.cljc ├── src └── can │ ├── can.cljc │ └── bitmask.cljc ├── README.md └── LICENSE /tests.edn: -------------------------------------------------------------------------------- 1 | #kaocha/v1 2 | {:tests [{:id :unit-cljs 3 | :type :kaocha.type/cljs}]} 4 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | *.class 2 | *.jar 3 | *.swp 4 | .classpath 5 | .cljs_node_repl/ 6 | .hg/ 7 | .hgignore 8 | .project 9 | .settings/ 10 | /.lein-* 11 | /.nrepl-port 12 | /checkouts 13 | /classes 14 | /node_modules 15 | /target 16 | out/ 17 | package-lock.json 18 | pom.xml 19 | pom.xml.asc 20 | profiles.clj 21 | -------------------------------------------------------------------------------- /CHANGELOG.md: -------------------------------------------------------------------------------- 1 | # Changelog 2 | 3 | ## Unreleased 4 | ### New features 5 | 6 | * `can.can/allow?` supports domain-only checks; this simplifies code that 7 | checks whether a domain is (generally) permissible, e.g., to determine 8 | whether to display the admin UI (of admin domain). While this could be 9 | done with `(contains? permissions domain-key)`, the intent is clearer 10 | with `can.can/allow? permissions domain-key)`. 11 | -------------------------------------------------------------------------------- /project.clj: -------------------------------------------------------------------------------- 1 | (defproject can "0.4.0-SNAPSHOT" 2 | :description "Permissions library for Clojure[Script]" 3 | :url "https://github.com/shaolang/can" 4 | :license {:name "EPL-2.0" 5 | :url "https://www.eclipse.org/legal/epl-2.0/"} 6 | 7 | :aliases {"test-cljs" ["trampoline" "run" "-m" "kaocha.runner" "unit-cljs"]} 8 | 9 | :profiles {:dev {:dependencies [[lambdaisland/kaocha "1.0.829"] 10 | [lambdaisland/kaocha-cljs "0.0-71"] 11 | [org.clojure/clojure "1.10.3"]]}} 12 | 13 | :repl-options {:init-ns can.can} 14 | 15 | :scm {:name "git" 16 | :url "https://github.com/shaolang/can"}) 17 | -------------------------------------------------------------------------------- /test/can/bitmask_test.cljc: -------------------------------------------------------------------------------- 1 | (ns can.bitmask-test 2 | (:require #?(:clj [clojure.test :refer [deftest is testing]] 3 | :cljs [cljs.test :refer-macros [deftest is testing]]) 4 | [can.bitmask :as bitmask])) 5 | 6 | (deftest decode-test 7 | (let [all-permissions {:admin [:create :read :update :delete] 8 | :support [:create-tix :read-tix :edit-tix :delete-tix] 9 | :printers [:print]} 10 | bitmasks {:admin 5 :support 4 :printers 0}] 11 | (is (= {:admin #{:create :update} 12 | :support #{:edit-tix}} 13 | (bitmask/decode all-permissions bitmasks))) 14 | 15 | (is (= {:admin #{:*}} 16 | (bitmask/decode all-permissions {:admin 15}))))) 17 | 18 | 19 | (deftest encode-test 20 | (let [all-permissions {:admin [:create :read :update :delete] 21 | :support [:create-tix :read-tix :edit-tx :delete-tix]} 22 | user-permissions {:admin #{:create :delete} 23 | :support #{:*} 24 | :printer #{:print}}] 25 | (is (= {:admin 9 :support 15} 26 | (bitmask/encode all-permissions user-permissions))) 27 | 28 | (is (= {:admin 1 :support 0} 29 | (bitmask/encode all-permissions {:admin #{:create}}))))) 30 | -------------------------------------------------------------------------------- /src/can/can.cljc: -------------------------------------------------------------------------------- 1 | (ns can.can 2 | (:require [clojure.set :as set] 3 | [clojure.string :as str])) 4 | 5 | (defn- subset? [xs ys] 6 | (set/subset? (set xs) (set ys))) 7 | 8 | 9 | (defn actions->permissions 10 | ([actions] 11 | (->> actions 12 | (map #(map keyword (str/split % #":"))) 13 | (group-by first) 14 | (map (fn [[k vs]] [k (set (map second vs))])) 15 | (into {}))) 16 | ([domain-actions actions] 17 | (let [permissions (actions->permissions actions) 18 | domains (set (keys domain-actions))] 19 | (if (and (subset? (keys permissions) domains) 20 | (every? (fn [[k vs]] (subset? vs (get domain-actions k))) 21 | permissions)) 22 | permissions 23 | :unknown-domain-action-found)))) 24 | 25 | 26 | (defn allow? [permissions action] 27 | (let [[domain action] (->> (str/split action #":") 28 | (map keyword)) 29 | actions (get permissions domain (:* permissions))] 30 | (boolean (when-not (or (= action :*) (= domain :*)) 31 | (or (some #{action} actions) 32 | (some #{:*} actions) 33 | (and (contains? permissions domain) 34 | (nil? action))))))) 35 | 36 | 37 | (defn permissions->actions [full-permissions permissions] 38 | (->> permissions 39 | (map (fn [[k vs]] 40 | (let [kstr (name k) 41 | vs (if (some #{:*} vs) (get full-permissions k) vs)] 42 | [k (set (map #(str kstr %) vs))]))) 43 | (into {}))) 44 | -------------------------------------------------------------------------------- /src/can/bitmask.cljc: -------------------------------------------------------------------------------- 1 | (ns can.bitmask 2 | (:require [clojure.string :as str])) 3 | 4 | 5 | (defn- actions->bitmask-map [actions] 6 | (zipmap (iterate #(* 2 %) 1) actions)) 7 | 8 | 9 | (defn- on-all-bitmasks [actions] 10 | (dec (int (Math/pow 2 (count actions))))) 11 | 12 | 13 | (defn- bitmask->granted-actions [bitmask actions] 14 | (if (= bitmask (on-all-bitmasks actions)) 15 | #{:*} 16 | (let [bitmask-actions (actions->bitmask-map actions) 17 | granted-actions (for [[action-bit action] bitmask-actions] 18 | (when (pos? (bit-and bitmask action-bit)) 19 | action)) 20 | granted-actions (filter (complement nil?) granted-actions)] 21 | (when-not (empty? granted-actions) 22 | (into #{} (filter (complement nil?) granted-actions)))))) 23 | 24 | (defn- parse-long [s] 25 | #?(:clj (Long/parseLong s) 26 | :cljs (js/parseInt s))) 27 | 28 | 29 | (defn decode [all-permissions domain-bitmasks] 30 | (let [permissions (for [[domain bitmask] domain-bitmasks] 31 | (let [actions (get all-permissions domain) 32 | granted-actions (bitmask->granted-actions bitmask 33 | actions)] 34 | (when-not (nil? granted-actions) 35 | (hash-map domain granted-actions))))] 36 | (apply merge {} permissions))) 37 | 38 | 39 | (defn- granted-actions->bitmask [granted-actions all-domain-actions] 40 | (if (= granted-actions #{:*}) 41 | (on-all-bitmasks all-domain-actions) 42 | (let [bitmask-actions (actions->bitmask-map all-domain-actions)] 43 | (transduce (comp (filter (fn [[_ action]] (some #{action} granted-actions))) 44 | (map first)) 45 | + 46 | bitmask-actions)))) 47 | 48 | 49 | (defn encode [all-permissions granted-permissions] 50 | (->> all-permissions 51 | (map (fn [[domain all-actions]] 52 | [domain (granted-actions->bitmask (get granted-permissions domain) 53 | all-actions)])) 54 | (into {}))) 55 | -------------------------------------------------------------------------------- /test/can/can_test.cljc: -------------------------------------------------------------------------------- 1 | (ns can.can-test 2 | (:require #?(:clj [clojure.test :refer [are deftest is testing]] 3 | :cljs [cljs.test :refer-macros [are deftest is testing]]) 4 | [can.can :as can])) 5 | 6 | (deftest allow?-test 7 | (let [permissions {:admin #{:create :read :update :delete} 8 | :support #{:create-ticket :close-ticket} 9 | :audit #{:*}}] 10 | (are [action expected] (and action 11 | (= (can/allow? permissions action) expected)) 12 | 13 | ;; input expected 14 | "admin:create" true ;; specified domain and known action 15 | "audit:print-log" true ;; specified domain with wildcard action 16 | "admin:approve" false ;; specified domain but unknown action 17 | "misc:print" false ;; unknown domain and unknown action 18 | "*:create" false ;; wildcard domain 19 | "admin" true ;; domain only check 20 | "*" false ;; domain-only cannot be a wildcard 21 | "create" false)) ;; action only check 22 | 23 | (let [permissions {:* #{:*}}] ;; [almost] anything allowed 24 | (are [action expected] (= (can/allow? permissions action) expected) 25 | 26 | ;;input expected 27 | "hello:world" true ;; allows everything 28 | "*:delete" false ;; domain cannot be a wildcard 29 | "misc:*" false ;; user action cannot be a wildcard 30 | "admin" true ;; domain only check 31 | "*" false))) ;; domain-only cannot be a wildcard 32 | 33 | 34 | (deftest actions->permissions-test 35 | (testing "with no full domain/action map given" 36 | (is (= {:admin #{:create :read} 37 | :support #{:close-ticket}} 38 | (can/actions->permissions 39 | ["admin:create" "admin:read" "support:close-ticket"])))) 40 | 41 | (testing "identical domain/action names are handled properly" 42 | (is (= {:support #{:support}} 43 | (can/actions->permissions ["support:support"])))) 44 | 45 | (testing "with full domain-action map given with no unknown action given" 46 | (is (= {:admin #{:delete} 47 | :support #{:edit-ticket}} 48 | (can/actions->permissions {:admin #{:create :read :update :delete} 49 | :support #{:create-ticket :edit-ticket}} 50 | ["admin:delete" "support:edit-ticket"])))) 51 | 52 | (testing "with full domain-action map given and unknown action given" 53 | (is (= :unknown-domain-action-found 54 | (can/actions->permissions {:admin #{:create :read} 55 | :support #{:create-ticket}} 56 | ["admin:create" "support:edit-ticket"]))))) 57 | 58 | 59 | (deftest permissions->actions-test 60 | (is (= {:admin #{"admin:create" "admin:read" "admin:update" "admin:delete"} 61 | :support #{"support:create-ticket"}} 62 | (can/permissions->actions {:admin #{:create :read :update :delete} 63 | :support #{:create-ticket :edit-ticket}} 64 | {:admin #{:*} 65 | :support #{:create-ticket}})))) 66 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # can 2 | [![Clojars Project](https://img.shields.io/clojars/v/can.svg)](https://clojars.org/can) 3 | 4 | A permissions library for Clojure(Script), inspired by 5 | [agynamix/permissions][permissions]. 6 | 7 | __Library is still undergoing development, so expect frequent changes 8 | to the API.__ 9 | 10 | ## Basic Usage 11 | 12 | The core API lives in `can.can` (not `can.core`) and is recommended 13 | to be aliased as `can`, i.e., `(require '[can.can :as can])`. 14 | 15 | Permissions is a map of sets, where the key is the domain, and the 16 | values the rights applicable to that domain. `can.can/allow?` takes 17 | the permissions map and an domain/action string to determine whether 18 | the user is allowed to perform the said action: 19 | 20 | ```clojure 21 | (def permissions {:support #{:create-ticket :update-ticket} 22 | :printer #{:print}}) 23 | 24 | 25 | (print (can/allow? permissions "support:create-ticket")) ;; outputs "true" 26 | (print (can/allow? permissions "print:clear-spool")) ;; outputs "false" 27 | ``` 28 | 29 | You could also use `:*` to grant permissions: 30 | 31 | ```clojure 32 | (def super-support {:support #{:*}}) 33 | 34 | (print (can/allow? super-support "support:launch-nuclear")) ;; outputs "true" 35 | (print (can/allow? super-support "print:clear-spool")) ;; outputs "false" 36 | ``` 37 | 38 | And even superuser: 39 | 40 | ```clojure 41 | (def superuser {:* #{:*}}) 42 | 43 | (print (can/allow? superuser "hello:world")) ;; outputs "true" 44 | ``` 45 | 46 | Unlike permissions, actions cannot use `*`, i.e., doing 47 | `(can/allow? permissions "*:create-ticket")` or 48 | `(can/allow? permissions "admin:*")` will always return `false`. 49 | 50 | ## Bitmasks permissions 51 | __Breaking change in 0.3.0: bitmask-related functions reside in `can.bitmask` 52 | now, and they are renamed as decode and encode.__ 53 | 54 | `can.bitmask/decode` takes the full permissions setup (i.e., 55 | all available domains and actions available in your application) and 56 | converts a map of domain-bitmask pair into a permissions map. 57 | 58 | ```clojure 59 | (def all-permissions {:admin [:create :read :update :delete :approve :reject] 60 | :support [:create-ticket :update-ticket :close-ticket] 61 | :printer [:print :clear-spool]}) 62 | 63 | 64 | (def alice-permissions 65 | (can/decode all-permissions {:admin 7 :printer 1})) 66 | 67 | (print alice-permissions) ;; outputs {:admin #{:create :read :update} 68 | ;; :printer #{:print}} 69 | ``` 70 | 71 | Note that the order of the available actions in each domain matters, i.e., 72 | new actions should be appended to the end of the action list. 73 | 74 | `can.bitmask/decode` makes it trivial to implement 75 | access control list/matrix in your application, e.g., the relational 76 | database could have a table that looks like the following: 77 | 78 | 79 | 80 | 81 | 82 | 83 | 84 | 85 | 86 | 87 | 88 | 89 | 90 | 91 |
useridadminsupportprinter
alice701
bob072
92 | 93 | Note that when using bitmasks permissions, the total number of actions 94 | per domain cannot exceed 63 on Clojure, and cannot exceed 52 on 95 | ClojureScript. 96 | 97 | `can.bitmask/encode` converts the permissions map into a map of 98 | domain-bitmask pair (somewhat the inverse of `can.bitmask/decode`), 99 | making it easy to persist changes back to the datastore: 100 | 101 | ```clojure 102 | (print (encode all-permissions alice-permissions)) ;; outputs {:admin 7 103 | ;; :support 0 104 | ;; :printer 1} 105 | ``` 106 | 107 | ## License 108 | 109 | Copyright © 2019 Shaolang Ai 110 | 111 | This program and the accompanying materials are made available under the 112 | terms of the Eclipse Public License 2.0 which is available at 113 | http://www.eclipse.org/legal/epl-2.0. 114 | 115 | [permissions]: https://github.com/tuhlmann/permissions 116 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | Eclipse Public License - v 2.0 2 | 3 | THE ACCOMPANYING PROGRAM IS PROVIDED UNDER THE TERMS OF THIS ECLIPSE 4 | PUBLIC LICENSE ("AGREEMENT"). ANY USE, REPRODUCTION OR DISTRIBUTION 5 | OF THE PROGRAM CONSTITUTES RECIPIENT'S ACCEPTANCE OF THIS AGREEMENT. 6 | 7 | 1. DEFINITIONS 8 | 9 | "Contribution" means: 10 | 11 | a) in the case of the initial Contributor, the initial content 12 | Distributed under this Agreement, and 13 | 14 | b) in the case of each subsequent Contributor: 15 | i) changes to the Program, and 16 | ii) additions to the Program; 17 | where such changes and/or additions to the Program originate from 18 | and are Distributed by that particular Contributor. A Contribution 19 | "originates" from a Contributor if it was added to the Program by 20 | such Contributor itself or anyone acting on such Contributor's behalf. 21 | Contributions do not include changes or additions to the Program that 22 | are not Modified Works. 23 | 24 | "Contributor" means any person or entity that Distributes the Program. 25 | 26 | "Licensed Patents" mean patent claims licensable by a Contributor which 27 | are necessarily infringed by the use or sale of its Contribution alone 28 | or when combined with the Program. 29 | 30 | "Program" means the Contributions Distributed in accordance with this 31 | Agreement. 32 | 33 | "Recipient" means anyone who receives the Program under this Agreement 34 | or any Secondary License (as applicable), including Contributors. 35 | 36 | "Derivative Works" shall mean any work, whether in Source Code or other 37 | form, that is based on (or derived from) the Program and for which the 38 | editorial revisions, annotations, elaborations, or other modifications 39 | represent, as a whole, an original work of authorship. 40 | 41 | "Modified Works" shall mean any work in Source Code or other form that 42 | results from an addition to, deletion from, or modification of the 43 | contents of the Program, including, for purposes of clarity any new file 44 | in Source Code form that contains any contents of the Program. Modified 45 | Works shall not include works that contain only declarations, 46 | interfaces, types, classes, structures, or files of the Program solely 47 | in each case in order to link to, bind by name, or subclass the Program 48 | or Modified Works thereof. 49 | 50 | "Distribute" means the acts of a) distributing or b) making available 51 | in any manner that enables the transfer of a copy. 52 | 53 | "Source Code" means the form of a Program preferred for making 54 | modifications, including but not limited to software source code, 55 | documentation source, and configuration files. 56 | 57 | "Secondary License" means either the GNU General Public License, 58 | Version 2.0, or any later versions of that license, including any 59 | exceptions or additional permissions as identified by the initial 60 | Contributor. 61 | 62 | 2. GRANT OF RIGHTS 63 | 64 | a) Subject to the terms of this Agreement, each Contributor hereby 65 | grants Recipient a non-exclusive, worldwide, royalty-free copyright 66 | license to reproduce, prepare Derivative Works of, publicly display, 67 | publicly perform, Distribute and sublicense the Contribution of such 68 | Contributor, if any, and such Derivative Works. 69 | 70 | b) Subject to the terms of this Agreement, each Contributor hereby 71 | grants Recipient a non-exclusive, worldwide, royalty-free patent 72 | license under Licensed Patents to make, use, sell, offer to sell, 73 | import and otherwise transfer the Contribution of such Contributor, 74 | if any, in Source Code or other form. This patent license shall 75 | apply to the combination of the Contribution and the Program if, at 76 | the time the Contribution is added by the Contributor, such addition 77 | of the Contribution causes such combination to be covered by the 78 | Licensed Patents. The patent license shall not apply to any other 79 | combinations which include the Contribution. No hardware per se is 80 | licensed hereunder. 81 | 82 | c) Recipient understands that although each Contributor grants the 83 | licenses to its Contributions set forth herein, no assurances are 84 | provided by any Contributor that the Program does not infringe the 85 | patent or other intellectual property rights of any other entity. 86 | Each Contributor disclaims any liability to Recipient for claims 87 | brought by any other entity based on infringement of intellectual 88 | property rights or otherwise. As a condition to exercising the 89 | rights and licenses granted hereunder, each Recipient hereby 90 | assumes sole responsibility to secure any other intellectual 91 | property rights needed, if any. For example, if a third party 92 | patent license is required to allow Recipient to Distribute the 93 | Program, it is Recipient's responsibility to acquire that license 94 | before distributing the Program. 95 | 96 | d) Each Contributor represents that to its knowledge it has 97 | sufficient copyright rights in its Contribution, if any, to grant 98 | the copyright license set forth in this Agreement. 99 | 100 | e) Notwithstanding the terms of any Secondary License, no 101 | Contributor makes additional grants to any Recipient (other than 102 | those set forth in this Agreement) as a result of such Recipient's 103 | receipt of the Program under the terms of a Secondary License 104 | (if permitted under the terms of Section 3). 105 | 106 | 3. REQUIREMENTS 107 | 108 | 3.1 If a Contributor Distributes the Program in any form, then: 109 | 110 | a) the Program must also be made available as Source Code, in 111 | accordance with section 3.2, and the Contributor must accompany 112 | the Program with a statement that the Source Code for the Program 113 | is available under this Agreement, and informs Recipients how to 114 | obtain it in a reasonable manner on or through a medium customarily 115 | used for software exchange; and 116 | 117 | b) the Contributor may Distribute the Program under a license 118 | different than this Agreement, provided that such license: 119 | i) effectively disclaims on behalf of all other Contributors all 120 | warranties and conditions, express and implied, including 121 | warranties or conditions of title and non-infringement, and 122 | implied warranties or conditions of merchantability and fitness 123 | for a particular purpose; 124 | 125 | ii) effectively excludes on behalf of all other Contributors all 126 | liability for damages, including direct, indirect, special, 127 | incidental and consequential damages, such as lost profits; 128 | 129 | iii) does not attempt to limit or alter the recipients' rights 130 | in the Source Code under section 3.2; and 131 | 132 | iv) requires any subsequent distribution of the Program by any 133 | party to be under a license that satisfies the requirements 134 | of this section 3. 135 | 136 | 3.2 When the Program is Distributed as Source Code: 137 | 138 | a) it must be made available under this Agreement, or if the 139 | Program (i) is combined with other material in a separate file or 140 | files made available under a Secondary License, and (ii) the initial 141 | Contributor attached to the Source Code the notice described in 142 | Exhibit A of this Agreement, then the Program may be made available 143 | under the terms of such Secondary Licenses, and 144 | 145 | b) a copy of this Agreement must be included with each copy of 146 | the Program. 147 | 148 | 3.3 Contributors may not remove or alter any copyright, patent, 149 | trademark, attribution notices, disclaimers of warranty, or limitations 150 | of liability ("notices") contained within the Program from any copy of 151 | the Program which they Distribute, provided that Contributors may add 152 | their own appropriate notices. 153 | 154 | 4. COMMERCIAL DISTRIBUTION 155 | 156 | Commercial distributors of software may accept certain responsibilities 157 | with respect to end users, business partners and the like. While this 158 | license is intended to facilitate the commercial use of the Program, 159 | the Contributor who includes the Program in a commercial product 160 | offering should do so in a manner which does not create potential 161 | liability for other Contributors. Therefore, if a Contributor includes 162 | the Program in a commercial product offering, such Contributor 163 | ("Commercial Contributor") hereby agrees to defend and indemnify every 164 | other Contributor ("Indemnified Contributor") against any losses, 165 | damages and costs (collectively "Losses") arising from claims, lawsuits 166 | and other legal actions brought by a third party against the Indemnified 167 | Contributor to the extent caused by the acts or omissions of such 168 | Commercial Contributor in connection with its distribution of the Program 169 | in a commercial product offering. The obligations in this section do not 170 | apply to any claims or Losses relating to any actual or alleged 171 | intellectual property infringement. In order to qualify, an Indemnified 172 | Contributor must: a) promptly notify the Commercial Contributor in 173 | writing of such claim, and b) allow the Commercial Contributor to control, 174 | and cooperate with the Commercial Contributor in, the defense and any 175 | related settlement negotiations. The Indemnified Contributor may 176 | participate in any such claim at its own expense. 177 | 178 | For example, a Contributor might include the Program in a commercial 179 | product offering, Product X. That Contributor is then a Commercial 180 | Contributor. If that Commercial Contributor then makes performance 181 | claims, or offers warranties related to Product X, those performance 182 | claims and warranties are such Commercial Contributor's responsibility 183 | alone. Under this section, the Commercial Contributor would have to 184 | defend claims against the other Contributors related to those performance 185 | claims and warranties, and if a court requires any other Contributor to 186 | pay any damages as a result, the Commercial Contributor must pay 187 | those damages. 188 | 189 | 5. NO WARRANTY 190 | 191 | EXCEPT AS EXPRESSLY SET FORTH IN THIS AGREEMENT, AND TO THE EXTENT 192 | PERMITTED BY APPLICABLE LAW, THE PROGRAM IS PROVIDED ON AN "AS IS" 193 | BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, EITHER EXPRESS OR 194 | IMPLIED INCLUDING, WITHOUT LIMITATION, ANY WARRANTIES OR CONDITIONS OF 195 | TITLE, NON-INFRINGEMENT, MERCHANTABILITY OR FITNESS FOR A PARTICULAR 196 | PURPOSE. Each Recipient is solely responsible for determining the 197 | appropriateness of using and distributing the Program and assumes all 198 | risks associated with its exercise of rights under this Agreement, 199 | including but not limited to the risks and costs of program errors, 200 | compliance with applicable laws, damage to or loss of data, programs 201 | or equipment, and unavailability or interruption of operations. 202 | 203 | 6. DISCLAIMER OF LIABILITY 204 | 205 | EXCEPT AS EXPRESSLY SET FORTH IN THIS AGREEMENT, AND TO THE EXTENT 206 | PERMITTED BY APPLICABLE LAW, NEITHER RECIPIENT NOR ANY CONTRIBUTORS 207 | SHALL HAVE ANY LIABILITY FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, 208 | EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING WITHOUT LIMITATION LOST 209 | PROFITS), HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 210 | CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 211 | ARISING IN ANY WAY OUT OF THE USE OR DISTRIBUTION OF THE PROGRAM OR THE 212 | EXERCISE OF ANY RIGHTS GRANTED HEREUNDER, EVEN IF ADVISED OF THE 213 | POSSIBILITY OF SUCH DAMAGES. 214 | 215 | 7. GENERAL 216 | 217 | If any provision of this Agreement is invalid or unenforceable under 218 | applicable law, it shall not affect the validity or enforceability of 219 | the remainder of the terms of this Agreement, and without further 220 | action by the parties hereto, such provision shall be reformed to the 221 | minimum extent necessary to make such provision valid and enforceable. 222 | 223 | If Recipient institutes patent litigation against any entity 224 | (including a cross-claim or counterclaim in a lawsuit) alleging that the 225 | Program itself (excluding combinations of the Program with other software 226 | or hardware) infringes such Recipient's patent(s), then such Recipient's 227 | rights granted under Section 2(b) shall terminate as of the date such 228 | litigation is filed. 229 | 230 | All Recipient's rights under this Agreement shall terminate if it 231 | fails to comply with any of the material terms or conditions of this 232 | Agreement and does not cure such failure in a reasonable period of 233 | time after becoming aware of such noncompliance. If all Recipient's 234 | rights under this Agreement terminate, Recipient agrees to cease use 235 | and distribution of the Program as soon as reasonably practicable. 236 | However, Recipient's obligations under this Agreement and any licenses 237 | granted by Recipient relating to the Program shall continue and survive. 238 | 239 | Everyone is permitted to copy and distribute copies of this Agreement, 240 | but in order to avoid inconsistency the Agreement is copyrighted and 241 | may only be modified in the following manner. The Agreement Steward 242 | reserves the right to publish new versions (including revisions) of 243 | this Agreement from time to time. No one other than the Agreement 244 | Steward has the right to modify this Agreement. The Eclipse Foundation 245 | is the initial Agreement Steward. The Eclipse Foundation may assign the 246 | responsibility to serve as the Agreement Steward to a suitable separate 247 | entity. Each new version of the Agreement will be given a distinguishing 248 | version number. The Program (including Contributions) may always be 249 | Distributed subject to the version of the Agreement under which it was 250 | received. In addition, after a new version of the Agreement is published, 251 | Contributor may elect to Distribute the Program (including its 252 | Contributions) under the new version. 253 | 254 | Except as expressly stated in Sections 2(a) and 2(b) above, Recipient 255 | receives no rights or licenses to the intellectual property of any 256 | Contributor under this Agreement, whether expressly, by implication, 257 | estoppel or otherwise. All rights in the Program not expressly granted 258 | under this Agreement are reserved. Nothing in this Agreement is intended 259 | to be enforceable by any entity that is not a Contributor or Recipient. 260 | No third-party beneficiary rights are created under this Agreement. 261 | 262 | Exhibit A - Form of Secondary Licenses Notice 263 | 264 | "This Source Code may also be made available under the following 265 | Secondary Licenses when the conditions for such availability set forth 266 | in the Eclipse Public License, v. 2.0 are satisfied: {name license(s), 267 | version(s), and exceptions or additional permissions here}." 268 | 269 | Simply including a copy of this Agreement, including this Exhibit A 270 | is not sufficient to license the Source Code under Secondary Licenses. 271 | 272 | If it is not possible or desirable to put the notice in a particular 273 | file, then You may include the notice in a location (such as a LICENSE 274 | file in a relevant directory) where a recipient would be likely to 275 | look for such a notice. 276 | 277 | You may add additional accurate notices of copyright ownership. 278 | --------------------------------------------------------------------------------